# Docker vmain — Documentación técnica oficial

> **Espejo Offline de Documentación Técnica**
> Licencia: Apache-2.0 | Documentos incluidos: 905 | Versión: main
> Descargado/sincronizado: 2026-09-15
> Documentación oficial en línea: https://docs.docker.com/
> Mantenedor del espejo: Raúl Caro Pastorino (@raupulus) · https://raupulus.dev

---

## Índice de contenidos


### Accounts

- [Accounts](#accounts)
- [Company overview](#company-overview)
- [Manage company organizations, owners, and members](#manage-company-organizations-owners-and-members)
- [Create new company](#create-new-company)
- [Docker individual accounts](#docker-individual-accounts)
- [Create a Docker account](#create-a-docker-account)
- [Deactivate a Docker account](#deactivate-a-docker-account)
- [Manage a Docker account](#manage-a-docker-account)
- [Organization accounts](#organization-accounts)
- [Activity logs](#activity-logs)
- [Insights](#insights)
- [Manage your organization](#manage-your-organization)
- [Deactivate an organization](#deactivate-an-organization)
- [Change general organization information](#change-general-organization-information)
- [Create and manage a team](#create-and-manage-a-team)
- [Manage license assignment](#manage-license-assignment)
- [Manage usage and access for Docker products](#manage-usage-and-access-for-docker-products)
- [Manage subscription seats](#manage-subscription-seats)
- [Invite and manage organization members](#invite-and-manage-organization-members)
- [Set up your organization](#set-up-your-organization)
- [Convert an account into an organization](#convert-an-account-into-an-organization)
- [Onboard your organization](#onboard-your-organization)
- [Create your organization](#create-your-organization)

### Agentic Platform

- [Docker Agentic Platform](#docker-agentic-platform)
- [Docker Agentic Platform FAQ](#docker-agentic-platform-faq)
- [Get started with Docker Agentic Platform](#get-started-with-docker-agentic-platform)
- [MCP](#mcp)
- [Network policies](#network-policies)
- [Docker Agentic Platform release notes](#docker-agentic-platform-release-notes)
- [Sandboxes](#sandboxes)
- [Secrets](#secrets)

### Ai

- [AI and Docker Compose](#ai-and-docker-compose)
- [Define AI Models in Docker Compose applications](#define-ai-models-in-docker-compose-applications)
- [Docker Agent](#docker-agent)
- [Gordon](#gordon)
- [Concepts](#concepts)
- [Gordon's capabilities](#gordon-s-capabilities)
- [Data privacy and Gordon](#data-privacy-and-gordon)
- [How-to guides](#how-to-guides)
- [Using Gordon via CLI](#using-gordon-via-cli)
- [Configure Gordon's tools](#configure-gordon-s-tools)
- [Using Gordon in Docker Desktop](#using-gordon-in-docker-desktop)
- [Gordon's permission model](#gordon-s-permission-model)
- [Gordon usage limits and tiers](#gordon-usage-limits-and-tiers)
- [Gordon use cases and examples](#gordon-use-cases-and-examples)
- [Docker MCP Catalog and Toolkit](#docker-mcp-catalog-and-toolkit)
- [Docker MCP Catalog](#docker-mcp-catalog)
- [Use MCP Toolkit from the CLI](#use-mcp-toolkit-from-the-cli)
- [Dynamic MCP](#dynamic-mcp)
- [E2B sandboxes](#e2b-sandboxes)
- [MCP Toolkit FAQs](#mcp-toolkit-faqs)
- [Get started with Docker MCP Toolkit](#get-started-with-docker-mcp-toolkit)
- [MCP Gateway](#mcp-gateway)
- [MCP Profiles](#mcp-profiles)
- [Docker MCP Toolkit](#docker-mcp-toolkit)
- [Docker Model Runner](#docker-model-runner)
- [DMR REST API](#dmr-rest-api)
- [Configuration options](#configuration-options)
- [DMR examples](#dmr-examples)
- [Get started with DMR](#get-started-with-dmr)
- [IDE and tool integrations](#ide-and-tool-integrations)
- [Inference engines](#inference-engines)
- [Open WebUI integration](#open-webui-integration)
- [Docker Sandboxes](#docker-sandboxes)
- [Supported agents](#supported-agents)
- [Claude Code](#claude-code)
- [Codex](#codex)
- [Copilot](#copilot)
- [Cursor](#cursor)
- [Devin](#devin)
- [Docker Agent](#docker-agent)
- [Droid](#droid)
- [Gemini](#gemini)
- [Kiro](#kiro)
- [OpenCode](#opencode)
- [Shell](#shell)
- [Architecture](#architecture)
- [Configure Docker Sandboxes](#configure-docker-sandboxes)
- [Manage credentials](#manage-credentials)
- [Sandbox environment files](#sandbox-environment-files)
- [Enable NVIDIA GPU passthrough](#enable-nvidia-gpu-passthrough)
- [Configure a registry mirror](#configure-a-registry-mirror)
- [Configure an upstream proxy](#configure-an-upstream-proxy)
- [Customizing sandboxes](#customizing-sandboxes)
- [Build your own agent kit](#build-your-own-agent-kit)
- [Kit examples](#kit-examples)
- [Kit spec reference](#kit-spec-reference)
- [Kits](#kits)
- [Templates](#templates)
- [FAQ](#faq)
- [Get started with Docker Sandboxes](#get-started-with-docker-sandboxes)
- [Governance](#governance)
- [Access controls](#access-controls)
- [Filesystem access policies](#filesystem-access-policies)
- [Local policy](#local-policy)
- [MCP access policies](#mcp-access-policies)
- [Network access policies](#network-access-policies)
- [Organization policies](#organization-policies)
- [AI Governance Audit Logs](#ai-governance-audit-logs)
- [Configure audit delivery](#configure-audit-delivery)
- [Local audit logs](#local-audit-logs)
- [Audit record reference](#audit-record-reference)
- [SIEM forwarding](#siem-forwarding)
- [View and export audit events](#view-and-export-audit-events)
- [Policy concepts](#policy-concepts)
- [Monitor and enforce](#monitor-and-enforce)
- [Monitoring policies](#monitoring-policies)
- [Sign-in enforcement](#sign-in-enforcement)
- [Reference](#reference)
- [AI Governance API](#ai-governance-api)
- [MCP policy reference](#mcp-policy-reference)
- [Install Docker Sandboxes](#install-docker-sandboxes)
- [Editor and app integrations](#editor-and-app-integrations)
- [Connect ChatGPT to a sandbox](#connect-chatgpt-to-a-sandbox)
- [Connect Claude Desktop to a sandbox](#connect-claude-desktop-to-a-sandbox)
- [Connect Cursor to a sandbox](#connect-cursor-to-a-sandbox)
- [Connect T3 Code to a sandbox](#connect-t3-code-to-a-sandbox)
- [Connect VS Code to a sandbox](#connect-vs-code-to-a-sandbox)
- [MCP gateway](#mcp-gateway)
- [Docker Sandboxes release notes](#docker-sandboxes-release-notes)
- [Security model](#security-model)
- [Default security posture](#default-security-posture)
- [Isolation layers](#isolation-layers)
- [Troubleshooting](#troubleshooting)
- [Usage](#usage)
- [Workflow patterns](#workflow-patterns)
- [Share agent skills](#share-agent-skills)
- [Authenticate command-line tools](#authenticate-command-line-tools)
- [Run sandboxes in CI](#run-sandboxes-in-ci)
- [Develop and test locally](#develop-and-test-locally)
- [Use Git with sandboxes](#use-git-with-sandboxes)

### Build

- [Docker Build](#docker-build)
- [Bake](#bake)
- [Building with Bake from a Compose file](#building-with-bake-from-a-compose-file)
- [Using Bake with additional contexts](#using-bake-with-additional-contexts)
- [Expression evaluation in Bake](#expression-evaluation-in-bake)
- [Functions](#functions)
- [Inheritance in Bake](#inheritance-in-bake)
- [Introduction to Bake](#introduction-to-bake)
- [Matrix targets](#matrix-targets)
- [Overriding configurations](#overriding-configurations)
- [Remote Bake file definition](#remote-bake-file-definition)
- [Bake targets](#bake-targets)
- [Variables in Bake](#variables-in-bake)
- [Builders](#builders)
- [Build drivers](#build-drivers)
- [Cloud driver](#cloud-driver)
- [Docker container driver](#docker-container-driver)
- [Docker driver](#docker-driver)
- [Kubernetes driver](#kubernetes-driver)
- [Remote driver](#remote-driver)
- [Manage builders](#manage-builders)
- [Building](#building)
- [Base images](#base-images)
- [Building best practices](#building-best-practices)
- [Container Device Interface (CDI)](#container-device-interface-cdi)
- [Export binaries](#export-binaries)
- [Multi-platform builds](#multi-platform-builds)
- [Multi-stage builds](#multi-stage-builds)
- [Build secrets](#build-secrets)
- [Build variables](#build-variables)
- [BuildKit](#buildkit)
- [Configure BuildKit](#configure-buildkit)
- [Dockerfile release notes](#dockerfile-release-notes)
- [Custom Dockerfile syntax](#custom-dockerfile-syntax)
- [Docker build cache](#docker-build-cache)
- [Cache storage backends](#cache-storage-backends)
- [Azure Blob Storage cache](#azure-blob-storage-cache)
- [GitHub Actions cache](#github-actions-cache)
- [Inline cache](#inline-cache)
- [Local cache](#local-cache)
- [Registry cache](#registry-cache)
- [Amazon S3 cache](#amazon-s3-cache)
- [Build garbage collection](#build-garbage-collection)
- [Build cache invalidation](#build-cache-invalidation)
- [Optimize cache usage in builds](#optimize-cache-usage-in-builds)
- [Checking your build configuration](#checking-your-build-configuration)
- [Continuous integration with Docker](#continuous-integration-with-docker)
- [Docker Build GitHub Actions](#docker-build-github-actions)
- [Add image annotations with GitHub Actions](#add-image-annotations-with-github-actions)
- [Add SBOM and provenance attestations with GitHub Actions](#add-sbom-and-provenance-attestations-with-github-actions)
- [GitHub Actions build summary](#github-actions-build-summary)
- [Cache management with GitHub Actions](#cache-management-with-github-actions)
- [Validating build configuration with GitHub Actions](#validating-build-configuration-with-github-actions)
- [Configuring your GitHub Actions builder](#configuring-your-github-actions-builder)
- [Copy image between registries with GitHub Actions](#copy-image-between-registries-with-github-actions)
- [Export to Docker with GitHub Actions](#export-to-docker-with-github-actions)
- [Docker GitHub Builder](#docker-github-builder)
- [Docker GitHub Builder architecture](#docker-github-builder-architecture)
- [Bake with Docker GitHub Builder](#bake-with-docker-github-builder)
- [Build with Docker GitHub Builder](#build-with-docker-github-builder)
- [Local registry with GitHub Actions](#local-registry-with-github-actions)
- [Manage tags and labels with GitHub Actions](#manage-tags-and-labels-with-github-actions)
- [Multi-platform image with GitHub Actions](#multi-platform-image-with-github-actions)
- [Named contexts with GitHub Actions](#named-contexts-with-github-actions)
- [Push to multiple registries with GitHub Actions](#push-to-multiple-registries-with-github-actions)
- [Reproducible builds with GitHub Actions](#reproducible-builds-with-github-actions)
- [Using secrets with GitHub Actions](#using-secrets-with-github-actions)
- [Share built image between jobs with GitHub Actions](#share-built-image-between-jobs-with-github-actions)
- [Test before push with GitHub Actions](#test-before-push-with-github-actions)
- [Update Docker Hub description with GitHub Actions](#update-docker-hub-description-with-github-actions)
- [Core concepts](#core-concepts)
- [Build context](#build-context)
- [Dockerfile overview](#dockerfile-overview)
- [Docker Build Overview](#docker-build-overview)
- [Debugging](#debugging)
- [OpenTelemetry support](#opentelemetry-support)
- [Exporters overview](#exporters-overview)
- [Image and registry exporters](#image-and-registry-exporters)
- [Local and tar exporters](#local-and-tar-exporters)
- [OCI and Docker exporters](#oci-and-docker-exporters)
- [Metadata](#metadata)
- [Annotations](#annotations)
- [Build attestations](#build-attestations)
- [SBOM attestations](#sbom-attestations)
- [Provenance attestations](#provenance-attestations)
- [Validating build inputs with policies](#validating-build-inputs-with-policies)
- [Built-in functions](#built-in-functions)
- [Debugging build policies](#debugging-build-policies)
- [Policy templates and examples](#policy-templates-and-examples)
- [Input reference](#input-reference)
- [Introduction to build policies](#introduction-to-build-policies)
- [Test build policies](#test-build-policies)
- [Using build policies](#using-build-policies)
- [Validating Git repositories](#validating-git-repositories)
- [Validating image inputs](#validating-image-inputs)
- [Release notes](#release-notes)

### Build Cloud

- [Docker Build Cloud](#docker-build-cloud)
- [Builder settings](#builder-settings)
- [Use Docker Build Cloud in CI](#use-docker-build-cloud-in-ci)
- [Optimize for building in the cloud](#optimize-for-building-in-the-cloud)
- [Docker Build Cloud release notes](#docker-build-cloud-release-notes)
- [Docker Build Cloud setup](#docker-build-cloud-setup)
- [Building with Docker Build Cloud](#building-with-docker-build-cloud)

### Compose

- [Docker Compose](#docker-compose)
- [Overview of Compose Bridge](#overview-of-compose-bridge)
- [Customize Compose Bridge](#customize-compose-bridge)
- [Use the default Compose Bridge transformation](#use-the-default-compose-bridge-transformation)
- [Use Docker Model Runner with Compose Bridge](#use-docker-model-runner-with-compose-bridge)
- [Using the Compose SDK](#using-the-compose-sdk)
- [Docker Compose Quickstart](#docker-compose-quickstart)
- [Index](#index)
- [Build dependent images](#build-dependent-images)
- [Environment variables in Compose](#environment-variables-in-compose)
- [Best practices for working with environment variables in Docker Compose](#best-practices-for-working-with-environment-variables-in-docker-compose)
- [Environment variables precedence in Docker Compose](#environment-variables-precedence-in-docker-compose)
- [Configure pre-defined environment variables in Docker Compose](#configure-pre-defined-environment-variables-in-docker-compose)
- [Set environment variables within your container's environment](#set-environment-variables-within-your-container-s-environment)
- [Set, use, and manage variables in a Compose file with interpolation](#set-use-and-manage-variables-in-a-compose-file-with-interpolation)
- [Use Compose Watch](#use-compose-watch)
- [Run Docker Compose services with GPU access](#run-docker-compose-services-with-gpu-access)
- [Use init containers in Compose](#use-init-containers-in-compose)
- [Using lifecycle hooks with Compose](#using-lifecycle-hooks-with-compose)
- [Use multiple Compose files](#use-multiple-compose-files)
- [Extend your Compose file](#extend-your-compose-file)
- [Include](#include)
- [Merge Compose files](#merge-compose-files)
- [Networking in Compose](#networking-in-compose)
- [Package and deploy Docker Compose applications as OCI artifacts](#package-and-deploy-docker-compose-applications-as-oci-artifacts)
- [Use Compose in production](#use-compose-in-production)
- [Using profiles with Compose](#using-profiles-with-compose)
- [Specify a project name](#specify-a-project-name)
- [Use provider services](#use-provider-services)
- [Control startup and shutdown order in Compose](#control-startup-and-shutdown-order-in-compose)
- [Manage secrets securely in Docker Compose](#manage-secrets-securely-in-docker-compose)
- [Overview of installing Docker Compose](#overview-of-installing-docker-compose)
- [Install the Docker Compose plugin](#install-the-docker-compose-plugin)
- [Install the Docker Compose standalone (Legacy)](#install-the-docker-compose-standalone-legacy)
- [Uninstall Docker Compose](#uninstall-docker-compose)
- [Introduction to Compose](#introduction-to-compose)
- [How Compose works](#how-compose-works)
- [Why use Compose?](#why-use-compose)
- [History and development of Docker Compose](#history-and-development-of-docker-compose)
- [Release notes](#release-notes)
- [Index](#index)
- [Frequently asked questions about Docker Compose](#frequently-asked-questions-about-docker-compose)
- [Give feedback](#give-feedback)
- [Trust model for Compose files](#trust-model-for-compose-files)

### Desktop

- [Docker Desktop](#docker-desktop)
- [Resolve the recent Docker Desktop issue on macOS](#resolve-the-recent-docker-desktop-issue-on-macos)
- [Docker Desktop Enterprise](#docker-desktop-enterprise)
- [Index](#index)
- [containerd image store](#containerd-image-store)
- [Use the Docker Desktop CLI](#use-the-docker-desktop-cli)
- [GPU support in Docker Desktop for Windows](#gpu-support-in-docker-desktop-for-windows)
- [Networking on Docker Desktop](#networking-on-docker-desktop)
- [Explore networking how-tos on Docker Desktop](#explore-networking-how-tos-on-docker-desktop)
- [Synchronized file shares](#synchronized-file-shares)
- [Using USB/IP with Docker Desktop](#using-usb-ip-with-docker-desktop)
- [Virtual Machine Manager](#virtual-machine-manager)
- [Wasm workloads](#wasm-workloads)
- [Docker Desktop WSL 2 backend on Windows](#docker-desktop-wsl-2-backend-on-windows)
- [WSL 2 best practices for Docker Desktop on Windows](#wsl-2-best-practices-for-docker-desktop-on-windows)
- [Custom kernels on WSL](#custom-kernels-on-wsl)
- [Develop with Docker Desktop using WSL 2 on Windows](#develop-with-docker-desktop-using-wsl-2-on-windows)
- [Docker Desktop for Mac 2.x release notes](#docker-desktop-for-mac-2-x-release-notes)
- [Docker for Windows 2.x release notes](#docker-for-windows-2-x-release-notes)
- [Docker Desktop for Mac 3.x release notes](#docker-desktop-for-mac-3-x-release-notes)
- [Docker for Windows 3.x release notes](#docker-for-windows-3-x-release-notes)
- [Previous releases](#previous-releases)
- [Release notes for previous versions](#release-notes-for-previous-versions)
- [Release notes for previous versions](#release-notes-for-previous-versions)
- [Docker Desktop for Mac Edge release notes](#docker-desktop-for-mac-edge-release-notes)
- [Docker Desktop for Windows Edge Release notes](#docker-desktop-for-windows-edge-release-notes)
- [Docker Desktop release notes](#docker-desktop-release-notes)
- [Index](#index)
- [How to back up and restore your Docker Desktop data](#how-to-back-up-and-restore-your-docker-desktop-data)
- [Change your Docker Desktop settings](#change-your-docker-desktop-settings)
- [Index](#index)
- [Allowlist for Docker Desktop](#allowlist-for-docker-desktop)
- [Install](#install)
- [Install Docker Desktop on Linux](#install-docker-desktop-on-linux)
- [Install Docker Desktop on Arch-based distributions](#install-docker-desktop-on-arch-based-distributions)
- [Install Docker Desktop on Debian](#install-docker-desktop-on-debian)
- [Install Docker Desktop on Fedora](#install-docker-desktop-on-fedora)
- [Install Docker Desktop on RHEL](#install-docker-desktop-on-rhel)
- [Install Docker Desktop on Ubuntu](#install-docker-desktop-on-ubuntu)
- [Install Docker Desktop on Mac](#install-docker-desktop-on-mac)
- [Understand permission requirements for Docker Desktop on Mac](#understand-permission-requirements-for-docker-desktop-on-mac)
- [Install Docker Desktop on Windows](#install-docker-desktop-on-windows)
- [Understand permission requirements for Windows](#understand-permission-requirements-for-windows)
- [Sign in to Docker Desktop](#sign-in-to-docker-desktop)
- [Run Docker Desktop for Windows in a VM or VDI environment](#run-docker-desktop-for-windows-in-a-vm-or-vdi-environment)
- [Index](#index)
- [FAQs](#faqs)
- [General FAQs for Desktop](#general-faqs-for-desktop)
- [FAQs for Docker Desktop for Linux](#faqs-for-docker-desktop-for-linux)
- [FAQs for Docker Desktop for Mac](#faqs-for-docker-desktop-for-mac)
- [FAQs on Docker Desktop releases](#faqs-on-docker-desktop-releases)
- [FAQs for Docker Desktop for Windows](#faqs-for-docker-desktop-for-windows)
- [Give feedback](#give-feedback)
- [Troubleshoot Docker Desktop](#troubleshoot-docker-desktop)
- [Known issues](#known-issues)
- [Fix "Docker.app is damaged and can't be opened" on macOS](#fix-docker-app-is-damaged-and-can-t-be-opened-on-macos)
- [Troubleshoot topics for Docker Desktop](#troubleshoot-topics-for-docker-desktop)
- [Uninstall Docker Desktop](#uninstall-docker-desktop)
- [Explore Docker Desktop](#explore-docker-desktop)
- [Explore the Builds view in Docker Desktop](#explore-the-builds-view-in-docker-desktop)
- [Explore the Containers view in Docker Desktop](#explore-the-containers-view-in-docker-desktop)
- [Explore the Images view in Docker Desktop](#explore-the-images-view-in-docker-desktop)
- [Explore the Kubernetes view](#explore-the-kubernetes-view)
- [Explore the Logs view in Docker Desktop](#explore-the-logs-view-in-docker-desktop)
- [Pause Docker Desktop](#pause-docker-desktop)
- [Docker Desktop's Resource Saver mode](#docker-desktop-s-resource-saver-mode)
- [Explore the Volumes view in Docker Desktop](#explore-the-volumes-view-in-docker-desktop)

### Dhi

- [Docker Hardened Images](#docker-hardened-images)
- [Explore Docker Hardened Images](#explore-docker-hardened-images)
- [Available types of Docker Hardened Images](#available-types-of-docker-hardened-images)
- [How Docker Hardened Images are built](#how-docker-hardened-images-are-built)
- [Malware scanning](#malware-scanning)
- [Understanding roles and responsibilities for Docker Hardened Images](#understanding-roles-and-responsibilities-for-docker-hardened-images)
- [Scanner integrations](#scanner-integrations)
- [Security concepts](#security-concepts)
- [Attestations](#attestations)
- [CIS Benchmark](#cis-benchmark)
- [Common Vulnerabilities and Exposures (CVEs)](#common-vulnerabilities-and-exposures-cves)
- [Image digests](#image-digests)
- [Minimal or distroless images](#minimal-or-distroless-images)
- [FIPS](#fips)
- [glibc and musl support in Docker Hardened Images](#glibc-and-musl-support-in-docker-hardened-images)
- [Base image hardening](#base-image-hardening)
- [Immutable infrastructure](#immutable-infrastructure)
- [Image provenance](#image-provenance)
- [Software Bill of Materials (SBOMs)](#software-bill-of-materials-sboms)
- [Code signing](#code-signing)
- [Supply-chain Levels for Software Artifacts (SLSA)](#supply-chain-levels-for-software-artifacts-slsa)
- [Software Supply Chain Security](#software-supply-chain-security)
- [Secure Software Development Lifecycle](#secure-software-development-lifecycle)
- [STIG](#stig)
- [Vulnerability Exploitability eXchange (VEX)](#vulnerability-exploitability-exchange-vex)
- [How Docker Hardened Images are tested](#how-docker-hardened-images-are-tested)
- [What are hardened images and why use them?](#what-are-hardened-images-and-why-use-them)
- [Docker Hardened Images quickstart](#docker-hardened-images-quickstart)
- [How-tos](#how-tos)
- [Create and build a Docker Hardened Image](#create-and-build-a-docker-hardened-image)
- [Customize a Docker Hardened Image or chart](#customize-a-docker-hardened-image-or-chart)
- [Use Hardened System Packages](#use-hardened-system-packages)
- [Use a Docker Hardened Image chart](#use-a-docker-hardened-image-chart)
- [Mirror a Docker Hardened Image repository](#mirror-a-docker-hardened-image-repository)
- [Apply Docker Hardened Image policies to your images](#apply-docker-hardened-image-policies-to-your-images)
- [Scan Docker Hardened Images](#scan-docker-hardened-images)
- [Search and evaluate Docker Hardened Images](#search-and-evaluate-docker-hardened-images)
- [Get started with DHI Select and Enterprise](#get-started-with-dhi-select-and-enterprise)
- [Troubleshoot](#troubleshoot)
- [Use a Docker Hardened Image](#use-a-docker-hardened-image)
- [Verify a Docker Hardened Image or chart](#verify-a-docker-hardened-image-or-chart)
- [Query VEX for a Docker Hardened Image](#query-vex-for-a-docker-hardened-image)
- [Migration](#migration)
- [Migration checklist](#migration-checklist)
- [Migration examples](#migration-examples)
- [.NET](#net)
- [Go](#go)
- [Java](#java)
- [Node.js](#node-js)
- [Python](#python)
- [Migrate from Alpine or Debian](#migrate-from-alpine-or-debian)
- [Migrate from Ubuntu](#migrate-from-ubuntu)
- [Migrate from Wolfi](#migrate-from-wolfi)
- [Migrate using Gordon](#migrate-using-gordon)
- [Release notes](#release-notes)
- [DHI CLI release notes](#dhi-cli-release-notes)
- [Docker Hardened Images release notes](#docker-hardened-images-release-notes)
- [Resources and feedback](#resources-and-feedback)
- [Tools](#tools)
- [Use the DHI API](#use-the-dhi-api)
- [Use the DHI CLI](#use-the-dhi-cli)
- [Use Docker Hub](#use-docker-hub)
- [Use the DHI MCP server](#use-the-dhi-mcp-server)
- [Use the DHI Terraform provider](#use-the-dhi-terraform-provider)

### Docker Hub

- [Docker Hub](#docker-hub)
- [Content library](#content-library)
- [Generative AI content](#generative-ai-content)
- [Mirror the Docker Hub library](#mirror-the-docker-hub-library)
- [Docker Hub search](#docker-hub-search)
- [Trusted content](#trusted-content)
- [Docker Hub MCP server](#docker-hub-mcp-server)
- [Docker Hub quickstart](#docker-hub-quickstart)
- [Docker Hub release notes](#docker-hub-release-notes)
- [Repositories](#repositories)
- [Archive or unarchive a repository](#archive-or-unarchive-a-repository)
- [Create a repository](#create-a-repository)
- [Delete a repository](#delete-a-repository)
- [Manage](#manage)
- [Access management](#access-management)
- [Automated builds](#automated-builds)
- [Advanced options for autobuild and autotest](#advanced-options-for-autobuild-and-autotest)
- [Automated repository tests](#automated-repository-tests)
- [Configure automated builds from GitHub and BitBucket](#configure-automated-builds-from-github-and-bitbucket)
- [Manage autobuilds](#manage-autobuilds)
- [Migrate from Autobuilds](#migrate-from-autobuilds)
- [Set up automated builds](#set-up-automated-builds)
- [Troubleshoot your autobuilds](#troubleshoot-your-autobuilds)
- [Export organization repositories to CSV](#export-organization-repositories-to-csv)
- [Image management](#image-management)
- [Bulk migrate images](#bulk-migrate-images)
- [Immutable tags on Docker Hub](#immutable-tags-on-docker-hub)
- [Image Management](#image-management)
- [Move images between repositories](#move-images-between-repositories)
- [Software artifacts on Docker Hub](#software-artifacts-on-docker-hub)
- [Push images to a repository](#push-images-to-a-repository)
- [Tags on Docker Hub](#tags-on-docker-hub)
- [Repository information](#repository-information)
- [Trusted content](#trusted-content)
- [Docker-Sponsored Open Source Program](#docker-sponsored-open-source-program)
- [Docker Verified Publisher Program](#docker-verified-publisher-program)
- [Insights and analytics](#insights-and-analytics)
- [Docker Official Images](#docker-official-images)
- [Image security insights](#image-security-insights)
- [Webhooks](#webhooks)
- [Settings](#settings)
- [Troubleshoot Docker Hub](#troubleshoot-docker-hub)
- [Docker Hub usage and limits](#docker-hub-usage-and-limits)
- [Best practices for optimizing Docker Hub usage](#best-practices-for-optimizing-docker-hub-usage)
- [Docker Hub pull usage and limits](#docker-hub-pull-usage-and-limits)

### Engine

- [Docker Engine](#docker-engine)
- [CLI](#cli)
- [Completion](#completion)
- [Filter commands](#filter-commands)
- [Format command and log output](#format-command-and-log-output)
- [OpenTelemetry for the Docker CLI](#opentelemetry-for-the-docker-cli)
- [Use a proxy server with the Docker CLI](#use-a-proxy-server-with-the-docker-cli)
- [Containers](#containers)
- [GPU access](#gpu-access)
- [Run multiple processes in a container](#run-multiple-processes-in-a-container)
- [Resource constraints](#resource-constraints)
- [Runtime metrics](#runtime-metrics)
- [Start containers automatically](#start-containers-automatically)
- [Docker daemon configuration overview](#docker-daemon-configuration-overview)
- [Alternative container runtimes](#alternative-container-runtimes)
- [Run containerd in the Docker daemon](#run-containerd-in-the-docker-daemon)
- [Use IPv6 networking](#use-ipv6-networking)
- [Live restore](#live-restore)
- [Read the daemon logs](#read-the-daemon-logs)
- [Collect Docker metrics with Prometheus](#collect-docker-metrics-with-prometheus)
- [Daemon proxy configuration](#daemon-proxy-configuration)
- [Configure remote access for Docker daemon](#configure-remote-access-for-docker-daemon)
- [Start the daemon](#start-the-daemon)
- [Troubleshooting the Docker daemon](#troubleshooting-the-docker-daemon)
- [Install Docker Engine](#install-docker-engine)
- [Install Docker Engine from binaries](#install-docker-engine-from-binaries)
- [Install Docker Engine on CentOS](#install-docker-engine-on-centos)
- [Install Docker Engine on Debian](#install-docker-engine-on-debian)
- [Install Docker Engine on Fedora](#install-docker-engine-on-fedora)
- [Linux post-installation steps for Docker Engine](#linux-post-installation-steps-for-docker-engine)
- [Install Docker Engine on Raspberry Pi OS (32-bit / armhf)](#install-docker-engine-on-raspberry-pi-os-32-bit-armhf)
- [Install Docker Engine on RHEL](#install-docker-engine-on-rhel)
- [Install Docker Engine on Ubuntu](#install-docker-engine-on-ubuntu)
- [View container logs](#view-container-logs)
- [Configure logging drivers](#configure-logging-drivers)
- [Logging drivers](#logging-drivers)
- [Amazon CloudWatch Logs logging driver](#amazon-cloudwatch-logs-logging-driver)
- [ETW logging driver](#etw-logging-driver)
- [Fluentd logging driver](#fluentd-logging-driver)
- [Google Cloud Logging driver](#google-cloud-logging-driver)
- [Graylog Extended Format logging driver](#graylog-extended-format-logging-driver)
- [Journald logging driver](#journald-logging-driver)
- [JSON File logging driver](#json-file-logging-driver)
- [Local file logging driver](#local-file-logging-driver)
- [Splunk logging driver](#splunk-logging-driver)
- [Syslog logging driver](#syslog-logging-driver)
- [Use docker logs with remote logging drivers](#use-docker-logs-with-remote-logging-drivers)
- [Customize log driver output](#customize-log-driver-output)
- [Use a logging driver plugin](#use-a-logging-driver-plugin)
- [Manage resources](#manage-resources)
- [Docker contexts](#docker-contexts)
- [Docker object labels](#docker-object-labels)
- [Prune unused Docker objects](#prune-unused-docker-objects)
- [Networking overview](#networking-overview)
- [Use CA certificates with Docker](#use-ca-certificates-with-docker)
- [Network drivers](#network-drivers)
- [Bridge network driver](#bridge-network-driver)
- [Host network driver](#host-network-driver)
- [IPvlan network driver](#ipvlan-network-driver)
- [Macvlan network driver](#macvlan-network-driver)
- [None network driver](#none-network-driver)
- [Overlay network driver](#overlay-network-driver)
- [Docker with iptables](#docker-with-iptables)
- [Docker with nftables](#docker-with-nftables)
- [Legacy container links](#legacy-container-links)
- [Packet filtering and firewalls](#packet-filtering-and-firewalls)
- [Port publishing and mapping](#port-publishing-and-mapping)
- [Docker Engine 17.03 release notes](#docker-engine-17-03-release-notes)
- [Docker Engine 17.04 release notes](#docker-engine-17-04-release-notes)
- [Docker Engine 17.05 release notes](#docker-engine-17-05-release-notes)
- [Docker Engine 17.06 release notes](#docker-engine-17-06-release-notes)
- [Docker Engine 17.07 release notes](#docker-engine-17-07-release-notes)
- [Docker Engine 17.09 release notes](#docker-engine-17-09-release-notes)
- [Docker Engine 17.10 release notes](#docker-engine-17-10-release-notes)
- [Docker Engine 17.11 release notes](#docker-engine-17-11-release-notes)
- [Docker Engine 17.12 release notes](#docker-engine-17-12-release-notes)
- [Docker Engine 18.01 release notes](#docker-engine-18-01-release-notes)
- [Docker Engine 18.02 release notes](#docker-engine-18-02-release-notes)
- [Docker Engine 18.03 release notes](#docker-engine-18-03-release-notes)
- [Docker Engine 18.04 release notes](#docker-engine-18-04-release-notes)
- [Docker Engine 18.05 release notes](#docker-engine-18-05-release-notes)
- [Docker Engine 18.06 release notes](#docker-engine-18-06-release-notes)
- [Docker Engine 18.09 release notes](#docker-engine-18-09-release-notes)
- [Docker Engine 19.03 release notes](#docker-engine-19-03-release-notes)
- [Docker Engine 20.10 release notes](#docker-engine-20-10-release-notes)
- [Docker Engine 23.0 release notes](#docker-engine-23-0-release-notes)
- [Docker Engine 24.0 release notes](#docker-engine-24-0-release-notes)
- [Docker Engine 25.0 release notes](#docker-engine-25-0-release-notes)
- [Docker Engine 26.0 release notes](#docker-engine-26-0-release-notes)
- [Docker Engine 26.1 release notes](#docker-engine-26-1-release-notes)
- [Docker Engine version 27 release notes](#docker-engine-version-27-release-notes)
- [Docker Engine version 28 release notes](#docker-engine-version-28-release-notes)
- [Docker Engine version 29 release notes](#docker-engine-version-29-release-notes)
- [Release notes](#release-notes)
- [Docker Engine prior releases](#docker-engine-prior-releases)
- [Docker Engine security](#docker-engine-security)
- [Antivirus software and Docker](#antivirus-software-and-docker)
- [AppArmor security profiles for Docker](#apparmor-security-profiles-for-docker)
- [Verify repository client with certificates](#verify-repository-client-with-certificates)
- [Readme](#readme)
- [Docker security non-events](#docker-security-non-events)
- [Protect the Docker daemon socket](#protect-the-docker-daemon-socket)
- [Rootless mode](#rootless-mode)
- [Tips](#tips)
- [Troubleshooting](#troubleshooting)
- [UID/GID mapping](#uid-gid-mapping)
- [Seccomp security profiles for Docker](#seccomp-security-profiles-for-docker)
- [Content trust in Docker](#content-trust-in-docker)
- [Deploy Notary Server with Compose](#deploy-notary-server-with-compose)
- [Automation with content trust](#automation-with-content-trust)
- [Delegations for content trust](#delegations-for-content-trust)
- [Manage keys for content trust](#manage-keys-for-content-trust)
- [Play in a content trust sandbox](#play-in-a-content-trust-sandbox)
- [Isolate containers with a user namespace](#isolate-containers-with-a-user-namespace)
- [Storage](#storage)
- [Bind mounts](#bind-mounts)
- [containerd image store with Docker Engine](#containerd-image-store-with-docker-engine)
- [Storage drivers](#storage-drivers)
- [AUFS storage driver](#aufs-storage-driver)
- [BTRFS storage driver](#btrfs-storage-driver)
- [Device Mapper storage driver (deprecated)](#device-mapper-storage-driver-deprecated)
- [OverlayFS storage driver](#overlayfs-storage-driver)
- [Select a storage driver](#select-a-storage-driver)
- [VFS storage driver](#vfs-storage-driver)
- [windowsfilter storage driver](#windowsfilter-storage-driver)
- [ZFS storage driver](#zfs-storage-driver)
- [Image mounts](#image-mounts)
- [tmpfs mounts](#tmpfs-mounts)
- [Volumes](#volumes)
- [Swarm mode](#swarm-mode)
- [Administer and maintain a swarm of Docker Engines](#administer-and-maintain-a-swarm-of-docker-engines)
- [Store configuration data using Docker Configs](#store-configuration-data-using-docker-configs)
- [How swarm works](#how-swarm-works)
- [How nodes work](#how-nodes-work)
- [Manage swarm security with public key infrastructure (PKI)](#manage-swarm-security-with-public-key-infrastructure-pki)
- [How services work](#how-services-work)
- [Swarm task states](#swarm-task-states)
- [Use Swarm mode routing mesh](#use-swarm-mode-routing-mesh)
- [Join nodes to a swarm](#join-nodes-to-a-swarm)
- [Swarm mode key concepts](#swarm-mode-key-concepts)
- [Manage nodes in a swarm](#manage-nodes-in-a-swarm)
- [Manage swarm service networks](#manage-swarm-service-networks)
- [Raft consensus in swarm mode](#raft-consensus-in-swarm-mode)
- [Manage sensitive data with Docker secrets](#manage-sensitive-data-with-docker-secrets)
- [Deploy services to a swarm](#deploy-services-to-a-swarm)
- [Deploy a stack to a swarm](#deploy-a-stack-to-a-swarm)
- [Run Docker Engine in swarm mode](#run-docker-engine-in-swarm-mode)
- [Getting started with Swarm mode](#getting-started-with-swarm-mode)
- [Add nodes to the swarm](#add-nodes-to-the-swarm)
- [Create a swarm](#create-a-swarm)
- [Delete the service running on the swarm](#delete-the-service-running-on-the-swarm)
- [Deploy a service to the swarm](#deploy-a-service-to-the-swarm)
- [Drain a node on the swarm](#drain-a-node-on-the-swarm)
- [Inspect a service on the swarm](#inspect-a-service-on-the-swarm)
- [Apply rolling updates to a service](#apply-rolling-updates-to-a-service)
- [Scale the service in the swarm](#scale-the-service-in-the-swarm)
- [Lock your swarm to protect its encryption key](#lock-your-swarm-to-protect-its-encryption-key)

### Enterprise

- [Deploy Docker Desktop](#deploy-docker-desktop)
- [Dev box](#dev-box)
- [Enterprise deployment FAQs](#enterprise-deployment-faqs)
- [Install Docker Desktop from the Microsoft Store on Windows](#install-docker-desktop-from-the-microsoft-store-on-windows)
- [MSI installer](#msi-installer)
- [PKG installer](#pkg-installer)
- [Deploy with Intune](#deploy-with-intune)
- [Deploy with Jamf Pro](#deploy-with-jamf-pro)
- [Security for enterprises](#security-for-enterprises)
- [Enforce sign-in for Docker Desktop](#enforce-sign-in-for-docker-desktop)
- [Configure sign-in enforcement](#configure-sign-in-enforcement)
- [Hardened Docker Desktop](#hardened-docker-desktop)
- [Air-gapped containers](#air-gapped-containers)
- [Enhanced Container Isolation](#enhanced-container-isolation)
- [Configure Docker socket exceptions and advanced settings](#configure-docker-socket-exceptions-and-advanced-settings)
- [Enable Enhanced Container Isolation](#enable-enhanced-container-isolation)
- [Enhanced Container Isolation FAQs](#enhanced-container-isolation-faqs)
- [Enhanced Container Isolation limitations](#enhanced-container-isolation-limitations)
- [Image Access Management](#image-access-management)
- [Namespace access control](#namespace-access-control)
- [Registry Access Management](#registry-access-management)
- [Settings Management](#settings-management)
- [Desktop settings reporting](#desktop-settings-reporting)
- [Configure Settings Management in Docker Home](#configure-settings-management-in-docker-home)
- [Configure Settings Management with a JSON file](#configure-settings-management-with-a-json-file)
- [Settings reference](#settings-reference)

### Extensions

- [Docker Extensions](#docker-extensions)
- [Overview of the Extensions SDK](#overview-of-the-extensions-sdk)
- [Extension architecture](#extension-architecture)
- [Extension metadata](#extension-metadata)
- [Extension security](#extension-security)
- [Part one: Build](#part-one-build)
- [Add a backend to your extension](#add-a-backend-to-your-extension)
- [Create an advanced frontend extension](#create-an-advanced-frontend-extension)
- [Create a simple extension](#create-a-simple-extension)
- [UI styling overview for Docker extensions](#ui-styling-overview-for-docker-extensions)
- [Design guidelines for Docker extensions](#design-guidelines-for-docker-extensions)
- [Docker design principles](#docker-design-principles)
- [MUI best practices](#mui-best-practices)
- [Developer SDK tools](#developer-sdk-tools)
- [Extension APIs](#extension-apis)
- [Extension Backend](#extension-backend)
- [Navigation](#navigation)
- [Dashboard](#dashboard)
- [Docker](#docker)
- [Extension UI API](#extension-ui-api)
- [Continuous Integration (CI)](#continuous-integration-ci)
- [Test and debug](#test-and-debug)
- [CLI reference](#cli-reference)
- [Package and release your extension](#package-and-release-your-extension)
- [Part two: Publish](#part-two-publish)
- [Extension image labels](#extension-image-labels)
- [Build multi-arch extensions](#build-multi-arch-extensions)
- [Publish in the Marketplace](#publish-in-the-marketplace)
- [Share your extension](#share-your-extension)
- [Validate your extension](#validate-your-extension)
- [Developer Guides](#developer-guides)
- [Invoke host binaries](#invoke-host-binaries)
- [Interacting with Kubernetes from an extension](#interacting-with-kubernetes-from-an-extension)
- [Authentication](#authentication)
- [Use the Docker socket from the extension backend](#use-the-docker-socket-from-the-extension-backend)
- [The build and publish process](#the-build-and-publish-process)
- [Quickstart](#quickstart)
- [Marketplace extensions](#marketplace-extensions)
- [Non-marketplace extensions](#non-marketplace-extensions)
- [Configure a private marketplace for extensions](#configure-a-private-marketplace-for-extensions)
- [Settings and feedback for Docker Extensions](#settings-and-feedback-for-docker-extensions)

### Faqs

- [FAQs](#faqs)
- [Account FAQs](#account-faqs)
- [Platform FAQs](#platform-faqs)
- [Security FAQs](#security-faqs)
- [Subscription and billing FAQs](#subscription-and-billing-faqs)

### Offload

- [Docker Offload](#docker-offload)
- [About Docker Offload](#about-docker-offload)
- [Configure Docker Offload](#configure-docker-offload)
- [Give feedback](#give-feedback)
- [Optimize Docker Offload usage](#optimize-docker-offload-usage)
- [Docker Offload quickstart](#docker-offload-quickstart)
- [Troubleshoot Docker Offload](#troubleshoot-docker-offload)
- [Docker Offload usage](#docker-offload-usage)

### Reference

- [Reference documentation](#reference-documentation)
- [API reference](#api-reference)
- [Docker AI Governance API](#docker-ai-governance-api)
- [DVP Data API](#dvp-data-api)
- [Docker Verified Publisher API changelog](#docker-verified-publisher-api-changelog)
- [Deprecated Docker Verified Publisher API endpoints](#deprecated-docker-verified-publisher-api-endpoints)
- [Docker Verified Publisher API reference](#docker-verified-publisher-api-reference)
- [Docker Engine API](#docker-engine-api)
- [Latest](#latest)
- [Develop with Docker Engine SDKs](#develop-with-docker-engine-sdks)
- [Examples using the Docker Engine SDKs and Docker API](#examples-using-the-docker-engine-sdks-and-docker-api)
- [API reference by version](#api-reference-by-version)
- [Docker Engine API v1.40 reference](#docker-engine-api-v1-40-reference)
- [Docker Engine API v1.41 reference](#docker-engine-api-v1-41-reference)
- [Docker Engine API v1.42 reference](#docker-engine-api-v1-42-reference)
- [Docker Engine API v1.43 reference](#docker-engine-api-v1-43-reference)
- [Docker Engine API v1.44 reference](#docker-engine-api-v1-44-reference)
- [Docker Engine API v1.45 reference](#docker-engine-api-v1-45-reference)
- [Docker Engine API v1.46 reference](#docker-engine-api-v1-46-reference)
- [Docker Engine API v1.47 reference](#docker-engine-api-v1-47-reference)
- [Docker Engine API v1.48 reference](#docker-engine-api-v1-48-reference)
- [Docker Engine API v1.49 reference](#docker-engine-api-v1-49-reference)
- [Docker Engine API v1.50 reference](#docker-engine-api-v1-50-reference)
- [Docker Engine API v1.51 reference](#docker-engine-api-v1-51-reference)
- [Docker Engine API v1.52 reference](#docker-engine-api-v1-52-reference)
- [Docker Engine API v1.53 reference](#docker-engine-api-v1-53-reference)
- [Docker Engine API v1.54 reference](#docker-engine-api-v1-54-reference)
- [Docker Engine API v1.55 reference](#docker-engine-api-v1-55-reference)
- [Docker Engine API v1.56 reference](#docker-engine-api-v1-56-reference)
- [Interface: BackendV0](#interface-backendv0)
- [Interface: DesktopUI](#interface-desktopui)
- [Interface: Dialog](#interface-dialog)
- [Interface: Docker](#interface-docker)
- [Interface: DockerCommand](#interface-dockercommand)
- [Interface: DockerDesktopClient](#interface-dockerdesktopclient)
- [Interface: Exec](#interface-exec)
- [Interface: ExecOptions](#interface-execoptions)
- [Interface: ExecProcess](#interface-execprocess)
- [Interface: ExecResult](#interface-execresult)
- [Interface: ExecResultV0](#interface-execresultv0)
- [Interface: ExecStreamOptions](#interface-execstreamoptions)
- [Interface: Extension](#interface-extension)
- [Interface: ExtensionCli](#interface-extensioncli)
- [Interface: ExtensionHost](#interface-extensionhost)
- [Interface: ExtensionVM](#interface-extensionvm)
- [Interface: Host](#interface-host)
- [Interface: HttpService](#interface-httpservice)
- [Interface: NavigationIntents](#interface-navigationintents)
- [Interface: OpenDialogResult](#interface-opendialogresult)
- [Interface: RawExecResult](#interface-rawexecresult)
- [Interface: RequestConfig](#interface-requestconfig)
- [Interface: RequestConfigV0](#interface-requestconfigv0)
- [Interface: ServiceError](#interface-serviceerror)
- [Interface: SpawnOptions](#interface-spawnoptions)
- [Interface: Toast](#interface-toast)
- [Extensions API Reference](#extensions-api-reference)
- [Docker Hub API](#docker-hub-api)
- [Docker Hub API changelog](#docker-hub-api-changelog)
- [Deprecated Docker Hub API endpoints](#deprecated-docker-hub-api-endpoints)
- [Docker Hub API reference](#docker-hub-api-reference)
- [Index](#index)
- [Registry authentication](#registry-authentication)
- [Supported registry API for Docker Hub](#supported-registry-api-for-docker-hub)
- [CLI reference](#cli-reference)
- [Compose file reference](#compose-file-reference)
- [Compose Build Specification](#compose-build-specification)
- [Configs top-level element](#configs-top-level-element)
- [Compose Deploy Specification](#compose-deploy-specification)
- [Compose Develop Specification](#compose-develop-specification)
- [Extensions](#extensions)
- [Fragments](#fragments)
- [Use include to modularize Compose files](#use-include-to-modularize-compose-files)
- [Interpolation](#interpolation)
- [Legacy versions](#legacy-versions)
- [Merge Compose files](#merge-compose-files)
- [Models](#models)
- [Define and manage networks in Docker Compose](#define-and-manage-networks-in-docker-compose)
- [Learn how to use profiles in Docker Compose](#learn-how-to-use-profiles-in-docker-compose)
- [Secrets](#secrets)
- [Define services in Docker Compose](#define-services-in-docker-compose)
- [Version and name top-level elements](#version-and-name-top-level-elements)
- [Define and manage volumes in Docker Compose](#define-and-manage-volumes-in-docker-compose)
- [Glossary](#glossary)
- [Samples overview](#samples-overview)
- [Agentic AI samples](#agentic-ai-samples)
- [AI/ML samples](#ai-ml-samples)
- [Angular samples](#angular-samples)
- [Cloudflared samples](#cloudflared-samples)
- [Django samples](#django-samples)
- [.NET samples](#net-samples)
- [Elasticsearch / Logstash / Kibana samples](#elasticsearch-logstash-kibana-samples)
- [Express samples](#express-samples)
- [FastAPI samples](#fastapi-samples)
- [Flask samples](#flask-samples)
- [Gitea samples](#gitea-samples)
- [Go samples](#go-samples)
- [Java samples](#java-samples)
- [JavaScript samples](#javascript-samples)
- [MariaDB samples](#mariadb-samples)
- [Minecraft samples](#minecraft-samples)
- [MongoDB samples](#mongodb-samples)
- [MS-SQL samples](#ms-sql-samples)
- [MySQL samples](#mysql-samples)
- [Nextcloud samples](#nextcloud-samples)
- [NGINX samples](#nginx-samples)
- [Node.js samples](#node-js-samples)
- [PHP samples](#php-samples)
- [Pi-hole samples](#pi-hole-samples)
- [Plex samples](#plex-samples)
- [Portainer samples](#portainer-samples)
- [PostgreSQL samples](#postgresql-samples)
- [Prometheus samples](#prometheus-samples)
- [Python samples](#python-samples)
- [Rails samples](#rails-samples)
- [React samples](#react-samples)
- [Redis samples](#redis-samples)
- [Ruby samples](#ruby-samples)
- [Rust samples](#rust-samples)
- [Spark samples](#spark-samples)
- [Spring Boot samples](#spring-boot-samples)
- [Traefik samples](#traefik-samples)
- [TypeScript samples](#typescript-samples)
- [Vue.js samples](#vue-js-samples)
- [WireGuard samples](#wireguard-samples)
- [WordPress samples](#wordpress-samples)

### Scout

- [Docker Scout](#docker-scout)
- [Deep dive](#deep-dive)
- [Advisory database sources and matching service](#advisory-database-sources-and-matching-service)
- [Data collection and storage in Docker Scout](#data-collection-and-storage-in-docker-scout)
- [Explore](#explore)
- [Docker Scout image analysis](#docker-scout-image-analysis)
- [Dashboard](#dashboard)
- [Manage vulnerability exceptions](#manage-vulnerability-exceptions)
- [Image details view](#image-details-view)
- [Docker Scout metrics exporter](#docker-scout-metrics-exporter)
- [How-tos](#how-tos)
- [Use Scout with different artifact types](#use-scout-with-different-artifact-types)
- [Configure Docker Scout with environment variables](#configure-docker-scout-with-environment-variables)
- [Create an exception using the GUI](#create-an-exception-using-the-gui)
- [Create an exception using the VEX](#create-an-exception-using-the-vex)
- [Docker Scout SBOMs](#docker-scout-sboms)
- [Install Docker Scout](#install-docker-scout)
- [Integrating Docker Scout with other systems](#integrating-docker-scout-with-other-systems)
- [Using Docker Scout in continuous integration](#using-docker-scout-in-continuous-integration)
- [Integrate Docker Scout with Microsoft Azure DevOps Pipelines](#integrate-docker-scout-with-microsoft-azure-devops-pipelines)
- [Integrate Docker Scout with Circle CI](#integrate-docker-scout-with-circle-ci)
- [Integrate Docker Scout with GitHub Actions](#integrate-docker-scout-with-github-actions)
- [Integrate Docker Scout with GitLab CI/CD](#integrate-docker-scout-with-gitlab-ci-cd)
- [Integrate Docker Scout with Jenkins](#integrate-docker-scout-with-jenkins)
- [Integrating Docker Scout with environments](#integrating-docker-scout-with-environments)
- [Generic environment integration with CLI](#generic-environment-integration-with-cli)
- [Integrate Docker Scout with a container registry](#integrate-docker-scout-with-a-container-registry)
- [Policy Evaluation](#policy-evaluation)
- [Evaluate policies](#evaluate-policies)
- [Docker Scout quickstart](#docker-scout-quickstart)
- [Release notes](#release-notes)
- [Cli](#cli)
- [Docker Scout release notes](#docker-scout-release-notes)

### Security

- [Security](#security)
- [Access tokens](#access-tokens)
- [Organization access tokens](#organization-access-tokens)
- [Personal access tokens](#personal-access-tokens)
- [Enable two-factor authentication for your Docker account](#enable-two-factor-authentication-for-your-docker-account)
- [Recover your Docker account](#recover-your-docker-account)
- [Authentication](#authentication)
- [OIDC connections overview](#oidc-connections-overview)
- [Create and manage OIDC connections](#create-and-manage-oidc-connections)
- [OIDC connections rulesets and subject claims](#oidc-connections-rulesets-and-subject-claims)
- [Single sign-on overview](#single-sign-on-overview)
- [Set up single sign-on](#set-up-single-sign-on)
- [Manage SSO domains and connections](#manage-sso-domains-and-connections)
- [Troubleshoot single sign-on](#troubleshoot-single-sign-on)
- [Provision users](#provision-users)
- [Auto-provisioning](#auto-provisioning)
- [Add and manage domains](#add-and-manage-domains)
- [Just-in-Time provisioning](#just-in-time-provisioning)
- [SCIM overview](#scim-overview)
- [Group mapping](#group-mapping)
- [Migrate JIT to SCIM](#migrate-jit-to-scim)
- [Set up SCIM provisioning](#set-up-scim-provisioning)
- [Troubleshoot provisioning](#troubleshoot-provisioning)
- [Docker organization roles and permissions](#docker-organization-roles-and-permissions)
- [Docker core roles and permissions](#docker-core-roles-and-permissions)
- [Custom roles and permissions overview](#custom-roles-and-permissions-overview)
- [Manage custom roles in Docker Home](#manage-custom-roles-in-docker-home)
- [Custom role permissions reference](#custom-role-permissions-reference)
- [Docker security announcements](#docker-security-announcements)

### Subscription Billing

- [Subscription and billing](#subscription-and-billing)
- [Docker Desktop license agreement](#docker-desktop-license-agreement)
- [Use 3D Secure authentication for Docker billing](#use-3d-secure-authentication-for-docker-billing)
- [Manage billing](#manage-billing)
- [Update your billing details](#update-your-billing-details)
- [Billing and invoice history](#billing-and-invoice-history)
- [Add or update a payment method](#add-or-update-a-payment-method)
- [Manage plans](#manage-plans)
- [Sales tax exemption and VAT](#sales-tax-exemption-and-vat)
- [Plans](#plans)
- [AI Governance plan](#ai-governance-plan)
- [DHI plans](#dhi-plans)
- [Docker Agentic Platform plans](#docker-agentic-platform-plans)
- [Docker Verified Publisher plans](#docker-verified-publisher-plans)
- [Docker plans](#docker-plans)
- [Gordon plans](#gordon-plans)

### Support

- [Get support for Docker products](#get-support-for-docker-products)

### Unassociated Machines

- [Manage unassociated machines](#manage-unassociated-machines)

### Docker

- [Home](#home)
- [Automated traffic detection](#automated-traffic-detection)
- [Manuals](#manuals)
- [Docker AI overview](#docker-ai-overview)
- [Release notes for Docker Home, the Admin Console, billing, security, and subscription features](#release-notes-for-docker-home-the-admin-console-billing-security-and-subscription-features)
- [Docker's product release lifecycle](#docker-s-product-release-lifecycle)
- [Deprecated and retired Docker products and features](#deprecated-and-retired-docker-products-and-features)
- [Testcontainers Cloud](#testcontainers-cloud)
- [Testcontainers](#testcontainers)

---



---

# Accounts

*Sección: Accounts*

A Docker account identifies you and lets you access Docker products. You
manage it in [Docker Home](https://app.docker.com/). Docker has two
primary account types: individual and organization. A company groups
multiple organizations.

| Account type | What it is | Who it's for |
| --- | --- | --- |
| Individual | A Docker ID with personal settings, Hub repositories, and sign-in methods | A person |
| Organization | A shared workspace for members, teams, and repositories | Teams on Docker Team or Business |
| Company | Multiple organizations under centralized administration | Docker Business subscribers |

You always sign in with your individual account, then work in the
organizations you own or belong to. Those organizations sit under a
company when you administer more than one.

## Next steps

{{< grid >}}


---

# Company overview

*Sección: Accounts*

{{< summary-bar feature_name="Company" >}}

A company groups multiple Docker organizations for centralized configuration
and provides a single point of visibility across those organizations.
Organization owners with a Docker Business subscription can create a company
and manage it through Docker Home.

## Company structure

A company sits at the top of the hierarchy and groups multiple Docker
organizations for centralized configuration. Companies are only available
for Docker Business subscribers.

![Diagram showing Docker’s administration hierarchy with Company at the top, followed by Organizations, Teams, and Members](../organization/images/docker-admin-structure.webp)

An organization sits below the company. You group teams and members there
and assign access to repositories. Every Docker Team and Business
subscriber has at least one organization.

For organization structure, including teams and members, see
[Organization accounts](../organization/index.md).

[Upgrading to a Docker Business plan](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdmin)
grants you the company owner role so you can manage multiple organizations.

## Company roles

A company includes one or more company owners. The creator of a company
becomes both a company owner and an organization owner, and occupies a seat
as organization owner. After creation, a company can have multiple owners,
and each owner has visibility across the entire company. They can manage
settings for every organization under it and have the same access rights as
organization owners.

- A company can have up to ten unique company owners.
- Company owners don't occupy a seat unless one of the following applies:
  - They're added as a member of an organization under the company.
  - SSO is enabled and the company owner signs in through SSO, which
    automatically adds them as an organization member.

To add or remove company owners, see
[Manage your company](manage.md#company-owners).

## Next steps

Learn how to create and manage a company in the following sections.

{{< grid >}}


---

# Manage company organizations, owners, and members

*Sección: Accounts*

{{< summary-bar feature_name="Company" >}}

After creating a company, you can manage multiple organizations from
Docker Home. Company owners can use the company portal to invite members to
specific organizations, view seat availability across organizations, and
add new company owners.

## Add more organizations

Company owners can add Docker organizations with a Docker Business plan
to their company, so long as they're also the organization owners for
that organization. There's no limit to the number of organizations you
add to a company.

> [!IMPORTANT]
>
> Once you add an organization to a company, you can't remove it from the
> company.

1. Sign in to [Docker Home](https://app.docker.com) and select
   your company.
1. Select **Managed organizations**.
1. Select **Add organization**, then select an organization from the
   drop-down list.

A nested organization must keep its Docker Business subscription to stay
managed by the company. If an organization downgrades from Docker
Business, you can no longer manage it through the company, and its owner
must manage it separately.

## Company owners

A company can have multiple owners who manage the company and all of its
organizations. For details about the company owner role and how it affects
seats, see [Company roles](index.md#company-roles).

### Add a company owner

1. Sign in to [Docker Home](https://app.docker.com) and select your company.
1. Select **Company owners**, then select **Add owner**.
1. Specify the member's Docker ID, then select **Add company owner**.

### Remove a company owner

1. Sign in to [Docker Home](https://app.docker.com) and select your company.
1. Select **Company owners**.
1. Find the company owner you want to remove and select the **Actions**
   menu, then select **Remove as company owner**.

## Company invitations

You add a member to your company by inviting them to an organization within
the company. Company owners can invite members to any organization in the
company using a Docker ID, email address, or in bulk with a CSV file of
email addresses.

Members and invitations belong to individual organizations, not to the
company itself. A pending invitation occupies a seat until the invitee
accepts.

### Invite members to an organization

1. Sign in to [Docker Home](https://app.docker.com) and select your company.
1. Select **Users**, then select **Invite**.

{{< tabs >}}
{{< tab name="Email or username" >}}

1. Select **Emails or usernames**.
1. Enter the Docker IDs or email addresses of the invitees.
1. Select an organization for each invitee.

{{< /tab >}}
{{< tab name="CSV upload" >}}

1. Select **CSV upload**.
1. Upload a CSV file of email addresses.
1. Select an organization for the invitees.

{{< /tab >}}
{{< /tabs >}}

Invitees receive an email with instructions to accept. After they accept,
new members appear on the **Users** page. The table shows how many
organizations each member belongs to.

### Resend invitations

Company owners can resend invitations from the company-level **Users**
page.

{{< tabs >}}
{{< tab name="Individual" >}}

1. Select your company from [Docker Home](https://app.docker.com/).
1. Select **Users**, then locate the invitee from the table.
1. Select the **Actions** menu, then select **Resend**.
   - Before resending, confirm you selected the correct invitee.
   - The resend invitation modal displays the date you originally invited
     the invitee.
1. Select **Invite** to confirm.

{{< /tab >}}
{{< tab name="Bulk" >}}

1. Select your company from [Docker Home](https://app.docker.com/).
1. Select **Users**.
1. From the table, use the multi-select checkboxes next to the invitees
   you want to resend to.
1. Select **Resend invites**, then select **Resend** to confirm.

{{< /tab >}}
{{< /tabs >}}

## Export a member list CSV

Company owners can export a CSV file of members across organizations in the
company.

1. Sign in to [Docker Home](https://app.docker.com/) and select your company.
1. Select **Users**.
1. Select the **Download** icon. The CSV file downloads in your browser.

   {{< accordion title="CSV fields" >}}
   - Name: The member's name
   - Username: The member's Docker ID
   - Email: The member's email address
   - Member of Organizations: Organizations the member belongs to within the
     company
   - Invited to Organizations: Organizations where the invitee has a
     pending invitation
   - Account created: The time and date when the account was created

   {{< /accordion >}}

## Add seats to an organization

If you have a self-serve subscription that has no pending subscription
changes, you can add seats using Docker Home. For more information about
adding seats, see
[Manage seats](../organization/manage/manage-seats.md#add-seats-to-your-subscription).

If you have a sales-assisted subscription, you must contact Docker support
or sales to add seats.

## Manage teams

Teams exist at the organization level, not the company level. After inviting
members to an organization, you can add them to teams within that
organization. For more details, see
[Manage members on a team](../organization/manage/members.md#manage-members-on-a-team).

## Next steps

- [Company overview](index.md)
- [Manage organization members](../organization/manage/members.md)
- [Manage seats](../organization/manage/manage-seats.md)
- [Roles and permissions](../../security/roles-and-permissions/index.md)


---

# Create new company

*Sección: Accounts*

{{< summary-bar feature_name="Company" >}}

Learn how to create a new company in Docker Home, a centralized
dashboard for managing organizations.

## Prerequisites

Before you begin, you must:

- Be the owner of the organization you want to add to your company
- Have a Docker Business subscription

## Create a company

To create a new company:

1. Sign in to [Docker Home](https://app.docker.com/) and select the
   organization you want to add to your company.
1. Select **Organization settings**.
1. Select **Create a company**.
1. Enter a unique name for your company, then select **Continue**.

   > [!TIP]
   >
   > The name for your company can't be the same as an existing user,
   > organization, or company namespace.

1. Review the migration details and then select **Create company**.

When you create the company, the organization you selected is automatically
migrated to the new company.

For more information on how you can add more organizations to your company,
see [Add more organizations](manage.md#add-more-organizations).

## Next steps

- [Add organizations](manage.md#add-more-organizations)
- [Invite company members](manage.md#company-invitations)
- [Manage company owners](manage.md#company-owners)

## More resources

- [Video: Create a company](https://youtu.be/XZ5_i6qiKho?feature=shared&t=359)


---

# Docker individual accounts

*Sección: Accounts*

A Docker account is how Docker identifies you. Use it to access products like
Docker Hub and Docker Desktop, manage settings, and join organizations.

For how individual, organization, and company accounts compare, see
[Accounts](../index.md). For organization accounts, including
companies, see
[Organization accounts](../organization/index.md).

## Docker ID, email, and sign-in

When you create an account, you choose a Docker ID and a sign-in method.
Docker also ties a verified email to the account.

- Docker account: Associates your plans, Hub repositories, and account
  settings.
- Docker ID: A unique username that identifies you.
- Email: How Docker contacts you for notifications and security-related
  communications.
- Sign-in method: Email and password,
  [single sign-on (SSO)](../../security/authentication/single-sign-on/index.md),
  Google, or GitHub.

## Next steps

{{< grid >}}


---

# Create a Docker account

*Sección: Accounts*

You can create a free Docker account with your email address or by signing up
with your Google or GitHub account. After creating a unique Docker ID, you can
access Docker products, including Docker Hub, Docker Desktop, and Docker Scout.

Your Docker ID becomes your username for hosted Docker services and
[Docker forums](https://forums.docker.com/).

> [!TIP]
>
> See
> [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsCreateAccount)
> for available plans.

## Create and verify your account

Signing up with an email address, Google, or GitHub requires verification
before you can sign in:

- If you sign up with Google or GitHub, verify your email address with that
  provider first.
- If you sign up with an email address, Docker sends a one-time password
  (OTP). Enter the code from the Docker email on the OTP page.

Docker blocks sign-in until you've verified your account.

{{< tabs >}}
{{< tab name="Email" >}}

1. Go to the [Docker sign-up page](https://app.docker.com/signup/) and enter a
   unique, valid email address.
1. Enter a username to use as your Docker ID. After you create your Docker
   ID, you can't change it or reuse it if you deactivate this account. Your
   username:
   - Must be between 4 and 30 characters long
   - Can only contain numbers and lowercase letters
1. Choose a password that's at least 9 characters long, then select
   **Sign up**.
1. Verify your email address when you receive the Docker OTP verification
   email. This completes the registration process.

{{< /tab >}}
{{< tab name="Google or GitHub" >}}

1. Go to the [Docker sign-up page](https://app.docker.com/signup/).
1. Select your social provider, Google or GitHub.
1. Select the social account you want to link to your Docker account.
1. Select **Authorize Docker** to let Docker access your social account
   information. Docker redirects you to the sign-up page.
1. Enter a username to use as your Docker ID. After you create your Docker
   ID, you can't change it or reuse it if you deactivate this account. Your
   username:
   - Must be between 4 and 30 characters long
   - Can only contain numbers and lowercase letters
1. Select **Sign up**.

{{< /tab >}}
{{< /tabs >}}

## Troubleshooting

If you have a paid Docker subscription,
[contact the Support team](https://hub.docker.com/support/contact/) for
assistance.

All Docker users can seek troubleshooting information and support through the
following resources, where Docker or the community respond on a best-effort
basis:

- [Docker Community Forums](https://forums.docker.com/)
- [Docker Community Slack](https://dockr.ly/comm-slack)

## Next steps

- [Manage a Docker account](manage-account.md)
- [Enable two-factor authentication](../../security/authentication/2fa/index.md)


---

# Deactivate a Docker account

*Sección: Accounts*

Learn how to deactivate an individual Docker account, including the
prerequisites required for deactivation.

For information on deactivating an organization, see
[Deactivate an organization](../organization/manage/deactivate-account.md).

> [!WARNING]
>
> All Docker products and services that use your Docker account are
> inaccessible after deactivating your account.

## Prerequisites

Before deactivating your Docker account, complete the following
requirements:

- If you are an organization or company owner, you must leave your
  organization or company before deactivating your Docker account:
  1. Sign in to [Docker Home](https://app.docker.com/admin) and choose your
     organization.
  1. Select **Members** and find your username.
  1. Select the **Actions** menu and then select **Leave organization**.
- If you are the sole owner of an organization, you must assign the owner
  role to another member of the organization and then remove yourself from
  the organization, or deactivate the organization. Similarly, if you are
  the sole owner of a company, either add someone else as a company owner
  and then remove yourself, or deactivate the company.
- If you have an active Docker subscription,
  [downgrade it to a Docker Personal
  subscription](../../subscription-billing/plans/docker.md#cancel-a-docker-plan).
- Download any images and tags you want to keep. Use
  `docker pull -a <image>` to pull all tags, or `docker pull <image>:<tag>`
  to pull a specific tag.
- If you linked a GitHub or Bitbucket account for automated builds, unlink
  it. See
  [Unlink a GitHub user
  account](../../docker-hub/repos/manage/builds/link-source.md#unlink-a-github-user-account)
  or
  [Unlink a Bitbucket user
  account](../../docker-hub/repos/manage/builds/link-source.md#unlink-a-bitbucket-user-account).

## Deactivate

After you complete the prerequisites, you can deactivate your account.

> [!WARNING]
>
> Deactivating your account is permanent and can't be undone. Make sure
> to back up any important data.

1. Sign in to [Docker Home](https://app.docker.com/login).
1. Select your avatar to open the drop-down menu.
1. Select **Account settings**.
1. Select **Deactivate**.
1. Select **Deactivate account**, then select again to confirm.

## Delete personal data

Deactivating your account does not delete your personal data. To request
personal data deletion, fill out Docker's
[Privacy request form](https://preferences.docker.com/).


---

# Manage a Docker account

*Sección: Accounts*

You can manage your Docker account in Docker Home, including administrative
and security settings.

> [!TIP]
>
> If your account is associated with an organization that enforces single
> sign-on (SSO), you may not have permissions to update your account settings.
> Contact your administrator to update your settings.

## Update account information

Account information is visible on your **Account settings** page. You can
update the following:

- Full name
- Company
- Location
- Website
- Gravatar email

To add or update your avatar using Gravatar:

1. Create a [Gravatar account](https://gravatar.com/).
1. Create your avatar.
1. Add your Gravatar email to your Docker account settings.

It may take some time for your avatar to update in Docker.

## Update email address

To update your email address:

1. Sign in to your [Docker account](https://app.docker.com/login).
1. Select your avatar in the top-right corner and select **Account settings**.
1. Select **Email**.
1. Enter your new email address and confirm your identity with your password.
   Select **Verify email**.
1. Go to the new Docker email and copy the 6-digit verification code.
1. Paste the verification code to complete updating your email.

Your verification session expires after 15 minutes.

> [!NOTE]
>
> Docker accounts only support one verified email address at a time, which
> is used for account notifications and security-related communications. You
> can't add multiple verified email addresses to your account.

## Change your password

Initiate your password reset through email:

1. Sign in to your [Docker account](https://app.docker.com/login).
1. Select your avatar in the top-right corner and select **Account settings**.
1. Select **Password**, then **Reset password**.
1. Docker sends you a password reset email with instructions to reset your
   password.

## Manage two-factor authentication

To update your two-factor authentication (2FA) settings:

1. Sign in to your [Docker account](https://app.docker.com/login).
1. Select your avatar in the top-right corner and select **Account settings**.
1. Select **2FA**.

For more information, see
[Enable two-factor authentication](../../security/authentication/2fa/index.md).

## Manage personal access tokens

To manage personal access tokens:

1. Sign in to your [Docker account](https://app.docker.com/login).
1. Select your avatar in the top-right corner and select **Account settings**.
1. Select **Personal access tokens**.

For more information, see
[Create and manage access tokens](../../security/access-tokens/personal-access-tokens.md).

## Manage connected accounts

If you signed up with Google or GitHub, that provider appears under
**Connected accounts**. Disconnecting it removes the OAuth connection. It
doesn't change your Docker ID, and it doesn't let you add a different sign-in
method. You can't connect both Google and GitHub to the same account.

To disconnect a connected account:

1. Sign in to your [Docker account](https://app.docker.com/login).
1. Select your avatar in the top-right corner and select **Account settings**.
1. Select **Connected accounts**.
1. Select **Disconnect** on your connected account.

To fully unlink your Docker account, you must also unlink Docker from Google
or GitHub. See Google or GitHub's documentation for more information:

- [Manage connections between your Google Account and
  third-parties](https://support.google.com/accounts/answer/13533235?hl=en)
- [Reviewing and revoking authorization of GitHub
  Apps](https://docs.github.com/en/apps/using-github-apps/reviewing-and-revoking-authorization-of-github-apps)

## Convert your account

For information on converting your account into an organization, see
[Convert an account into an
organization](../organization/setup/convert-account.md).

## Deactivate your account

For information on deactivating your account, see
[Deactivate a Docker account](deactivate-user-account.md).

## Next steps

- [Docker individual accounts overview](index.md)
- [Create a Docker account](create-account.md)
- [Enable two-factor authentication](../../security/authentication/2fa/index.md)


---

# Organization accounts

*Sección: Accounts*

Organization and company owners can manage members, control access, and enforce
security across their Docker environments. You perform these tasks in Docker
Home, which provides centralized observability, access management, and security
controls.

A Docker organization is a collection of teams and repositories under
centralized management. Organization administrators group members and
assign repository access at scale.

As an organization or company owner, you can:

- Create and manage companies and organizations
- Assign roles and permissions to members
- Group members into teams to manage access by project or role
- Set company-wide policies, including SCIM provisioning and security
  enforcement

For how individual, organization, and company accounts compare, see
[Accounts](../index.md). For individual accounts, see
[Docker individual accounts](../individual/index.md).

## Organization structure

The following diagram shows how organizations relate to teams and members.

![Diagram showing how teams and members relate within a Docker
organization](./images/org-structure.webp)

An organization includes owners, members, and optional teams. Organization
owners have full administrator access to manage members, roles, and teams.

### Team

Teams are optional and let you group members to assign repository permissions
collectively. Teams simplify permission management across projects
or functions.

### Member

A member is any Docker user added to an organization. Organization and company
owners can assign roles to members to define their level of access.

For details about each role and its permissions, see
[Roles and
permissions](../../security/roles-and-permissions/index.md).

For how companies relate to organizations, see
[Company structure](../company/index.md#company-structure).

## Next steps

Learn how to manage organizations in the following sections.

{{< grid >}}


---

# Activity logs

*Sección: Accounts*

{{< summary-bar feature_name="Activity logs" >}}

Activity logs display a chronological list of activities that occur at organization and repository levels. The activity log provides organization owners with a record of all
member activities.

With activity logs, owners can view and track:

 - What changes were made
 - The date when a change was made
 - Who initiated the change

For example, activity logs display activities such as the date when a repository was created or deleted, the member who created the repository, the name of the repository, and when there was a change to the privacy settings.

Owners can also see the activity logs for their repository if the repository is part of the organization subscribed to a Docker Business or Team subscription.

## Access activity logs

{{< tabs >}}
{{< tab name="Docker Home">}}

To view activity logs in Docker Home:

1. Sign in to [Docker Home](https://app.docker.com) and select your
organization.
1. Select **Activity**.

{{< /tab >}}
{{< tab name="API">}}

To view activity logs using the Docker Hub API, use the [Audit logs endpoints](https://docs.docker.com/reference/api/hub/latest/#tag/audit-logs).

{{< /tab >}}
{{< /tabs >}}

## Filter and customize activity logs

> [!IMPORTANT]
>
> Docker Home retains activity logs for 30 days. To retrieve
activities beyond 30 days, you must use the
[Docker Hub API](https://docs.docker.com/reference/api/hub/latest/#tag/audit-logs).

By default, the **Activity** tab displays all recorded events within
the last 30 days. To narrow your view, use the calendar to select a specific
date range. The log updates to show only the activities that occurred during
that period.

You can also filter by activity type. Use the **All Activities** drop-down to
focus on organization-level, repository-level, or billing-related events.
In Docker Hub, when viewing a repository, the **Activities** tab only shows
events for that repository.

After selecting a category—**Organization**, **Repository**, or **Billing**—use
the **All Actions** drop-down to refine the results even further by specific
event type.

> [!NOTE]
>
> Events triggered by Docker Support appear under the username **dockersupport**.

## Types of activity log events

Refer to the following section for a list of events and their descriptions:

### Organization events

| Event                                                          | Description                                   |
|:------------------------------------------------------------------|:------------------------------------------------|
| Team Created | Activities related to the creation of a team |
| Team Updated | Activities related to the modification of a team |
| Team Deleted | Activities related to the deletion of a team |
| Team Member Added | Details of the member added to your team |
| Team Member Removed | Details of the member removed from your team |
| Team Member Invited | Details of the member invited to your team |
| Organization Member Added | Details of the member added to your organization |
| Organization Member Removed | Details about the member removed from your organization |
| Member Role Changed | Details about the role changed for a member in your organization |
| Organization Created | Activities related to the creation of a new organization |
| Organization Settings Updated | Details related to the organization setting that was updated |
| Registry Access Management enabled | Activities related to enabling Registry Access Management |
| Registry Access Management disabled | Activities related to disabling Registry Access Management |
| Registry Access Management registry added | Activities related to the addition of a registry |
| Registry Access Management registry removed | Activities related to the removal of a registry |
| Registry Access Management registry updated | Details related to the registry that was updated |
| Single Sign-On domain added | Details of the single sign-on domain added to your organization |
| Single Sign-On domain removed | Details of the single sign-on domain removed from your organization |
| Single Sign-On domain verified | Details of the single sign-on domain verified for your organization |
| Access token created | Access token created in organization |
| Access token updated | Access token updated in organization |
| Access token deleted | Access token deleted in organization |
| Policy created | Details of adding a settings policy |
| Policy updated | Details of updating a settings policy |
| Policy deleted | Details of deleting a settings policy |
| Policy transferred | Details of transferring a settings policy to another owner |
| Create SSO Connection | Details of creating a new org/company SSO connection |
| Update SSO Connection | Details of updating an existing org/company SSO connection |
| Delete SSO Connection | Details of deleting an existing org/company SSO connection |
| Enforce SSO | Details of toggling enforcement on an existing org/company SSO connection |
| Enforce SCIM | Details of toggling SCIM on an existing org/company SSO connection |
| Refresh SCIM Token | Details of a SCIM token refresh on an existing org/company SSO connection |
| Change SSO Connection Type | Details of a connection type change on an existing org/company SSO connection |
| Toggle JIT provisioning | Details of a JIT toggle on an existing org/company SSO connection |

### Repository events

> [!NOTE]
>
> Event descriptions that include a user action can refer to a Docker username, personal access token (PAT) or organization access token (OAT). For example, if a user pushes a tag to a repository, the event would include the description: `<user-access-token>` pushed the tag to the repository.

| Event                                                          | Description                                   |
|:------------------------------------------------------------------|:------------------------------------------------|
| Repository Created | Activities related to the creation of a new repository |
| Repository Deleted | Activities related to the deletion of a repository |
| Repository Updated | Activities related to updating the description, full description, or status of a repository |
| Privacy Changed | Details related to the privacy policies that were updated |
| Tag Pushed | Activities related to the tags pushed |
| Tag Deleted | Activities related to the tags deleted |
| Categories Updated | Activities related to setting or updating categories of a repository |

### Billing events

| Event                                                          | Description                                   |
|:------------------------------------------------------------------|:------------------------------------------------|
| Plan Upgraded | Occurs when your organization’s billing plan is upgraded to a higher tier plan.|
| Plan Downgraded | Occurs when your organization’s billing plan is downgraded to a lower tier plan. |
| Seat Added | Occurs when a seat is added to your organization’s billing plan. |
| Seat Removed | Occurs when a seat is removed from your organization’s billing plan. |
| Billing Cycle Changed | Occurs when there is a change in the recurring interval that your organization is charged.|
| Plan Downgrade Canceled | Occurs when a scheduled plan downgrade for your organization is canceled.|
| Seat Removal Canceled | Occurs when a scheduled seat removal for an organization’s billing plan is canceled. |
| Plan Upgrade Requested | Occurs when a user in your organization requests a plan upgrade. |
| Plan Downgrade Requested | Occurs when a user in your organization requests a plan downgrade. |
| Seat Addition Requested | Occurs when a user in your organization requests an increase in the number of seats. |
| Seat Removal Requested | Occurs when a user in your organization requests a decrease in the number of seats. |
| Billing Cycle Change Requested | Occurs when a user in your organization requests a change in the billing cycle. |
| Plan Downgrade Cancellation Requested | Occurs when a user in your organization requests a cancellation of a scheduled plan downgrade. |
| Seat Removal Cancellation Requested | Occurs when a user in your organization requests a cancellation of a scheduled seat removal. |

### Offload events

> [!NOTE]
>
> Event descriptions show the Docker username of the actor and details about the lease.

| Event                                                          | Description                                   |
|:------------------------------------------------------------------|:------------------------------------------------|
| Offload Lease Start | Occurs when an Offload lease is started in your organization. |
| Offload Lease End | Occurs when an Offload lease is ended in your organization. |


---

# Insights

*Sección: Accounts*

{{< summary-bar feature_name="Insights" >}}

Insights helps administrators visualize and understand how Docker is used within
their organizations. With Insights, administrators can ensure their teams are
fully equipped to utilize Docker to its fullest potential, leading to improved
productivity and efficiency across the organization.

Key benefits include:

- Uniform working environment: Establish and maintain standardized
  configurations across teams.
- Best practices: Promote and enforce usage guidelines to ensure optimal
  performance.
- Increased visibility: Monitor and drive adoption of organizational
  configurations and policies.
- Optimized license use: Ensure that developers have access to advanced
  features provided by a Docker subscription.

## Prerequisites

To use Insights, you must meet the following requirements:

- [Docker Business subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminInsights)
- Administrators must [enforce sign-in](../../enterprise/security/enforce-sign-in/index.md)
  for users
- Your Account Executive must turn on Insights for your organization

## View Insights for organization users

To access Insights, contact your Account Executive to turn on the feature. Once enabled, access Insights using the
following steps:

1. Sign in to [Docker Home](https://app.docker.com/) and choose
   your organization.
2. Select **Insights**, then select a time period for the data you want to view.

> [!NOTE]
>
> Insights data is not real-time and is updated daily. At the top-right of the
> Insights page, view the **Last updated** date to understand when the data was
> last updated.

### Docker Desktop users

Track active Docker Desktop users in your domain, differentiated by license
status. This chart helps you understand the engagement levels within your
organization, providing insights into how many users are actively using Docker
Desktop. Note that users who opt out of analytics aren't included in the active
counts.

The chart contains the following data:

| Data                         | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| :--------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Active user                  | The number of users who have actively used Docker Desktop and either signed in with a Docker account that has a license in your organization or signed in to a Docker account with an email address from a domain associated with your organization. <br><br>Users who don’t sign in to an account associated with your organization are not represented in the data. To ensure users sign in with an account associated with your organization, you can [enforce sign-in](../../enterprise/security/enforce-sign-in/index.md). |
| Total organization members   | The number of users who have used Docker Desktop, regardless of their Insights activity.                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| Users opted out of analytics | The number of users who are members of your organization that have opted out of sending analytics. <br><br>When users opt out of sending analytics, you won't see any of their data in Insights. To ensure that the data includes all users, you can use [Settings Management](../../enterprise/security/hardened-desktop/settings-management/index.md) to set `analyticsEnabled` for all your users.                                                                                                                           |
| Active users (graph)         | The view over time for total active users.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

### Builds

Monitor development efficiency and the time your team invests in builds with
this chart. It provides a clear view of the build activity, helping you identify
patterns, optimize build times, and enhance overall development productivity.

The chart contains the following data:

| Data                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Average build per user | The average number of builds per active user. A build includes any time a user runs one of the following commands: <ul><li>`docker build`</li><li>`docker buildx b`</li><li>`docker buildx bake`</li><li>`docker buildx build`</li><li>`docker buildx f`</li><li>`docker builder b`</li><li>`docker builder bake`</li><li>`docker builder build`</li><li>`docker builder f`</li><li>`docker compose build`</li><li>`docker compose up --build`</li><li>`docker image build`</li></ul> |
| Average build time     | The average build time per build.                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| Build success rate     | The percentage of builds that were successful out of the total number of builds. A successful build includes any build that exits normally.                                                                                                                                                                                                                                                                                                                                           |
| Total builds (graph)   | The total number of builds separated into successful builds and failed builds. A successful build includes any build that exits normally. A failed build includes any build that exits abnormally.                                                                                                                                                                                                                                                                                    |

### Containers

View the total and average number of containers run by users with this chart. It
lets you gauge container usage across your organization, helping you understand
usage trends and manage resources effectively.

The chart contains the following data:

| Data                                   | Description                                                                                                                                                                |
| :------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Total containers run                   | The total number of containers run by active users. Containers run include those run using the Docker Desktop graphical user interface, `docker run`, or `docker compose`. |
| Average number of containers run       | The average number of containers run per active user.                                                                                                                      |
| Containers run by active users (graph) | The number of containers run over time by active users.                                                                                                                    |

### Docker Desktop usage

Explore Docker Desktop usage patterns with this chart to optimize your team's
workflows and ensure compatibility. It provides valuable insights into how
Docker Desktop is being utilized, enabling you to streamline processes and
improve efficiency.

The chart contains the following data:

| Data                              | Description                                                                                                                                                                                                                                                                       |
| :-------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Most used version                 | The most used version of Docker Desktop by users in your organization.                                                                                                                                                                                                            |
| Most used OS                      | The most used operating system by users.                                                                                                                                                                                                                                          |
| Versions by active users (graph)  | The number of active users using each version of Docker Desktop. <br><br>To learn more about each version and release dates, see the [Docker Desktop release notes](../../desktop/release-notes.md).                                                                           |
| Interface by active users (graph) | The number of active users grouped into the type of interface they used to interact with Docker Desktop. <br><br>A CLI user is any active user who has run a `docker` command. A GUI user is any active user who has interacted with the Docker Desktop graphical user interface. |

### Docker Hub images

Analyze image distribution activity with this chart and view the most utilized
Docker Hub images within your domain. This information helps you manage image
usage, ensuring that the most critical resources are readily available and
efficiently used.

> [!NOTE]
>
> Data for images is only for Docker Hub. Data for third-party
> registries and mirrors aren't included.

The chart contains the following data:

| Data                 | Description                                                                                                     |
| :------------------- | :-------------------------------------------------------------------------------------------------------------- |
| Total pulled images  | The total number of images pulled by users from Docker Hub.                                                     |
| Total pushed images  | The total number of images pushed by users to Docker Hub.                                                       |
| Top 10 pulled images | A list of the top 10 images pulled by users from Docker Hub and the number of times each image has been pulled. |

### Extensions

Monitor extension installation activity with this chart. It provides visibility
into the Docker Desktop extensions your teams are using, letting you track
adoption and identify popular tools that enhance productivity.

The chart contains the following data:

| Data                                           | Description                                                                                                                                      |
| :--------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------- |
| Percentage of org with extensions installed    | The percentage of users in your organization with at least one Docker Desktop extension installed.                                               |
| Top 5 extensions installed in the organization | A list of the top 5 Docker Desktop extensions installed by users in your organization and the number of users who have installed each extension. |

## Export Docker Desktop user data

You can export Docker Desktop user data as a CSV file:

1. Open [Docker Home](https://app.docker.com) and select your organization from the top-left account drop-down.
1. Select **Docker Desktop**, then **Desktop insights**.
1. Choose a timeframe for your insights data: **1 Week**, **1 Month**, or
   **3 Months**.
1. Select **Export** and choose **Docker Desktop users** from the drop-down.

Your export will automatically download. Open the file to view
the export data.

### Understanding export data

A Docker Desktop user export file contains the following data points:

- Name: User's name
- Username: User's Docker ID
- Email: User's email address associated with their Docker ID
- Type: User type
- Role: User [role](/manuals/security/roles-and-permissions.md)
- Teams: Team(s) within your organization the user is a
  member of
- Date Joined: The date the user joined your organization
- Last Logged-In Date: The last date the user logged into Docker using
  their web browser (this includes Docker Hub and Docker Home)
- Docker Desktop Version: The version of Docker Desktop the user has
  installed
- Last Seen Date: The last date the user used the Docker Desktop application
- Opted Out Analytics: Whether the user has opted out of the
  [Send usage statistics](../../enterprise/security/hardened-desktop/settings-management/settings-reference.md#send-usage-statistics) setting in Docker Desktop

## Troubleshoot Insights

If you’re experiencing issues with data in Insights, consider the following
solutions to resolve common problems:

- Update users to the latest version of Docker Desktop.

  Data is not shown for users using versions 4.16 or lower of Docker Desktop.
  In addition, older versions may not provide all data. Ensure all users have
  installed the latest version of Docker Desktop.

- Turn on **Send usage statistics** in Docker Desktop for all your users.

  If users have opted out of sending usage statistics for Docker Desktop, then
  their usage data will not be a part of Insights. To manage the setting at
  scale for all your users, you can use [Settings
  Management](../../enterprise/security/hardened-desktop/settings-management/index.md) and turn on the
  `analyticsEnabled` setting.

- Ensure users use Docker Desktop and aren't using the standalone
  version of Docker Engine.

  Only Docker Desktop can provide data for Insights. If a user installs Docker
  Engine outside of Docker Desktop, Docker Engine won't provide
  data for that user.

- Make sure users sign in to an account associated with your
  organization.

  Users who don’t sign in to an account associated with your organization are
  not represented in the data. To ensure users sign in with an account
  associated with your organization, you can [enforce
  sign-in](../../enterprise/security/enforce-sign-in/index.md).


---

# Manage your organization

*Sección: Accounts*

As an organization owner, you manage your organization's membership, access,
product usage, and settings. You can invite members, group them into teams,
assign or revoke licenses and seats, change access to Docker products, update
organization information, and deactivate the organization.

## Managing your organization

You manage your organization from [Docker Home](https://app.docker.com) and
must be assigned the
[organization owner role](../../../security/roles-and-permissions/index.md).

## Seats and licenses

Seats and licenses both control access, but they apply to different kinds of
plans. The following table summarizes the difference.

| Entitlement | What it grants                                          | Applies to                                       | Managed from |
| ----------- | ------------------------------------------------------- | ------------------------------------------------ | ------------ |
| Seat        | Membership in your Docker Team or Business subscription | Docker Core subscription                         | Billing      |
| License     | Access to a specific product or add-on                  | AI Governance, Docker Offload, and other add-ons | Members      |

For details, see [Seats](manage-seats.md)
and [License assignment](manage-licenses.md).

## Next steps

Explore the following sections to manage your organization.

{{< grid >}}


---

# Deactivate an organization

*Sección: Accounts*

{{< summary-bar feature_name="General admin" >}}

Learn how to deactivate a Docker organization, including required prerequisite
steps. For information about deactivating user accounts, see
[Deactivate a Docker
account](../../individual/deactivate-user-account.md).

> [!WARNING]
>
> All Docker products and services that use this organization are
> inaccessible after you deactivate it. Your individual Docker account
> remains active.

## Prerequisites

You must complete all the following steps before you can deactivate your
organization:

- Download any images and tags you want to keep. Use `docker pull -a <image>`
  to pull all tags, or `docker pull <image>:<tag>` to pull a specific tag.
- If you have an active Docker subscription, [downgrade it to a basic
  organization
  account](../../../subscription-billing/plans/docker.md#cancel-a-docker-plan).
- Remove all other members within the organization.
- Unlink your [GitHub and Bitbucket
  accounts](../../../docker-hub/repos/manage/builds/link-source.md#unlink-a-github-user-account).
- For Business organizations, [remove your SSO
  connection](../../../security/authentication/single-sign-on/manage.md#delete-a-connection).

## Deactivate

> [!WARNING]
>
> Deactivating an organization is permanent and can't be undone. Make sure
> you've gathered all the data you need before you deactivate it.

1. Sign in to [Docker Home](https://app.docker.com) and select the organization
   you want to deactivate.
1. Select **Organization settings**, then **Deactivate**. If the **Deactivate**
   button is unavailable, confirm you've completed all
   [Prerequisites](#prerequisites).
1. Enter the organization name to confirm deactivation.
1. Select **Deactivate organization**.


---

# Change general organization information

*Sección: Accounts*

Learn how to update your organization information.

## Update organization information

General organization information appears on your organization landing page.

This information includes:

- Organization Name
- Company
- Location
- Website
- Gravatar email: To add an avatar to your Docker account, create a [Gravatar account](https://gravatar.com/) and upload an avatar. Next, add your Gravatar email to your Docker account settings. It may take some time for your avatar to update in Docker.

To edit this information:

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization from the top-left account drop-down.
1. Select **Organization settings**.
1. Enter or update your organization’s details, then select **Save**.

## Next steps

After configuring your organization information, you can:

- [Configure single sign-on (SSO)](../../../security/authentication/single-sign-on/connect.md)
- [Set up SCIM provisioning](../../../security/provisioning/scim/index.md)
- [Manage domains](../../../security/provisioning/domain-management.md)
- [Create a company](../../company/new-company.md)


---

# Create and manage a team

*Sección: Accounts*

{{< summary-bar feature_name="Admin orgs" >}}

You can create teams for your organization in Docker Home or Docker Hub,
and configure team repository access in Docker Hub.

A team is a group of Docker users that belong to an organization. An
organization can have multiple teams. An organization owner can create new
teams and add members to an existing team using their Docker ID or email
address. Members aren't required to be part of a team to be associated with an
organization.

The organization owner can add additional organization owners to help them
manage users, teams, and repositories in the organization by assigning them
the owner role.

## What is an organization owner?

An organization owner is an administrator who has the following permissions:

- Manage repositories and add team members to the organization
- Access private repositories, all teams, billing information, and
  organization settings
- Specify [permissions](#permissions-reference) for each team in the
  organization
- Enable [SSO](../../../security/authentication/single-sign-on/index.md) for the
  organization

When SSO is enabled for your organization, the organization owner can
also manage users. Docker can auto-provision Docker IDs for new end-users or
users who'd like to have a separate Docker ID for company use through SSO
enforcement.

Organization owners can add others with the owner role to help them
manage users, teams, and repositories in the organization.

For more information on roles, see
[Roles and permissions](/manuals/security/roles-and-permissions.md).

## Create a team

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization.
1. Select **Teams**.
1. Select **Create team**.
1. Provide the team's information, then select **Create**.

## Set team repository permissions

You must create a team before you are able to configure repository permissions.
For more details, see [Create a team](#create-a-team).

To set team repository permissions:

1. Sign in to [Docker Hub](https://hub.docker.com).
1. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

1. Select a repository.

   The **General** page for the repository appears.

1. Select the **Permissions** tab.
1. Add, modify, or remove a team's repository permissions.
   - Add: Specify the **Team**, select the **Permission**, and then select **Add**.
   - Modify: Specify the new permission next to the team.
   - Remove: Select the **Remove permission** icon next to the team.

### Permissions reference

- `Read-only` access lets users view, search, and pull a private repository
  in the same way as they can a public repository.
- `Read & Write` access lets users pull, push, and view a repository. In
  addition, it lets users view, cancel, retry or trigger builds.
- `Admin` access lets users pull, push, view, edit, and delete a
  repository. You can also edit build settings and update the repository’s
  description, collaborator permissions, public/private visibility, and delete.

Permissions are cumulative. For example, if you have "Read & Write" permissions,
you automatically have "Read-only" permissions.

The following table shows what each permission level allows users to do:

|             Action              | Read-only | Read & Write | Admin |
| :-----------------------------: | :-------: | :----------: | :---: |
|        Pull a Repository        |    ✅     |      ✅      |  ✅   |
|        View a Repository        |    ✅     |      ✅      |  ✅   |
|        Push a Repository        |    ❌     |      ✅      |  ✅   |
|        Edit a Repository        |    ❌     |      ❌      |  ✅   |
|       Delete a Repository       |    ❌     |      ❌      |  ✅   |
| Update a Repository Description |    ❌     |      ❌      |  ✅   |
|           View Builds           |    ✅     |      ✅      |  ✅   |
|          Cancel Builds          |    ❌     |      ✅      |  ✅   |
|          Retry Builds           |    ❌     |      ✅      |  ✅   |
|         Trigger Builds          |    ❌     |      ✅      |  ✅   |
|       Edit Build Settings       |    ❌     |      ❌      |  ✅   |

> [!NOTE]
>
> A user who hasn't verified their email address only has `Read-only` access to
> the repository, regardless of the rights their team membership has given them.

## Delete a team

Organization owners can delete a team. When you remove a team from your
organization, this action revokes member access to the team's permitted
resources. It won't remove users from other teams that they belong to, and it
won't delete any resources.

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Teams**.
1. Select the **Actions** icon next to the name of the team you want to delete.
1. Select **Delete team**.
1. Review the confirmation message, then select **Delete**.

## More resources

- [Video: Docker Teams](https://youtu.be/WKlT1O-4Du8?feature=shared&t=348)
- [Video: Roles, teams, and repositories](https://youtu.be/WKlT1O-4Du8?feature=shared&t=435)


---

# Manage license assignment

*Sección: Accounts*

Licenses let you choose which organization members can access supported Docker
products. Organization owners can manage active licenses for their members, or
configure licenses to assign automatically when members access supported Docker
products.

> [!TIP]
> To learn more about product licenses, Docker Core seats, and other Docker
> add-ons, see [Docker plans](../../../subscription-billing/plans/index.md),
> or
> <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_admin_licenses" class="link" rel="noopener">contact sales</a>
> to purchase licenses.

## Licenses and invites

When you invite someone, you can select a product license to assign when they
accept. Docker doesn't reserve or deduct the license at invite time; assignment
happens on acceptance:

- If a license is available when they accept, Docker assigns it to them and the
  number of available licenses decreases by one.
- If no licenses remain when they accept, they still join your organization,
  but without a license.

> [!NOTE]
> Docker doesn't notify you or the invitee when a selected license is
> unavailable at acceptance.

Licenses aren't reserved for pending invitations, so they must still be
available when each invitee accepts. Monitor availability on the Members page
while invitations are pending.

### Select licenses when inviting

Selecting licenses when you invite is an alternative to assigning one manually
after they join, or, where available, relying on automatic license assignment
the first time they use a supported product. To select licenses when you invite
a member:

1. Sign in to [Docker Home](https://app.docker.com), then choose your
   organization.
1. Select **Members** from the left navigation, then select **Invite**.
1. Select **Emails or usernames**.
1. Enter the email addresses or Docker IDs of the people you want to invite,
   then assign their
   [role](../../../security/roles-and-permissions/index.md).
1. Under **Licenses (optional)**, select one or more licenses that are
   available to your organization.
1. Select **Invite** to send the invite.

For more about sending, resending, and removing invitations, including CSV
file limits, see
[Manage organization members](members.md).

### Accept invites

A user can accept from the link in their invitation email or from their
**Notifications Center**. If the selected license is available, Docker assigns
it automatically upon acceptance.

## Automatic license assignment

Automatic license assignment gives members a product license when they use a
supported product for the first time. Automatic license assignment is available
for AI Governance licenses. Only organizations that purchase AI Governance can
set up auto-assignment for Docker Core as well.

- When you purchase AI Governance, signing in to
  [Docker Sandboxes](../../../ai/sandboxes/index.md) with the `sbx login`
  command automatically provisions AI Governance licenses on a first-come,
  first-served basis.
- Similarly, signing in to Docker Desktop automatically provisions Docker Core
  for AI Governance license-holding organizations that have available Docker
  Core seats.
- Licenses are assigned until exhausted.
  - Once the available licenses are exhausted, automatic license assignment
    stops until you purchase more licenses or revoke assigned licenses.
  - Members can still use Docker Sandboxes or Docker Desktop, but organization
    policies for those products won't affect their usage.

AI Governance licenses include single sign-on (SSO) and provisioning features
regardless of your Docker Core subscription. Automatic license assignment
requires
[setting up SSO](../../../security/authentication/single-sign-on/connect.md), then
[provisioning](../../../security/provisioning/index.md) with System
for Cross-domain Identity Management (SCIM) or Just-in-Time (JIT).

## Manage licenses

The **Members** page lets you track the number of available licenses for your
organization and who holds a license. You can also assign or revoke licenses
from this page.

To manage licenses for your organization:

1. Sign in to [Docker Home](https://app.docker.com), then choose your
   organization.
1. Select **Members** from the left navigation.
1. Select the action menu at the end of the row to assign or revoke an active
   license.
1. Optional. To bulk assign or revoke licenses, choose the members you want to
   bulk manage, then select the **Bulk actions** menu.
1. Optional. To manage automatic license assignment, turn off or turn on with
   the **Automatically assign licenses** toggle.

## Next steps

Explore Docker Core add-ons and products that need licenses:

- [Docker plans](../../../subscription-billing/plans/index.md) to learn about different
  add-ons
- [Manage seats](manage-seats.md) to add more
  seats to your Docker Core subscription
- [AI Governance plan](../../../subscription-billing/plans/ai-governance.md) to learn
  about AI Governance license usage and billing
- [Docker Offload](../../../offload/about.md) to let your developers offload
  building and running containers to the cloud


---

# Manage usage and access for Docker products

*Sección: Accounts*

{{< summary-bar feature_name="Admin orgs" >}}

Use this page to learn how to control and monitor product access and usage
for your organization's members. If you're looking for setup and
configuration instructions, see each product's manual under
[Next steps](#next-steps).

## Control access for your organization

Organization members can access Docker products that your organization is
subscribed to by default. When signed in as an organization owner, you can
use the following procedures to control access for all members.

### Docker Desktop access

To manage Docker Desktop access:

1. [Enforce sign-in](../../../enterprise/security/enforce-sign-in/index.md).
1. Manage members [manually](members.md) or use
   [provisioning](../../../security/provisioning/index.md).

With sign-in enforced, only users who are a member of your organization can
use Docker Desktop after signing in.

### Docker Hub access

To manage Docker Hub access:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization, then select **Docker Desktop**.
1. Select **Registry Access** to configure
   [Registry Access Management](../../../enterprise/security/hardened-desktop/registry-access-management.md).
1. Select **Image Access** to control
   [Image Access Management](../../../enterprise/security/hardened-desktop/image-access-management.md).

### Docker Build Cloud access

To initially set up and configure Docker Build Cloud, sign in to
[Docker Build Cloud](https://app.docker.com/build) and follow the
on-screen instructions.

To manage Docker Build Cloud access:

1. Sign in to [Docker Home](https://app.docker.com/), then select
   [Docker Build Cloud](http://app.docker.com/build).
1. Select **Account settings**.
1. Select **Lock access to Docker Build Account**.

### Docker Scout access

To initially set up and configure Docker Scout, sign in to
[Docker Scout](https://scout.docker.com/) and follow the on-screen
instructions.

To manage Docker Scout access:

1. Sign in to [Docker Home](https://app.docker.com/), then select
   [Docker Scout](https://scout.docker.com/).
1. Select your organization, then **Settings**.
1. To manage what repositories are enabled for Docker Scout analysis, select
   **Repository settings**. For more information, see
   [repository settings](../../../scout/explore/dashboard.md#repository-settings).
1. To manage access to Docker Scout for use on local images with Docker
   Desktop, use
   [Settings Management](../../../enterprise/security/hardened-desktop/settings-management/index.md)
   and set `sbomIndexing` to `false` to disable, or to `true` to enable.

### Testcontainers Cloud access

To initially set up and configure Testcontainers Cloud, sign in to
[Testcontainers Cloud](https://app.testcontainers.cloud/) and follow the
on-screen instructions.

To manage access to Testcontainers Cloud:

1. Sign in to the [Testcontainers Cloud](https://app.testcontainers.cloud/),
   then select the menu icon.
1. Select **Account**, then **Settings**.
1. Choose **Lock access to Testcontainers Cloud**.

### Docker Offload access

> [!NOTE]
>
> Docker Offload isn't included in the core Docker subscription plans. To
> make Docker Offload available, you must
> [contact sales](https://www.docker.com/products/docker-offload/) and
> subscribe.

To manage Docker Offload access for your organization, use [Settings
Management](../../../enterprise/security/hardened-desktop/settings-management/index.md):

1. Sign in to [Docker Home](https://app.docker.com/), then select **Docker
   Desktop**.
1. Select **Settings Management**.
1. Configure the **Enable Docker Offload** setting to control whether
   Docker Offload features are available in Docker Desktop. You can
   configure this setting in five states:
   - **Always enabled**: Docker Offload is always enabled and users cannot
     disable it. The Offload toggle is always visible in the Docker Desktop
     header. Recommended for VDI environments where local Docker execution
     is not possible.
   - **Enabled**: Docker Offload is enabled by default but users can
     disable it in Docker Desktop settings. Suitable for hybrid
     environments.
   - **Disabled**: Docker Offload is disabled by default but users can
     enable it in Docker Desktop settings.
   - **Always disabled**: Docker Offload is disabled and users cannot
     enable it. The option is visible but locked. Use when Docker Offload
     is not approved for organizational use.
   - **User defined**: No enforced default. Users choose whether to enable
     or disable Docker Offload in their Docker Desktop settings.
1. Select **Save**.

For more details on Settings Management, see the [Settings
reference](../../../enterprise/security/hardened-desktop/settings-management/settings-reference.md#enable-docker-offload).

## Monitor product usage for your organization

You can monitor usage for Docker products across your organization. Use the
following table to learn where you can monitor organization usage:

| Product              | Monitor usage                                                                                                                                                                                    |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Docker Desktop       | From [Docker Home](https://app.docker.com/), view the [**Insights**](../insights.md) page.                                                                                                    |
| Docker Hub           | From Docker Hub, view the [**Usage** page](https://hub.docker.com/usage).                                                                                                                        |
| Docker Build Cloud   | From [Docker Build Cloud](http://app.docker.com/build), view the **Build minutes** page.                                                                                                         |
| Docker Scout         | From [Docker Home](https://app.docker.com/), select **Go to Scout** to view the [**Repository settings** page](https://scout.docker.com/settings/repos).                                         |
| Testcontainers Cloud | From [Docker Home](https://app.docker.com/), select **Go to Testcontainers Cloud**, then select the menu icon. Go to the [**Billing** page](https://app.testcontainers.cloud/dashboard/billing). |
| Docker Offload       | From [Docker Home](https://app.docker.com/), select **Offload**, then **Offload activity**. See [Docker Offload usage and billing](../../../offload/usage.md) for more details.                  |

If your usage or seat count exceeds your subscription amount, you can
[add seats](manage-seats.md) or [view available Docker plans](../../../subscription-billing/plans/index.md) to meet your needs.

## Next steps

For more detailed information about each product, including how to set up
and configure them, see the following manuals:

- [Docker Desktop](../../../desktop/index.md)
- [Docker Hub](../../../docker-hub/index.md)
- [Docker Build Cloud](../../../build-cloud/index.md)
- [Docker Scout](../../../scout/index.md)
- [Testcontainers Cloud](https://testcontainers.com/cloud/docs/#getting-started)
- [Docker Offload](../../../offload/index.md)


---

# Manage subscription seats

*Sección: Accounts*

You can add or remove seats from your Docker Team or Business subscription at any time to accommodate team changes. When you add seats mid-billing cycle, you're charged a prorated amount for the additional seats.

> [!IMPORTANT]
> If you have a sales-assisted Docker Business subscription,
> contact your account manager to add or remove seats from your subscription.

## Add seats to your subscription

To add seats:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Billing**.
1. Select the action menu from the **Active Plans** tile, then choose **Add seats**.
1. Follow the on-screen instructions to complete adding seats.
   - You can't use pay by invoice for purchasing additional seats.
   - You must use a card or US bank account.

You can add more members to your organization. For more information, see [Manage organization members](members.md).

## Volume pricing

Docker offers volume pricing for Docker Business subscriptions starting at 25 seats. Contact the <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_volume_pricing" class="link" rel="noopener">Docker Sales Team</a> for more information.

## Remove seats from your subscription

You can remove seats from your Team or Business subscription at any time. To remove seats:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Billing**.
1. Select the action menu, then choose **Remove seats**.
1. Follow the on-screen instructions to complete removing seats.

Changes apply to your next billing cycle, and unused portions aren't refundable.

For example, if you're billed on the 8th of every month for 10 seats and remove 2 seats on the 15th, the 2 seats remain available until your next billing cycle. Your payment for 8 seats begins on the next billing cycle.

> [!TIP]
> You can cancel the removal of seats before your next billing cycle. To do so, select **Cancel change**.


---

# Invite and manage organization members

*Sección: Accounts*

Learn how to invite and manage members for your organization in Docker Home.

## Invite members

Owners can invite new members using a Docker ID, email address, or a CSV file
of email addresses. If an invitee doesn't have a Docker account, they must
create one and verify their email address before they can accept. Pending
invitations occupy a seat.

When you invite members, you assign them a role. See
[Roles and permissions][roles-permissions] for details about the access
permissions for each role.

You can also select one or more product licenses for an invitee. Docker
assigns available licenses when they accept. Unlike a seat, licenses aren't
deducted from your organization's available licenses until the invitee
accepts. See [Licenses and invites][licenses-and-invites].

{{< tabs >}}
{{< tab name="Email or username" >}}

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization from the top-left account drop-down.
1. Select **Members**, then **Invite**.
1. Select **Emails or usernames**.
1. Follow the on-screen instructions to invite members. Invite a maximum of
   1000 members and separate multiple entries by comma, semicolon, or space.

{{< /tab >}}
{{< tab name="CSV upload" >}}

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization from the top-left account drop-down. Select **Members** >
   **Invite** > **CSV upload**.
1. Optional. Select **Download the template CSV file** to download an example
   CSV file. The following is an example of the contents of a valid CSV file:

   ```text
   email
   docker.user-0@example.com
   docker.user-1@example.com
   ```

   CSV file requirements:
   - The file must contain a header row with at least one heading named
     `email`. Additional columns are allowed and are ignored in the import.
   - The file must contain a maximum of 1000 email addresses (rows). To invite
     more than 1000 members, create multiple CSV files and complete this
     procedure for each file.

1. Create a new CSV file or export a CSV file from another application.
   - To export a CSV file from another application, see that application's
     documentation.
   - To create a new CSV file, open a new file in a text editor, type `email`
     on the first line, type one email address per line on the following
     lines, then save the file with a `.csv` extension.

1. Select **Browse files** and select your CSV file, or drag and drop the CSV
   file into the **Select a CSV file to upload** box. You can select only one
   CSV file at a time.
1. After the CSV file uploads, select **Review** to identify invalid email
   addresses, invitees with a pending invitation, members already in the
   organization, or duplicate email addresses in the same CSV file.
1. Follow the on-screen instructions to invite members.

{{< /tab >}}
{{< /tabs >}}

You can also bulk invite members with the Docker Hub API. For more
information, see the [Bulk create invites][bulk-invites] API endpoint.

Pending invitations appear in the Members table. Invitees can accept or
decline from the invitation email or the **Notifications Center**.

## Accept an invitation

To accept from the invitation email:

1. Open the Docker invitation email and select the link to Docker Hub.
1. The Docker account creation page opens. If you already have an account,
   select **Already have an account? Sign in**. If you don't have an account,
   create one using the same email address that received the invitation.
1. Optional. If you created a new account, open your email inbox and verify
   your email address using the Docker verification email.
1. After you sign in to Docker Hub, select **My Hub** from the top-level
   navigation menu.
1. Select **Accept** on your invitation.

To accept from the **Notifications Center**:

1. Sign in to [Docker Hub](https://hub.docker.com/) or
   [Docker Home](https://app.docker.com/).
1. Open the **Notifications Center** in the header.
1. Select **Accept** on the invitation.

After you accept the invitation, you are a member of the organization.

Invitation email links expire after 14 days. If your link has expired, you
can still accept from the **Notifications Center**.

## Manage invitations

After inviting members, you can resend or remove invitations. Each invitee
occupies one seat. If the number of email addresses in your CSV file exceeds
the number of available seats, you can't invite more members.

> [!TIP]
>
> Need more seats for your organization?
> [Add seats](manage-seats.md) to your
> subscription, or see [Docker pricing][docker-pricing] for plan options.

### Resend an invitation

You can resend individual or bulk invitations from Docker Home.

To resend an individual invitation:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Members**.
1. Select the **Actions** menu next to the invitee, then **Resend**.
1. Select **Invite** to confirm.

To bulk resend invitations:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Members**.
1. Use the checkboxes next to **Usernames** to select invitees.
1. Select **Resend invites**.
1. Select **Resend** to confirm.

### Remove an invitation

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Members**.
1. Select the **Actions** menu next to the invitee, then **Remove invitee**.
1. Select **Remove** to confirm.

## Manage members on a team

Use Docker Hub or Docker Home to add or remove team members. Organization
owners can add a member to one or more teams within an organization.

### Add a member to a team

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Teams**.
1. Select the team name.
1. Select **Add member**. Search for the member by email address or username.

An invitee must accept the invitation before you can add them to a team.

### Remove members from teams

If your organization uses single sign-on (SSO) with
[SCIM](../../../security/provisioning/scim/index.md) enabled,
remove members from your identity provider (IdP). That removes them from
Docker automatically. If SCIM is disabled, remove members manually in Docker
using the following steps.

Removing a member from a team revokes their access to that team's permitted
resources.

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Teams**, then select the team.
1. Select the **X** next to the member's name to remove them from the team.
1. When prompted, select **Remove** to confirm.

### Update a member role

Organization owners can manage
[roles](../../../security/roles-and-permissions/index.md) within
an organization. If an organization is part of a company, the company owner
can also manage that organization's roles. If SSO is enabled, you can use
[SCIM for role mapping][scim-role-mapping].

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Members**.
1. Find the username of the member whose role you want to edit. Select the
   **Actions** menu, then **Edit role**.

If you're the only owner of an organization and you want to edit your role,
assign a new owner first so you can change your own role.

### Remove a member from the organization

Organization owners can remove members from the organization. Removing a
member revokes their access to the organization's resources and teams.

If your organization uses SSO with
[SCIM](../../../security/provisioning/scim/index.md) enabled,
remove members from your IdP instead.

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Members**.
1. Find the username of the member you want to remove. Select the
   **Actions** menu, then **Remove member**.
1. Select **Remove** to confirm.

## Export a member list CSV

Organization owners can export a CSV file of all members. Docker generates
the file asynchronously and emails it to the owner when it's ready.

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
1. Select **Members**.
1. Select the **Download** icon to start the export.
1. Open the email from Docker and select the link to download the CSV file.

   {{< accordion title="CSV fields" >}}
   - Name: The member's name
   - Username: The member's Docker ID
   - Email: The member's email address
   - Type: Whether the entry is a member or an invitee
   - Role: The member's role in the organization
   - Teams: Teams the member belongs to
   - Date Joined: When the member joined the organization

   {{< /accordion >}}

## Next steps

After you invite and manage members, explore these related topics:

- [Manage subscription seats](manage-seats.md) to add seats for pending
  invitations
- [Manage license assignment](manage-licenses.md) to control product access
- [Create and manage a team](manage-a-team.md) to group members and set
  repository permissions
- [Roles and permissions][roles-permissions] for role definitions
- [SCIM provisioning][scim-provisioning] to automate member and role
  management

[roles-permissions]: ../../../security/roles-and-permissions/index.md
[licenses-and-invites]: manage-licenses.md#licenses-and-invites
[bulk-invites]: /reference/api/hub/latest/#tag/invites/paths/~1v2~1invites~1bulk/post
[docker-pricing]: https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminMembers
[scim-role-mapping]: ../../../security/provisioning/scim/index.md
[scim-provisioning]: ../../../security/provisioning/scim/index.md


---

# Set up your organization

*Sección: Accounts*

Before you manage members and access, set up your Docker organization. You can
create an organization, onboard and secure it, or convert an existing user
account into an organization.

## Setting up your organization

You set up your organization from [Docker Home](https://app.docker.com) and
must be assigned the
[organization owner role](../../../security/roles-and-permissions/index.md).
Setting up an organization happens in broad phases:

1. You can create a new organization, or convert an existing user account
   into one. Choose the option that fits how you already use Docker. You
   don't need both.
1. After creating your organization, you must onboard it by inviting members,
   securing authentication, and enforcing sign-in. These steps build on each
   other, so follow them in order.

## Next steps

Explore the following sections to set up your organization.

{{< grid >}}


---

# Convert an account into an organization

*Sección: Accounts*

{{< summary-bar feature_name="Admin orgs" >}}

Learn how to convert an existing user account into an organization. This is
useful if you need multiple users to access your account and the repositories
it’s connected to. Converting it to an organization gives you better control
over permissions for these users through
[teams](../manage/manage-a-team.md) and
[roles](../../../security/roles-and-permissions/index.md).

When you convert a user account to an organization, the account is migrated to
a Docker Team subscription by default.

## Prerequisites

Before you convert a user account to an organization, ensure that you meet the following requirements:

- The user account that you want to convert must not be a member of a company or any teams or organizations. You must remove the account from all teams, organizations, or the company.

  To do this:
  1. Navigate to **My Hub** and then select the organization you need to leave.
  1. Find your username in the **Members** tab.
  1. Select the **More options** menu and then select **Leave organization**.

  If the user account is the sole owner of any organization or company, assign another user the owner role and then remove yourself from the organization or company.

- You must have a separate Docker ID ready to assign as the owner of the organization during conversion.

  If you want to convert your user account into an organization account and you don't have any other user accounts, you need to create a new user account to assign it as the owner of the new organization. With the owner role assigned, this user account has full administrative access to configure and manage the organization. You can assign more users the owner role after the conversion.

## What happens when you convert your account

The following happens when you convert your account into
an organization:

- This process removes the email address for the account. Notifications are
  instead sent to organization owners. You'll be able to reuse the
  removed email address for another account after converting.
- The current subscription will automatically cancel and your new subscription
  will start.
- Repository namespaces and names won't change, but converting your account
  removes any repository collaborators. Once you convert the account, you'll need
  to add repository collaborators as team members.
- Existing automated builds appear as if they were set up by the first owner
  added to the organization.
- The user account that you add as the first owner will have full
  administrative access to configure and manage the organization.
- To transfer a user's personal access tokens (PATs) to your converted
  organization, you must designate the user as an organization owner. This will
  ensure any PATs associated with the user's account are transferred to the
  organization owner.

## Convert an account into an organization

> [!IMPORTANT]
>
> Converting an account into an organization is permanent. Back up any data
> or settings you want to retain.

1. Sign in to [Docker Home](https://app.docker.com/).
1. Select your avatar in the top-right corner to open the drop-down.
1. From **Account settings**, select **Convert**.
1. Review the warning displayed about converting a user account. This action
   cannot be undone and has considerable implications for your assets and the
   account.
1. Enter a **Username of new owner** to set an organization owner. The new
   Docker ID you specify becomes the organization’s owner. You cannot use the
   same Docker ID as the account you are trying to convert. The Docker ID is
   case-sensitive.
1. Select **Confirm**. The new owner receives a notification email. Use that
   owner account to sign in and manage the new organization.


---

# Onboard your organization

*Sección: Accounts*

{{< summary-bar feature_name="Admin orgs" >}}

Learn how to onboard your organization.

Onboarding your organization includes:

- Identifying users to help you allocate your subscription seats
- Invite members and owners to your organization
- Secure authentication and authorization for your organization
- Enforce sign-in for Docker Desktop to ensure security best practices

These actions help administrators gain visibility into user activity and
enforce security settings. Organization members also receive increased pull
limits and other benefits when they are signed in.

## Prerequisites

Before you start onboarding your organization, ensure you:

- Have a Docker Team or Business subscription. For more details, see
  [Docker subscriptions and features](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminOnboard).

  > [!NOTE]
  >
  > When purchasing a self-serve subscription, the on-screen instructions
  > guide you through creating an organization. If you have purchased a
  > subscription through Docker Sales and you have not yet created an
  > organization, see [Create an organization](orgs.md).

- Familiarize yourself with Docker concepts and terminology in
  the [administration overview](../../index.md).

## Onboard with guided setup

Docker Home has a guided setup to help you
onboard your organization. The guided setup's steps consist of basic onboarding
tasks. If you want to onboard outside of the guided setup,
see [Recommended onboarding steps](onboard.md#recommended-onboarding-steps).

To onboard using the guided setup,
navigate to [Docker Home](https://app.docker.com) and
select **Guided setup** in the left-hand navigation.

The guided setup walks you through the following onboarding steps:

- **Invite your team**: Invite owners and members.
- **Manage user access**: Add and verify a domain, manage users with SSO, and
  enforce Docker Desktop sign-in.
- **Docker Desktop security**: Configure image access management, registry
  access management, and settings management.

## Recommended onboarding steps

### Step one: Identify your Docker users

Identifying your users helps you allocate seats efficiently and ensures they
receive your Docker subscription benefits.

1. Identify the Docker users in your organization.
   - If your organization uses device management software, like MDM or Jamf,
     you can use the device management software to help identify Docker users.
     See your device management software's documentation for details. You can
     identify Docker users by checking if Docker Desktop is installed at the
     following location on each user's machine:
     - Mac: `/Applications/Docker.app`
     - Windows: `C:\Program Files\Docker\Docker`(all-user installation) or `%LOCALAPPDATA%\Programs\DockerDesktop` (per-user installation (Beta))
     - Linux: `/opt/docker-desktop`
   - If your organization doesn't use device management software or your
     users haven't installed Docker Desktop yet, you can survey your users to
     identify who is using Docker Desktop.
1. Ask users to update their Docker account's email address to one associated
   with your organization's domain, or create a new account with that email.
   - To update an account's email address, instruct your users to sign in
     to [Docker Hub](https://hub.docker.com), and update the email address to
     their email address in your organization's domain.
   - To create a new account, instruct your users to
     [sign up](https://hub.docker.com/signup) using their email address associated
     with your organization's domain. Ensure your users verify their email address.
1. Identify Docker accounts associated with your organization's domain:
   - Ask your Docker sales representative or
     <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_org_onboarding" class="link" rel="noopener">contact sales</a> to get a list
     of Docker accounts that use an email address in your organization's domain.

### Step two: Invite owners

Owners can help you onboard and manage your organization.

When you create an organization, you are the only owner. It is optional to
add additional owners.

To add an owner, invite a user and assign them the owner role. For more
details, see [Invite members](../manage/members.md) and
[Roles and permissions](../../../security/roles-and-permissions/index.md).

### Step three: Invite members

When you add users to your organization, you gain visibility into their
activity and you can enforce security settings. Your members also
receive increased pull limits and other organization wide benefits when
they are signed in.

To add a member, invite a user and assign them the member role.
For more details, see [Invite members](../manage/members.md) and
[Roles and permissions](../../../security/roles-and-permissions/index.md).

### Step four: Manage user access with SSO and SCIM

Configuring SSO and SCIM is optional and only available to Docker Business
subscribers. To upgrade a Docker Team subscription to a Docker Business
subscription, see [Upgrade a plan](../../../subscription-billing/manage/plans.md#upgrade-plans).

Use your identity provider (IdP) to manage members and provision them to Docker
automatically via SSO and SCIM. See the following for more details:

- [Configure SSO](../../../security/authentication/single-sign-on/connect.md)
  to authenticate and add members when they sign in to Docker through your
  identity provider.
- Optional.
  [Enforce SSO](../../../security/authentication/single-sign-on/connect.md) to
  ensure that when users sign in to Docker, they must use SSO.

  > [!NOTE]
  >
  > Enforcing single sign-on (SSO) and enforcing Docker Desktop sign in
  > are different features. For more details, see
  > [Enforcing sign-in versus enforcing single sign-on (SSO)](../../../enterprise/security/enforce-sign-in/index.md#enforcing-sign-in-versus-enforcing-single-sign-on-sso).

- [Configure SCIM](../../../security/provisioning/scim/index.md) to
  automatically provision, add, and de-provision members to Docker through
  your identity provider.

### Step five: Enforce sign-in for Docker Desktop

By default, members of your organization can use Docker Desktop without signing
in. When users don’t sign in as a member of your organization, they don’t
receive the
[benefits of your organization’s subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminOnboard)
and they can circumvent [Docker’s security features](../../../enterprise/security/hardened-desktop/index.md).

There are multiple ways you can enforce sign-in, depending on your organization's
Docker configuration:

- [Registry key method (Windows only)](../../../enterprise/security/enforce-sign-in/methods.md#registry-key-method-windows-only)
- [`.plist` method (Mac only)](../../../enterprise/security/enforce-sign-in/methods.md#plist-method-mac-only)
- [`registry.json` method (All)](../../../enterprise/security/enforce-sign-in/methods.md#registryjson-method-all)

### Step six: Manage Docker Desktop security

Docker offers the following security features to manage your organization's
security posture:

- [Image Access Management](../../../enterprise/security/hardened-desktop/image-access-management.md): Control which types of images your developers can pull from Docker Hub.
- [Registry Access Management](../../../enterprise/security/hardened-desktop/registry-access-management.md): Define which registries your developers can access.
- [Settings management](/manuals/enterprise/security/hardened-desktop/settings-management.md): Set and control Docker Desktop settings for your users.

## Next steps

- [Manage Docker products](../manage/manage-products.md) to configure access and view usage.
- Configure [Hardened Docker Desktop](../../../enterprise/security/hardened-desktop/index.md) to improve your organization’s security posture for containerized development.
- [Manage your domains](../../../security/provisioning/domain-management.md) to ensure that all Docker users in your domain are part of your organization.

Your Docker subscription provides many more additional features. To learn more,
see [Docker subscriptions and features](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminOnboard).


---

# Create your organization

*Sección: Accounts*

{{< summary-bar feature_name="Admin orgs" >}}

There are multiple ways to create an organization. You can either:

- Create a new organization using the **Create Organization** option in the
  Docker Home
- Convert an existing user account to an organization

## Prerequisites

- Before you create an organization, you need a [Docker ID](../../individual/create-account.md).
- For prerequisites and detailed instructions on converting an existing user account to an organization, see
  [Convert an account into an organization](convert-account.md).

> [!TIP]
> Need a different plan for your team's needs? Review different [Docker subscriptions and features](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminOrgs) to choose a subscription for your organization.

## Create an organization

1. Sign in to [Docker Home](https://app.docker.com/) and navigate to the bottom
   of the organization list. Select **Create new organization**.
1. Choose a subscription for your organization, a billing cycle, and specify how many seats you need. See [Docker Pricing](https://www.docker.com/pricing?ref=Docs&refAction=DocsAdminOrgs) for details on the features offered in the Team and Business subscription.
1. Select **Continue to profile**, then **Create an organization** to create a new organization.
1. Enter an **Organization namespace**. This is the official, unique name for
   your organization in Docker Hub.
   - It's not possible to change the name of the organization after you've created it.
   - Your Docker ID and organization can't share the same name.
   - If you want to use your Docker ID as the organization name, then you must first [convert your account into an organization](convert-account.md).
1. Enter your **Company name**. This is the full name of your company.
   - Docker displays the company name on your organization page and in the details of any
     public images you publish.
   - You can update the company name anytime by navigating to your organization's **Settings** page.
1. Select **Continue to billing** to continue, then enter your organization's billing information. Select **Continue to payment** to continue to the billing portal.
1. Provide your payment details and select **Purchase**.

You've now created an organization.

## View an organization

To view an organization:

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization.

Docker Home contains many options that let you to
configure your organization.

## Merge organizations

> [!WARNING]
>
> If you are merging organizations, it is recommended to do so at the _end_ of
> your billing cycle. When you merge an organization and downgrade another, you
> will lose seats on your downgraded organization. Docker does not offer
> refunds for downgrades.

If you have multiple organizations that you want to merge into one, complete
the following steps:

1. Based on the number of seats from the secondary organization, [purchase additional seats](../manage/manage-seats.md) for the primary organization account that you want to keep.
1. Manually add users to the primary organization and remove existing users from the secondary organization.
1. Manually move over your data, including all repositories.
1. Once you're done moving all of your users and data, [downgrade](../../../subscription-billing/plans/docker.md#cancel-a-docker-plan) the secondary account to a free subscription. Note that Docker does not offer refunds for downgrading organizations mid-billing cycle.

If your organization has a Docker Business subscription with a purchase
order, contact Support or your Account Manager at Docker.

## More resources

- [Video: Docker Hub Organizations](https://www.youtube.com/watch?v=WKlT1O-4Du8)


---

# Docker Agentic Platform

*Sección: Agentic Platform*

> [!NOTE]
> Docker Agentic Platform is experimental. Features and behavior may change.

Docker Agentic Platform runs agents and agent-powered tools in isolated
sandboxes on Docker-managed cloud infrastructure. An active workload is not
tied to your computer remaining awake or connected. You can leave the Console
and return to the sandbox while the agent continues working.

For sandboxes that run on your development machine through the `sbx` CLI, see
[Docker Sandboxes](../ai/sandboxes/index.md).

From the web Console, choose the type of sandbox to run and configure its model
credential, network access, tools, and compute. Docker creates the sandbox and
opens a live terminal for interacting with the agent. The **Sandboxes** page
provides one place to return to and manage your running and paused workloads.

Account-level configuration can be reused across sandboxes:

- [MCP](mcp.md) connects external tools.
- [Secrets](secrets.md) provide credentials
  without placing their values inside a sandbox.
- [Network policies](policies.md) control
  outbound destinations.

To begin, open [Docker Agentic Platform](https://agentic-platform.docker.com/)
and sign in with your Docker account. Docker meters sandbox compute per second.
For account and payment information, see [Docker Billing](/subscription-billing/).

{{< grid >}}


---

# Docker Agentic Platform FAQ

*Sección: Agentic Platform*

## What can I run in Docker Agentic Platform?

Docker Agentic Platform provides predefined sandbox types for Claude Code,
Codex, OpenCode, Copilot, Gemini CLI, and Shell. Each type runs in an isolated,
Docker-hosted sandbox with a live terminal.

## How does Docker Agentic Platform differ from Docker Sandboxes?

Docker Agentic Platform runs sandboxes on Docker-managed cloud infrastructure
through a web Console. Docker Sandboxes runs sandboxes on your development
machine through the `sbx` command. Docker Agentic Platform manages the compute,
MCP connections, secrets, and network policies used by its hosted sandboxes.

## Can I move a sandbox between my machine and Docker Agentic Platform?

No. Local and hosted sandboxes are separate in the initial release. You cannot
move a running sandbox or its local bind mounts into Docker Agentic Platform.

## Can I share sandboxes and configuration with a team?

The initial self-service experience is single-user. You manage your own
sandboxes, MCP connections, secrets, and network policies. Shared workspaces
and collaborative ownership are not part of the initial release.

## How does a sandbox access external services?

By default, every new sandbox uses the **Open** user policy, regardless of
sandbox type. **Open** allows access to all outbound destinations. To restrict
egress, replace **Open** with **Balanced**, a custom policy, or no user policy.

Network policies control the destinations a sandbox can reach. The sandbox
type's read-only kit policy applies automatically, and you can select zero or
more user policies when you create the sandbox. If you select no user policies,
only the kit policy applies and destinations that it does not allow are blocked.
A deny rule takes precedence over an allow rule. Docker stores configured
secret values outside the sandbox and applies them to matching requests through
the sandbox proxy.

## How are sandbox usage and model inference billed?

Docker bills sandbox compute per second while the sandbox runs. The Console
also shows the equivalent hourly rate.

Model inference is billed separately. The sandbox uses your credential for an
external model provider, which meters and bills inference under that provider
account. See [Docker Billing](/subscription-billing/) for account, usage, and payment
information.

## How long are logs, telemetry, and snapshots retained?

Docker retains Docker Agentic Platform service logs for 31 days and raw
telemetry for 12 months.

All snapshots, including the most recent snapshot created when you pause a
sandbox, are automatically deleted after seven days of non-use.


---

# Get started with Docker Agentic Platform

*Sección: Agentic Platform*

The Docker Agentic Platform launcher collects the configuration needed to start
an isolated sandbox.

## Before you begin

You need a Docker account and access to Docker Agentic Platform. The launcher
prompts for a model provider API key when needed. You can add the key under
**Secrets** before creating the sandbox or provide it in the launcher when
prompted.

The available sandbox types are Claude Code, Codex, OpenCode, Copilot, Gemini
CLI, and Shell. The supported model provider credentials are Anthropic, OpenAI,
GitHub Copilot, Google, Groq, and xAI.

## Start a sandbox

1. Open [Docker Agentic Platform](https://agentic-platform.docker.com/) and
   select **New**.
2. Choose a sandbox type and add any requested model credential. Copilot uses
   `GITHUB_TOKEN`; add the same GitHub secret to any other sandbox type that
   needs private repository access.
3. Configure the sandbox. The initial settings are **open access**, **no tools
   added**, and **medium compute**.
4. Choose whether Docker stops or deletes the sandbox when its timer expires,
   and set the timer from 1 to 24 hours.
5. Review the configuration and select **Run**.

You cannot change the sandbox's authentication, tools, access policy, or compute
size after it starts. Docker creates the sandbox, marks it as running, and opens
its terminal.

Use the terminal to interact with the sandbox.

Return to **Sandboxes** to find the running sandbox and reopen its terminal.

## Next steps

- [Manage sandboxes](sandboxes.md)
- [Connect MCP servers](mcp.md)
- [Manage secrets](secrets.md)
- [Manage network policies](policies.md)


---

# MCP

*Sección: Agentic Platform*

Model Context Protocol (MCP) servers connect agents to external services and
expose operations from those services as tools. From the **MCP** page, connect a
predefined server or add a custom server by URL. Complete authorization when a
server requires it.

MCP configuration grants agents tools they can invoke. It does not restrict or
inspect ordinary network access from a sandbox. Use
[network policies](policies.md) to control outbound
destinations. MCP-specific policies are not part of the initial release.

## Connect a predefined server

1. Open **MCP** and choose a predefined server.
2. Connect the server.
3. Complete authorization if prompted.

## Add a server by URL

To connect a server that is not predefined:

1. Open **MCP**.
2. Choose the option to add a server and enter its URL.
3. Connect the server and complete authorization if prompted.


---

# Network policies

*Sección: Agentic Platform*

Network policies control the external destinations that sandboxes can reach.
They are separate from MCP server connections and secret bindings.

Docker Agentic Platform uses two types of network policy:

- Kit policies are read-only policies for each sandbox type. The corresponding
  kit policy is applied automatically when you create a sandbox. These rules
  are the sandbox type's kit defaults. Review them under **Kit policies** on the
  **Policies** page.
- User policies are policies that you can select when you create a sandbox.
  Docker provides the read-only **Open** and **Balanced** presets, and you can
  create custom policies. **Open** allows all outbound destinations.
  **Balanced** allows a curated set of destinations.

You can select no user policies, one policy, or multiple policies. The selected
user policies are combined with the sandbox type's kit policy. Docker evaluates
all applicable rules, and a deny rule takes precedence over an allow rule.

If you select no user policies, only the kit policy applies. Network access is
default-deny, so the sandbox can reach only destinations that the kit policy
explicitly allows. If its kit policy has no network rules, all outbound
destinations are blocked.

## Policy rules

Policy rules allow or deny network destinations. Use the following hostname
patterns:

| Pattern               | Example           | Matches                                            |
| --------------------- | ----------------- | -------------------------------------------------- |
| Exact hostname        | `example.com`     | `example.com` only, not subdomains                 |
| Single-level wildcard | `*.example.com`   | One subdomain level, such as `api.example.com`     |
| Multi-level wildcard  | `**.example.com`  | Any depth: `api.example.com`, `v2.api.example.com` |
| Hostname with port    | `example.com:443` | `example.com` on port 443 only                     |

`example.com` does not match subdomains, and `*.example.com` does not match the
root domain. Add each pattern required by your destinations.

You can also match IPv4 and IPv6 CIDR ranges, such as `10.0.0.0/8`,
`192.168.1.0/24`, and `2001:db8::/32`.

When defining access, include every service the sandbox needs during startup
and operation. Depending on the workload, these services can include source
control hosts, package registries, and model providers.

## Create a policy

1. Open **Policies** and select **New policy**.
2. Enter a name that identifies the intended workload or access level.
3. Add allow and deny rules for the required destinations.
4. Review the rules and save the policy.

To apply the policy, select it under **Egress policy for this sandbox** when you
create a sandbox.

You can edit, copy, or delete a custom policy. Docker-managed policies cannot
be edited or deleted.

## Understand blocked access

An agent might report an HTTP 403 response, a connection failure, or another
service error when a required destination is not allowed. The error output from
the agent or tool is the primary source for identifying the destination.

For a sandbox that uses limited access, account for every host and port the
workload needs, including source control, package registries, model providers,
and supporting APIs. Add the narrowest allow rule that covers the required
destination. Use **Open** when broad outbound access is appropriate for the
workload.

Network policy controls outbound destinations. It does not grant MCP tools or
supply credentials. Configure those separately under **MCP** and **Secrets**.


---

# Docker Agentic Platform release notes

*Sección: Agentic Platform*

## September 1, 2026

- Added inline credential saving and credential selection for sandbox launches.

## August 28, 2026

- Fixed **Usage & billing** to show the active billing cycle and accrued
  compute costs for plans that renew mid-month.

## August 27, 2026

- Added Groq and xAI credentials under **Secrets** for OpenCode sandboxes.

## August 26, 2026

Docker Agentic Platform is available for running agent and tool workloads in
sandboxes hosted on Docker-managed cloud infrastructure.

The initial release includes:

- Predefined sandbox types for Claude Code, Codex, OpenCode, Copilot, and
  Gemini CLI
- A live terminal for interacting with the workload running in a sandbox
- Pause, resume, and delete controls for sandboxes
- Automatic sandbox stop or deletion after a timer from 1 to 24 hours
- Predefined MCP servers and custom servers added by URL, with connection and
  authorization flows
- Provider and service credential management under **Secrets**, with values
  kept outside sandboxes
- Read-only kit policies that apply automatically, Docker-managed Open and
  Balanced user policies, selectable custom policies, and deny-over-allow
  precedence
- Metered sandbox compute with selectable instance sizes


---

# Sandboxes

*Sección: Agentic Platform*

A sandbox is an isolated runtime on Docker-managed cloud infrastructure.
Docker hosts and meters the sandbox and provides a live terminal for
interacting with it.

Docker Agentic Platform provides predefined sandbox types for Claude Code,
Codex, OpenCode, Copilot, Gemini CLI, and Shell. All sandbox types run Ubuntu on
x86-64 compute with Docker pre-installed. Each sandbox has its own compute,
filesystem, network access, and terminal. The compute size that you select
determines its CPU and memory resources.

The Shell type opens a Bash shell without a pre-installed agent. It uses the
same agent-less environment as [`sbx run shell`](../ai/sandboxes/agents/shell.md)
and is useful for working manually or installing your own agent.

A sandbox continues running independently of your connection to the Console
until it is paused, stopped by its lifecycle timer, or deleted.

## Source code and files

A sandbox starts with a fresh filesystem. Docker Agentic Platform does not
mount a repository, local directory, or workspace from your computer into the
sandbox by default.

A sandbox does not synchronize its filesystem with your computer or a remote
repository. Work remains only in the sandbox unless you commit and push it to a
remote repository. Push work that you want to keep before deleting the
sandbox; files that exist only in a deleted sandbox are not available from a
later sandbox.

Docker Agentic Platform supports GitHub repositories for bringing source into
a sandbox and preserving changes. `GITHUB_TOKEN` authenticates both Copilot and
GitHub repository operations. Copilot uses the same token for both. To clone a
private repository or push changes from another sandbox type, select or add
`GITHUB_TOKEN` in the launcher. The token must have the required repository
permissions. Public repositories can be cloned without a GitHub credential,
but writing to them still requires authentication.

## Open a sandbox

After you select **Run**, Docker creates the sandbox and opens its detail page.
Use the terminal to interact with the sandbox.

Open **Sandboxes** to review each sandbox's name, type, status, hourly rate,
expiration, and age. Select a sandbox to reopen its detail page and terminal.

## Manage the lifecycle

A sandbox can be running or paused:

- Pause a running sandbox to stop its compute without deleting it.
- Resume a paused sandbox to continue working with it.
- Delete a sandbox when you no longer need it.

When you create a sandbox, set a lifecycle timer from 1 to 24 hours and choose
what happens when it expires. **Stop** stops the sandbox, while **Delete**
deletes the sandbox and its files. When a sandbox stops, all processes running
inside it stop too, including background processes.

The sandbox's authentication, tools, access policy, and compute size are fixed
when the sandbox is created and cannot be changed while it runs.

Docker bills sandbox compute per second while the sandbox runs. Model inference
uses your external provider credential and is metered by that provider. For
account, usage, and payment information, see [Docker Billing](/subscription-billing/).

## Check sandbox configuration

If the sandbox cannot reach a service or use a tool, check the configuration
that applies to the request:

- Confirm that the network policies permit the destination.
- If the sandbox needs an MCP tool, confirm that its server is connected and
  authorized.
- If the destination requires authentication, confirm that the sandbox was
  created with the service credential.


---

# Secrets

*Sección: Agentic Platform*

Secrets provide credentials to agents without placing their values in a
sandbox. Docker Agentic Platform stores each value outside sandboxes and uses
the sandbox proxy to apply it to matching requests.

Docker Agentic Platform supports the following credentials:

| Service       | Secret ID           | Used by                                           |
| ------------- | ------------------- | ------------------------------------------------- |
| Anthropic     | `ANTHROPIC_API_KEY` | Claude Code and OpenCode with Anthropic models    |
| OpenAI        | `OPENAI_API_KEY`    | Codex and OpenCode with OpenAI models             |
| Google Gemini | `GEMINI_API_KEY`    | Gemini CLI and OpenCode with Google models        |
| Groq          | `GROQ_API_KEY`      | OpenCode with Groq models                         |
| xAI           | `XAI_API_KEY`       | OpenCode with xAI models                          |
| GitHub        | `GITHUB_TOKEN`      | Copilot and any sandbox type that accesses GitHub |

Provider-specific credentials are applied only to matching requests from
compatible sandbox types. For example, an Anthropic credential is not applied
to requests from a Codex sandbox. OpenCode supports all the listed model
providers.

## GitHub credential

`GITHUB_TOKEN` authenticates both Copilot and GitHub repository operations.
Entering it in the launcher stores it as the same GitHub secret shown under
**Secrets**. Any sandbox type can use it for matching GitHub requests, such as
cloning a private repository or pushing changes.

## Configure a secret

To configure a credential before launching a sandbox:

1. Open **Secrets** and find the service.
2. Select the edit icon for that service.
3. Enter its API key or token and save the value.

You can also select or add credentials from **New** when you launch a sandbox.

## Manage secrets

The **Secrets** page shows each secret ID and the sandboxes that use it. Select
the copy icon to copy the secret ID, or select the edit icon to change the
stored value.

Agents see the secret ID, not the stored value. When an outbound request matches
the secret's service binding, the sandbox proxy applies the value to the
request. A secret for one service does not become a general-purpose credential
inside the sandbox.

Do not put API keys or tokens in prompts or files inside the sandbox. Rotate or
revoke a credential at its provider when it is no longer needed.


---

# AI and Docker Compose

*Sección: Ai*




---

# Define AI Models in Docker Compose applications

*Sección: Ai*

{{< summary-bar feature_name="Compose models" >}}

Compose lets you define AI models as core components of your application, so you can declare model dependencies alongside services and run the application on any platform that supports the Compose Specification.

## Prerequisites

- Docker Compose v2.38 or later
- A platform that supports Compose models such as [Docker Model Runner (DMR)](../model-runner/index.md#requirements).

## What are Compose models?

Compose `models` are a standardized way to define AI model dependencies in your application. By using the [`models` top-level element](../../reference/compose-file/models.md) in your Compose file, you can:

- Declare which AI models your application needs
- Specify model configurations and requirements
- Make your application portable across different platforms
- Let the platform handle model provisioning and lifecycle management

## Basic model definition

To define models in your Compose application, use the `models` top-level element:

```yaml
services:
  chat-app:
    image: my-chat-app
    models:
      - llm

models:
  llm:
    model: ai/smollm2
```

This example defines:
- A service called `chat-app` that uses a model named `llm`
- A model definition for `llm` that references the `ai/smollm2` model image

## Model configuration options

Models support various configuration options:

```yaml
models:
  llm:
    model: ai/smollm2
    context_size: 1024
    runtime_flags:
      - "--a-flag"
      - "--another-flag=42"
```

Common configuration options include:
- `model` (required): The OCI artifact identifier for the model. This is what Compose pulls and runs via the model runner.
- `context_size`: Defines the maximum token context size for the model.

   > [!NOTE]
   > Each model has its own maximum context size. When increasing the context length,
   > consider your hardware constraints. In general, try to keep context size
   > as small as feasible for your specific needs.

- `runtime_flags`: A list of raw command-line flags passed to the inference engine when the model is started.
   See [Configuration options](../model-runner/configuration.md) for commonly used parameters and examples.
- Platform-specific options may also be available via extension attributes `x-*`

> [!TIP]
> See more example in the [Common runtime configurations](#common-runtime-configurations) section.

## Service model binding

Services can reference models in two ways: short syntax and long syntax.

### Short syntax

The short syntax is the simplest way to bind a model to a service:

```yaml
services:
  app:
    image: my-app
    models:
      - llm
      - embedding-model

models:
  llm:
    model: ai/smollm2
  embedding-model:
    model: ai/all-minilm
```

With short syntax, the platform automatically generates environment variables based on the model name:
- `LLM_URL` - URL to access the LLM model
- `LLM_MODEL` - Model identifier for the LLM model
- `EMBEDDING_MODEL_URL` - URL to access the embedding-model
- `EMBEDDING_MODEL_MODEL` - Model identifier for the embedding-model

### Long syntax

The long syntax allows you to customize environment variable names:

```yaml
services:
  app:
    image: my-app
    models:
      llm:
        endpoint_var: AI_MODEL_URL
        model_var: AI_MODEL_NAME
      embedding-model:
        endpoint_var: EMBEDDING_URL
        model_var: EMBEDDING_NAME

models:
  llm:
    model: ai/smollm2
  embedding-model:
    model: ai/all-minilm
```

With this configuration, your service receives:
- `AI_MODEL_URL` and `AI_MODEL_NAME` for the LLM model
- `EMBEDDING_URL` and `EMBEDDING_NAME` for the embedding model

## Platform portability

One of the key benefits of using Compose models is portability across different platforms that support the Compose specification.

### Docker Model Runner

When [Docker Model Runner is enabled](../model-runner/index.md):

```yaml
services:
  chat-app:
    image: my-chat-app
    models:
      llm:
        endpoint_var: AI_MODEL_URL
        model_var: AI_MODEL_NAME

models:
  llm:
    model: ai/smollm2
    context_size: 4096
    runtime_flags:
      - "--no-prefill-assistant"
```

Docker Model Runner will:
- Pull and run the specified model locally
- Provide endpoint URLs for accessing the model
- Inject environment variables into the service

### Cloud providers

The Compose models specification is portable. Platforms that implement the Compose specification can support the `models` top-level element, allowing the same Compose file to run on different infrastructure. Cloud-specific behavior can be configured using extension attributes (`x-*`):

```yaml
services:
  chat-app:
    image: my-chat-app
    models:
      - llm

models:
  llm:
    model: ai/smollm2
    # Cloud-specific configurations
    x-cloud-options:
      - "cloud.instance-type=gpu-small"
      - "cloud.region=us-west-2"
```

How a platform handles model definitions depends on its implementation. A platform might:

- Use managed AI services instead of running models locally
- Apply platform-specific optimizations and scaling
- Provide additional monitoring and logging capabilities
- Handle model versioning and updates automatically

## Common runtime configurations

Below are some example configurations for various use cases.

### Development

```yaml
services:
  app:
    image: app
    models:
      dev_model:
        endpoint_var: DEV_URL
        model_var: DEV_MODEL

models:
  dev_model:
    model: ai/model
    context_size: 4096
    runtime_flags:
      - "--verbose"                       # Set verbosity level to infinity
      - "--verbose-prompt"                # Print a verbose prompt before generation
      - "--log-prefix"                    # Enable prefix in log messages
      - "--log-timestamps"                # Enable timestamps in log messages
      - "--log-colors"                    # Enable colored logging
```

### Conservative with disabled reasoning

```yaml
services:
  app:
    image: app
    models:
      conservative_model:
        endpoint_var: CONSERVATIVE_URL
        model_var: CONSERVATIVE_MODEL

models:
  conservative_model:
    model: ai/model
    context_size: 4096
    runtime_flags:
      - "--temp"                # Temperature
      - "0.1"
      - "--top-k"               # Top-k sampling
      - "1"
      - "--reasoning-budget"    # Disable reasoning
      - "0"
```

### Creative with high randomness

```yaml
services:
  app:
    image: app
    models:
      creative_model:
        endpoint_var: CREATIVE_URL
        model_var: CREATIVE_MODEL

models:
  creative_model:
    model: ai/model
    context_size: 4096
    runtime_flags:
      - "--temp"                # Temperature
      - "1"
      - "--top-p"               # Top-p sampling
      - "0.9"
```

### Highly deterministic

```yaml
services:
  app:
    image: app
    models:
      deterministic_model:
        endpoint_var: DET_URL
        model_var: DET_MODEL

models:
  deterministic_model:
    model: ai/model
    context_size: 4096
    runtime_flags:
      - "--temp"                # Temperature
      - "0"
      - "--top-k"               # Top-k sampling
      - "1"
```

### Concurrent processing

```yaml
services:
  app:
    image: app
    models:
      concurrent_model:
        endpoint_var: CONCURRENT_URL
        model_var: CONCURRENT_MODEL

models:
  concurrent_model:
    model: ai/model
    context_size: 2048
    runtime_flags:
      - "--threads"             # Number of threads to use during generation
      - "8"
      - "--mlock"               # Lock memory to prevent swapping
```

### Rich vocabulary model

```yaml
services:
  app:
    image: app
    models:
      rich_vocab_model:
        endpoint_var: RICH_VOCAB_URL
        model_var: RICH_VOCAB_MODEL

models:
  rich_vocab_model:
    model: ai/model
    context_size: 4096
    runtime_flags:
      - "--temp"                # Temperature
      - "0.1"
      - "--top-p"               # Top-p sampling
      - "0.9"
```

### Embeddings

When using embedding models with the `/v1/embeddings` endpoint, you must include the `--embeddings` runtime flag for the model to be properly configured.

```yaml
services:
  app:
    image: app
    models:
      embedding_model:
        endpoint_var: EMBEDDING_URL
        model_var: EMBEDDING_MODEL

models:
  embedding_model:
    model: ai/all-minilm
    context_size: 2048
    runtime_flags:
      - "--embeddings"          # Required for embedding models
```

## Reference

- [`models` top-level element](../../reference/compose-file/models.md)
- [`models` attribute](../../reference/compose-file/services.md#models)
- [Docker Model Runner documentation](../model-runner/index.md)
- [Configuration options](../model-runner/configuration.md) - Context size and runtime parameters
- [Inference engines](../model-runner/inference-engines.md) - llama.cpp and vLLM details
- [API reference](../model-runner/api-reference.md) - OpenAI and Ollama-compatible APIs


---

# Docker Agent

*Sección: Ai*

[Docker Agent](https://github.com/docker/docker-agent) is an open-source framework
for building teams of specialized AI agents. Instead of prompting one
generalist model, you define agents with specific roles and instructions that
collaborate to solve problems. Run these agent teams from your terminal using
any LLM provider.

> [!NOTE]
> Docker Agent is a framework for building and running custom agent teams.
> For Docker's built-in AI assistant, see [Gordon](/ai/gordon/) (`docker ai`).

## Why agent teams

One agent handling complex work means constant context-switching. Split the work
across focused agents instead - each handles what it's best at. Docker Agent manages
the coordination.

Here's a two-agent team that debugs problems:

```yaml
agents:
  root:
    model: openai/gpt-5-mini # Change to the model that you want to use
    description: Bug investigator
    instruction: |
      Analyze error messages, stack traces, and code to find bug root causes.
      Explain what's wrong and why it's happening.
      Delegate fix implementation to the fixer agent.
    sub_agents: [fixer]
    toolsets:
      - type: filesystem
      - type: mcp
        ref: docker:duckduckgo

  fixer:
    model: anthropic/claude-sonnet-4-5 # Change to the model that you want to use
    description: Fix implementer
    instruction: |
      Write fixes for bugs diagnosed by the investigator.
      Make minimal, targeted changes and add tests to prevent regression.
    toolsets:
      - type: filesystem
      - type: shell
```

The root agent investigates and explains the problem. When it understands the
issue, it hands off to `fixer` for implementation. Each agent stays focused on
its specialty.

## Installation

Docker Agent is included in Docker Desktop 4.63 and later. In Docker Desktop versions 4.49 through 4.62, this feature was called cagent.

For Docker Engine users or custom installations:

- **Homebrew**: `brew install docker-agent`
- **Winget**: `winget install Docker.Agent`
- **Pre-built binaries**: [GitHub
  releases](https://github.com/docker/docker-agent/releases)
- **From source**: See the [Docker Agent
  repository](https://github.com/docker/docker-agent?tab=readme-ov-file#build-from-source)

The `docker-agent` binary should be copied to `~/.docker/cli-plugins` and then can be used with the `docker agent` command. Alternatively, it can be used as a standalone binary.

## Get started

Try the bug analyzer team:

1. Set your API key for the model provider you want to use:

   ```console
   $ export ANTHROPIC_API_KEY=<your_key>  # For Claude models
   $ export OPENAI_API_KEY=<your_key>     # For OpenAI models
   $ export GOOGLE_API_KEY=<your_key>     # For Gemini models
   ```

2. Save the [example configuration](#why-agent-teams) as `debugger.yaml`.

3. Run your agent team:

   ```console
   $ docker agent run debugger.yaml
   ```

You'll see a prompt where you can describe bugs or paste error messages. The
investigator analyzes the problem, then hands off to the fixer for
implementation.

## How it works

You interact with the _root agent_, which can delegate work to sub-agents you
define. Each agent:

- Uses its own model and parameters
- Has its own context (agents don't share knowledge)
- Can access built-in tools like todo lists, memory, and task delegation
- Can use external tools via [MCP
  servers](../mcp-catalog-and-toolkit/mcp-gateway.md)

The root agent delegates tasks to agents listed under `sub_agents`. Sub-agents
can have their own sub-agents for deeper hierarchies.

## Configuration options

Agent configurations are YAML files. A basic structure looks like this:

```yaml
agents:
  root:
    model: claude-sonnet-4-0
    description: Brief role summary
    instruction: |
      Detailed instructions for this agent...
    sub_agents: [helper]

  helper:
    model: gpt-5-mini
    description: Specialist agent role
    instruction: |
      Instructions for the helper agent...
```

You can also configure model settings (like context limits), tools (including
MCP servers), and more. See the [configuration
reference](../../reference/api/ai-governance/index.md)
for complete details.

## Share agent teams

Agent configurations are packaged as OCI artifacts. Push and pull them like
container images:

```console
$ docker agent share push ./debugger.yaml myusername/debugger
$ docker agent share pull myusername/debugger
```

Use Docker Hub or any OCI-compatible registry. Pushing creates the repository if
it doesn't exist yet.

## What's next

- Follow the [quickstart](../../reference/api/ai-governance/index.md) to build your first agent
- Learn [best practices](../../reference/api/ai-governance/index.md) for building effective agents
- Integrate Docker Agent with your [editor](../../reference/api/ai-governance/index.md) or use agents as
  [tools in MCP clients](../../reference/api/ai-governance/index.md)
- Browse example agent configurations in the [Docker Agent
  repository](https://github.com/docker/docker-agent/tree/main/examples)
- Connect agents to external tools via the [Docker MCP
  Gateway](../mcp-catalog-and-toolkit/mcp-gateway.md)
- Read the full [configuration reference](../../reference/api/ai-governance/index.md)


---

# Gordon

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Gordon is an AI-powered assistant that takes action on your Docker workflows.
It analyzes your environment, proposes solutions, and executes commands with
your permission.

## What Gordon does

Gordon takes action to help you with Docker tasks:

- Explains Docker concepts and commands
- Searches Docker documentation and web resources for solutions
- Writes and modifies Dockerfiles following best practices
- Debugs container failures by reading logs and proposing fixes
- Manages containers, images, volumes, and networks

Gordon proposes every action before executing. You approve what it does.

## Where to use Gordon

Gordon is available on four surfaces:

- Open the Gordon view from the Docker Desktop sidebar to run Docker commands
  with your approval. See [Using Gordon in Docker
  Desktop](how-to/docker-desktop.md).
- Run `docker ai` in the terminal to use the full assistant from the command
  line. See [Using Gordon via CLI](how-to/cli.md).
- Select the Gordon icon on any repository page at
  [hub.docker.com](https://hub.docker.com) to ask about a repository's
  images, tags, and metadata. Hand off to Docker Desktop to take action.
- Select the Gordon icon on any page at
  [docs.docker.com](https://docs.docker.com) to ask Docker questions.

Docker Desktop and the CLI count against your Gordon plan's [usage
limits](usage-limits.md). Gordon on Docker Hub and docs.docker.com is free
and does not require a Docker account or a Docker Desktop install. It has
its own shared public usage limit and does not access your Docker
environment.

## Get started

### Prerequisites

Before you begin:

- Docker Desktop 4.74 or later
- Sign in to your Docker account

> [!NOTE]
> Gordon is enabled by default for signed-in Docker users. If your account
> belongs to an organization with a Business subscription, access requires two
> additional steps:
>
> 1. Contact Docker Support to activate Gordon for your organization. Docker
>    will confirm when activation is complete.
> 2. Once confirmed, an organization administrator must turn on Gordon via
>    [Settings Management](../../enterprise/security/hardened-desktop/settings-management/index.md).
>    Set **Enable Gordon** to **Enabled** or **Always enabled**. Ensure all
>    Settings Management prerequisites are met for the setting to take effect
>    on Docker Desktop clients.

### Quick start

{{< tabs >}}
{{< tab name="Docker Desktop" >}}

1. Open Docker Desktop.
2. Select **Gordon** in the sidebar.
3. Select your project directory.
4. Type a question: "What containers are running?"

   ![Gordon running in Docker Desktop](./images/gordon_gui.avif)

5. Review Gordon's proposed actions and approve.

{{< /tab >}}
{{< tab name="CLI" >}}

1. Open your terminal and run:

   ```console
   $ docker ai
   ```

   This opens the Terminal User Interface (TUI) for Gordon.

2. Type a question: "what containers are running?" and press <kbd>Enter</kbd>.

   ![Gordon running in the terminal](./images/gordon_tui.avif)

3. Review Gordon's proposed actions and approve by typing `y`.

{{< /tab >}}
{{< /tabs >}}

### Permissions

By default, Gordon asks for approval before executing actions. You can approve
individual actions or allow all actions for the current session.

![Gordon permission request](./images/gordon_permissions_prompt.avif)

Permissions reset for each session. To configure default permissions or enable
auto-approve mode, see [Permissions](how-to/permissions.md).

### Try these examples

Container inspection:

```console
$ docker ai "show me logs from my nginx container"
```

Dockerfile review:

```console
$ docker ai "review my Dockerfile for best practices"
```

Image management:

```console
$ docker ai "list my local images and their sizes"
```


---

# Concepts

*Sección: Ai*




---

# Gordon's capabilities

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Gordon combines multiple capabilities to handle Docker workflows. This page
explains what Gordon can do and the tools it uses.

## Core capabilities

Gordon uses five capabilities to take action on your behalf:

- Specialized sub-agents for specific Docker tasks
- Shell access to run commands
- Filesystem access to read and write files
- Knowledge base of Docker documentation and best practices
- Web access to fetch external resources

## Internal architecture

Gordon uses a primary agent that handles most tasks, with a specialized
sub-agent for specific workflows:

- **Main agent**: Handles all Docker operations, software development,
  containerization, and general development tasks
- **DHI migration sub-agent**: Specialized handler for migrating Dockerfiles to
  Docker Hardened Images

The main agent handles:

- Creating Docker assets (Dockerfile, compose.yaml, .dockerignore)
- Optimizing Dockerfiles to reduce image size and improve build performance
- Running Docker commands (ps, logs, exec, build, compose)
- Debugging container issues and analyzing configurations
- Writing and reviewing code across multiple programming languages
- General development questions and tasks

When you request DHI migration, Gordon automatically delegates to the DHI
migration sub-agent.

## Shell access

Gordon executes shell commands in your environment after you approve them.
This includes Docker CLI commands, system utilities, and application-specific
tools.

Example commands Gordon might run:

```console
$ docker ps
$ docker logs container-name
$ docker exec -it container-name bash
$ grep "error" app.log
```

Commands run with your user permissions. Gordon cannot access `sudo` unless
you've explicitly granted it.

## Filesystem access

Gordon reads and writes files on your system. It can analyze Dockerfiles, read
configuration files, scan directories, and parse logs without approval. Writing
files requires your approval.

The working directory sets the default context for file operations, but Gordon
can access files outside this directory when needed.

## Knowledge base

Gordon uses retrieval-augmented generation to access Docker documentation,
best practices, troubleshooting procedures, and security recommendations. This
lets Gordon answer questions accurately, explain errors, and suggest
solutions that follow Docker's guidelines.

## Web access

Gordon fetches external web resources to look up error messages, package
versions, and framework documentation. This helps when debugging issues that
require context outside Docker's own documentation.

Gordon cannot access authenticated or private resources, and external requests
are rate-limited.

## Working with other tools

Gordon complements general-purpose AI coding assistants by focusing on Docker
workflows. Use tools like Cursor or GitHub Copilot for application code and
refactoring, and use Gordon for containerization, deployment configuration,
and Docker operations. They work well together.


---

# Data privacy and Gordon

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

This page explains what data Gordon accesses, how it's used, and what privacy
protections are in place.

## What data Gordon accesses

When you use Gordon, the data it accesses depends on your query and
configuration.

### Local files

When you use the `docker ai` command, Gordon can access files and directories
on your system. The working directory sets the default context for file
operations.

In Docker Desktop, if you ask about a specific file or directory in the Gordon
view, you'll be prompted to select the relevant context.

### Local images

Gordon integrates with Docker Desktop and can view all images in your local
image store. This includes images you've built or pulled from a registry.

### Docker environment

Gordon has access to your Docker daemon's state, including:

- Running and stopped containers
- Container logs and configuration
- Images and image layers
- Volumes and networks
- Build cache

## Data retention policy

Gordon's data retention differs based on your subscription tier:

### Paid subscriptions

Docker and its AI providers do not retain any inputs or outputs from your
Gordon sessions. Your queries, Gordon's responses, and any code or files
processed are not stored. This applies to all paid subscriptions: Docker
Desktop plans (Pro, Team, Business) and Gordon plans (Plus, Max, Ultra).

### Personal (free) subscription

Anonymized conversation threads are stored for 5 days to help guarantee
quality of service and fight abuse. Individual queries and responses are
retained as part of your conversation history.

### All subscriptions

Data is never used for training AI models or shared with third parties. All
data transferred to Gordon's backend is encrypted in transit. Docker's
third-party AI providers process requests under zero-data-retention
agreements: they don't store your prompts or Gordon's responses.

## Sensitive data protection

Gordon automatically detects and redacts secrets and other sensitive material
from your requests using [portcullis](https://github.com/docker/portcullis),
Docker's open source redaction library. Around 240 patterns are covered,
including:

- Cloud provider credentials (AWS, GCP, Azure, and others)
- API tokens (GitHub, GitLab, Docker Hub, Slack, OpenAI, Stripe, and more)
- PEM private keys and JWTs
- Database connection-string passwords
- Payment card numbers, IBANs, and US Social Security numbers

Detected values are replaced with `[REDACTED]` before your request is
processed.

## Data security

Your data is protected through encryption in transit. For paid subscriptions,
no persistent storage occurs—Gordon processes your requests and discards the
data immediately.

For questions about privacy terms and conditions, review [Gordon's
Supplemental
Terms](https://www.docker.com/legal/docker-ai-supplemental-terms/).

## Organizational data policies

For Business subscriptions, administrators can enable or disable Gordon for
their organization using Settings Management. Review your organization's data
handling requirements before enabling Gordon.

See [Settings Management](/enterprise/security/hardened-desktop/settings-management/)
for configuration details.

## Disabling Gordon

You can disable Gordon at any time:

Individual users:

1. Open Docker Desktop Settings.
2. Navigate to the **AI** section.
3. Clear the **Enable Gordon** option.
4. Select **Apply**.

Business organizations:

Administrators can disable Gordon for the entire organization using Settings
Management. See [Settings Management](/enterprise/security/hardened-desktop/settings-management/)
for details.

## Questions about privacy

For questions about Docker's privacy practices:

- Review the [Docker Privacy Policy](https://www.docker.com/legal/privacy/)
- Read [Gordon's Supplemental Terms](https://www.docker.com/legal/docker-ai-supplemental-terms/)
- Contact Docker Support for specific concerns


---

# How-to guides

*Sección: Ai*




---

# Using Gordon via CLI

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

The `docker ai` command provides a Terminal User Interface (TUI) for Gordon,
integrating AI assistance directly into your terminal.

## Basic usage

Launch the interactive TUI:

```console
$ docker ai
```

This opens Gordon's terminal interface where you can type prompts, approve
actions, and continue conversations with full context.

<script src="https://asciinema.org/a/9kvZFH9LO9ZVDpwS.js" id="asciicast-9kvZFH9LO9ZVDpwS" async="true"></script>

Pass a prompt directly as an argument:

```console
$ docker ai "list my running containers"
```

Exit the TUI with `/exit` or <kbd>Ctrl+C</kbd>.

## Working directory

The working directory sets the default context for Gordon's file operations.

Gordon uses your current shell directory as the working directory:

```console
$ cd ~/my-project
$ docker ai
```

Override with `-C` or `--working-dir`:

```console
$ docker ai -C ~/different-project
```

## Disabling Gordon

Gordon CLI is part of Docker Desktop. To disable it, disable Gordon in Docker
Desktop Settings:

1. Open Docker Desktop Settings.
2. Navigate to the **AI** section.
3. Clear the **Enable Gordon** option.
4. Select **Apply**.

## Commands

The `docker ai` command includes several subcommands:

Interactive mode (default):

```console
$ docker ai
```

Opens the TUI for conversational interaction.

Version:

```console
$ docker ai version
```

Displays the Gordon version.

Feedback:

```console
$ docker ai feedback
```

Opens a feedback form in your browser.


---

# Configure Gordon's tools

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Gordon includes built-in tools that extend its capabilities. You can configure
which tools Gordon has access to based on your security requirements and
workflow needs.

Tool configuration provides an additional layer of control:

- Enabled tools: Gordon can propose actions using these tools (subject to
  your approval)
- Disabled tools: Gordon cannot use these tools, and will not request
  permission to use them

## Accessing tool settings

To configure Gordon's tools:

1. Open Docker Desktop.
2. Select **Gordon** in the sidebar.
3. Select the settings icon at the bottom of the text input area.

   ![Session settings icon](../images/gordon_permission_settings.avif)

The tool settings dialog opens with two tabs: **Basic** and **Advanced**.

## Basic tool settings

In the **Basic** tab, you can enable or disable individual tools globally.

To disable a tool:

1. Find the tool you want to disable in the list.
2. Toggle it off.
3. Select **Save**.

Disabled tools cannot be used by Gordon, even with your approval.

## Advanced tool settings

The **Advanced** tab lets you create fine-grained allow-lists and deny-lists
for specific commands or patterns.

Allow-lists:
Gordon can use allow-listed commands even when the main tool is disabled. For
example, disable the shell tool but allow `cat`, `grep`, and `ls`.

Deny-lists:
Block specific commands while keeping the tool enabled. For example, allow the
shell tool but deny `chown` and `chmod`.

To configure:

1. Switch to the **Advanced** tab.
2. Add commands to **Allow rules** or **Deny rules**.
3. Select **Save**.

![Advanced tool configuration](../images/gordon_advanced_tool_config.avif)

Gordon still requests approval before running allow-listed tools, unless YOLO
mode (auto-approve mode that bypasses permission checks) is enabled.

## Organizational controls

For Business subscriptions, administrators can control tool access for the
entire organization using Settings Management.

Administrators can:

- Disable specific tools for all users
- Lock tool configuration to prevent users from changing it
- Set organization-wide tool policies

See [Settings Management](/enterprise/security/hardened-desktop/settings-management/)
for details.


---

# Using Gordon in Docker Desktop

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Gordon is integrated into Docker Desktop. Access it from the sidebar to open
the Gordon view.

## Basic usage

To access Gordon:

1. Open Docker Desktop and sign in to your Docker account.
2. Select **Gordon** in the sidebar.
3. Type your question or request in the input field.
4. Press <kbd>Enter</kbd> or select the send button.

Gordon responds in the chat view and maintains context throughout the session.

## Working directory

The working directory sets the default context for Gordon's file operations.
Select your working directory when you start Gordon or use the directory icon
to change it during a conversation:

1. Select the directory icon in the Gordon input area.
2. Browse and select a different directory.

## Contextual help

The Gordon icon appears throughout Docker Desktop. Selecting it opens Gordon
pre-loaded with context about the item you are working with, such as container
logs or build output.

## Usage indicator

Docker Desktop shows a usage indicator so you can see how close you are to
your tier limit. See [Usage limits and tiers](../usage-limits.md) for details.

## Disabling Gordon

To disable Gordon:

1. Open Docker Desktop Settings.
2. Navigate to the **AI** section.
3. Clear the **Enable Gordon** option.
4. Select **Apply**.

## Configure tools

You can control which tools Gordon has access to. See [Configure
tools](configure-tools.md) for details on enabling, disabling, and
fine-tuning tool permissions.


---

# Gordon's permission model

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Before Gordon uses a tool or action that can modify your system, it proposes
the action and waits for your approval before executing.

## What requires approval

By default, the following actions require approval before Gordon can use them:

- Commands executed in your shell
- Writing or changing files
- Fetching information from the internet

## What doesn't require approval

- Reading files, listing directories (even outside Gordon's working directory)
- Searching the Docker documentation
- Analyzing code or explaining errors

## Configuring permission settings

To change the default permission settings for Gordon:

1. Open Docker Desktop.
2. Select **Gordon** in the sidebar.
3. Select the settings icon at the bottom of text input.

   ![Session settings icon](../images/gordon_permission_settings.avif)

In the **Basic** tab you can configure whether Gordon should ask for permission
before using a tool.

You can also enable YOLO mode to bypass permission checking altogether.

The new permission settings apply immediately to all sessions.

## Session-level permissions

When you choose "Approve for this session" (Desktop) or "A" (CLI), Gordon can
use that specific tool without asking again during the current conversation.

Example:

```console
$ docker ai "check my containers and clean up stopped ones"

Gordon proposes:
  docker ps -a

Approve? [Y/n/a]: a

[Gordon executes docker ps -a]

Gordon proposes:
  docker container prune -f

[Executes automatically - you approved shell access for this session]
```

Session permissions reset when:

- You close the Gordon view (Desktop)
- You exit `docker ai` (CLI)
- You start a new conversation

## Security considerations

Working directory
: The working directory sets the default context for file operations. It does
  not constrain Gordon's access to files or directories; Gordon can read files
  outside this directory.

Verify before approving
: Gordon can make mistakes. Before approving:

  - Confirm commands match your intent
  - Check container names and image tags are correct
  - Verify volume mounts and port mappings
  - Review file changes for important logic

  If you don't understand an operation, ask Gordon to explain it or reject and
  request a different approach.

Destructive operations
: Gordon warns about destructive operations but won't prevent them. Operations
  like `docker container rm`, `docker system prune`, and `docker volume rm` can
  cause permanent data loss. Back up important data first.

## Stopping and reverting

Stop Gordon during execution by pressing `Ctrl+C` (CLI) or selecting **Cancel**
(Desktop).

Revert Gordon's actions using Docker commands or version control:

- Restore files from Git
- Restart stopped containers
- Rebuild images
- Recreate volumes from backups

Use version control for all files in your working directory.

## Organizational controls

Administrators can control Gordon's capabilities at the organization level
using Settings Management.

Available controls:

- Disable Gordon entirely
- Restrict tool capabilities
- Set working directory boundaries

For Business subscriptions, Gordon must be enabled by an administrator before
users can access it.

See [Settings Management](/enterprise/security/hardened-desktop/settings-management/)
for details.


---

# Gordon usage limits and tiers

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Gordon is included with every Docker account at the Base tier. Paid Gordon
plans unlock higher usage limits.

## Tiers

| Tier  | Usage allocation                 |
| ----- | -------------------------------- |
| Base  | Included with any Docker account |
| Plus  | 2× Base                          |
| Max   | 5× Base                          |
| Ultra | 10× Base                         |

For more information about Gordon tiers and how to upgrade, go to
[docker.com](https://www.docker.com/products/gordon).

## Usage limits

Gordon usage is measured in questions. The number you can ask depends on
complexity: questions that involve more context, files, or Docker operations
count more toward your limit.

| Tier  | Per 4 hours | Per day | Per month |
| ----- | ----------- | ------- | --------- |
| Base  | ~40         | ~100    | ~180      |
| Plus  | ~80         | ~200    | ~360      |
| Max   | ~200        | ~500    | ~900      |
| Ultra | ~400        | ~1000   | ~1800     |

These are estimates and vary based on question complexity.

Usage limits reset at fixed UTC times, not on a sliding window. The 4-hour
window resets every 4 hours starting at 00:00 UTC, the daily window resets at
00:00 UTC, and the monthly window resets on the first day of each calendar
month at 00:00 UTC.

## View your usage

Docker Desktop shows a usage indicator so you can see how close you are to
your limit. To get more usage, upgrade your tier.


---

# Gordon use cases and examples

*Sección: Ai*

{{< summary-bar feature_name="Gordon" >}}

Gordon handles Docker workflows through natural conversation. In Docker
Desktop, Gordon is available from the sidebar for open-ended sessions and from
contextual entry points in views like Containers, Images, Builds, and Volumes.
Selecting Gordon from one of these views opens a conversation pre-loaded with
context about the item you're looking at. You can ask the same questions from
the CLI with `docker ai`.

## Debug a failing container

You're in the Containers view and a container has crashed or behaves
unexpectedly. Open Gordon from the container row to ask about that container's
state and configuration:

- "Why did this container exit?"
- "What environment variables are set in this container?"
- "How long did this container run?"
- "What security settings are applied to this container?"

From the CLI:

```console
$ docker ai "why is my postgres container crashing on startup?"
```

## Debug a failed build

You're in the Builds view looking at a build that failed or is slower than
expected. Open Gordon from the build to inspect the Dockerfile, build
arguments, and cache behavior:

- "Why did this build fail?"
- "How can I improve cache usage for this build?"
- "What Dockerfile instructions were used?"
- "What build arguments were used?"

From the CLI:

```console
$ docker ai "my build is failing at the pip install step, what's wrong?"
```

## Inspect an image

You're in the Images view and want to understand what's in an image before
running it, or you want to size up a base image:

- "How do I run this image in the CLI?"
- "What environment variables are configured?"
- "What entrypoint is configured?"
- "What's the base architecture of this image?"
- "Is there a lighter version of this image?"

From the CLI:

```console
$ docker ai "compare my python:3.12 image to python:3.12-slim"
```

## Manage volumes and resources

From the Volumes view, ask Gordon about what's stored, which containers use a
volume, or how to clean up. From any view, use the Gordon sidebar to inspect
your wider environment:

- "Which containers are using this volume?"
- "Show me all my containers and their status"
- "How much disk space is Docker using?"
- "List my images sorted by size"

From the CLI:

```console
$ docker ai "clean up all unused Docker resources"
```

## Build and containerize

For new projects, start a conversation in the Gordon sidebar or via `docker
ai` from your project directory. Gordon reads your working directory and
proposes the right files:

- "Containerize my Node.js app"
- "Create a docker-compose for my stack"
- "Set up a dev environment with Postgres and Redis"

From the CLI:

```console
$ cd ~/my-project
$ docker ai "create a Dockerfile for this application"
```

## Develop and optimize

Ask Gordon to review and improve existing Dockerfiles or service definitions.
You can start from the Images view (for an image you've already built) or from
the Gordon sidebar with your project context:

- "Optimize this Dockerfile"
- "Add a health check to my service"
- "Make my Dockerfile more secure"

From the CLI:

```console
$ docker ai "rate my Dockerfile and suggest improvements"
```

## Learn Docker

For conceptual questions, use the Gordon sidebar or CLI. Gordon explains
concepts grounded in your environment, not generic answers:

- "What is a Docker volume?"
- "Explain multi-stage builds"
- "How does networking work in Docker?"

From the CLI:

```console
$ docker ai "what's the difference between COPY and ADD in a Dockerfile?"
```

## Writing effective prompts

Be specific:

- Include relevant context: "my postgres container" not "the database"
- State your goal: "make my build faster" not "optimize"
- Include error messages when debugging

Gordon works best when you describe what you want to achieve rather than how
to do it. Gordon maintains context across a conversation, so you can follow up
with clarifications or ask related questions without repeating yourself.

### Working directory context

When using `docker ai` in the CLI, Gordon uses your current working directory
as the default context for file operations. Change to your project directory
before starting Gordon to ensure it has access to the right files:

```console
$ cd ~/my-project
$ docker ai "review my Dockerfile"
```

You can also override the working directory with the `-C` flag. See [Using
Gordon via CLI](how-to/cli.md#working-directory) for details.


---

# Docker MCP Catalog and Toolkit

*Sección: Ai*

{{< summary-bar feature_name="Docker MCP Catalog and Toolkit" >}}

[Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) is
an open protocol that standardizes how AI applications access external tools
and data sources. By connecting LLMs to local development tools, databases,
APIs, and other resources, MCP extends their capabilities beyond their base
training.

The challenge is that running MCP servers locally creates operational friction.
Each server requires separate installation and configuration for every
application you use. You run untrusted code directly on your machine, manage
updates manually, and troubleshoot dependency conflicts yourself. Configure a
GitHub server for Claude, then configure it again for Cursor, and so on. Each
time you manage credentials, permissions, and environment setup.

## Docker MCP features

The [MCP Toolkit](/ai/mcp-catalog-and-toolkit/toolkit/) and [MCP
Gateway](/ai/mcp-catalog-and-toolkit/mcp-gateway/) solve these challenges
through centralized management. Instead of configuring each server for every AI
application separately, you set things up once and connect all your clients to
it. The workflow centers on three concepts: catalogs, profiles, and clients.

![MCP overview](./images/mcp_toolkit.avif)

[Catalogs](/ai/mcp-catalog-and-toolkit/catalog/) are curated collections of
MCP servers. The Docker MCP Catalog provides 300+ verified servers packaged as
container images with versioning, provenance, and security updates. Organizations
can create [custom
catalogs](/ai/mcp-catalog-and-toolkit/catalog/#custom-catalogs) with approved
servers for their teams.

[Profiles](/ai/mcp-catalog-and-toolkit/profiles/) organize servers into named
collections for different projects. Your "web-dev" profile might use GitHub and
Playwright; your "backend" profile, database tools. Profiles support both
containerized servers from catalogs and remote MCP servers. Configure a profile
once, then share it across clients or with your team.

Clients are the AI applications that connect to your profiles. Claude Code,
Cursor, Zed, and others connect through the MCP Gateway, which routes requests
to the right server and handles authentication and lifecycle management.

> [!NOTE]
> MCP Gateway as part of Docker AI Governance is an invite-only feature. [Contact Docker Sales](https://www.docker.com/pricing/contact-sales/) to learn more.

## Learn more

{{< grid >}}


---

# Docker MCP Catalog

*Sección: Ai*

{{< summary-bar feature_name="Docker MCP Catalog" >}}

The [Docker MCP Catalog](https://hub.docker.com/mcp) is a curated collection of
verified MCP servers, packaged as Docker images and distributed through Docker
Hub. It solves common challenges with running MCP servers locally: environment
conflicts, setup complexity, and security concerns.

The catalog serves as the source of available MCP servers. When you add servers
to your [profiles](profiles.md), you select
them from the catalog. Each server runs as an isolated container, making it
portable and consistent across different environments.

> [!NOTE]
> E2B sandboxes now include direct access to the Docker MCP Catalog, giving
> developers access to over 200 tools and services to seamlessly build and run
> AI agents. For more information, see [E2B Sandboxes](e2b-sandboxes.md).

## What's in the catalog

The Docker MCP Catalog includes:

- Verified servers: All servers are versioned with full provenance and SBOM
  metadata
- Partner tools: Servers from New Relic, Stripe, Grafana, and other trusted
  partners
- Docker-built servers: Locally-running servers built and digitally signed by
  Docker for enhanced security
- Remote services: Cloud-hosted servers that connect to external services like
  GitHub, Notion, and Linear

### Local versus remote servers

The catalog contains two types of servers based on where they run:

Local servers run as containers on your machine. They work offline once
downloaded and offer predictable performance and complete data privacy. Docker
builds and signs all local servers in the catalog.

Remote servers run on the provider's infrastructure and connect to external
services. Many remote servers use OAuth authentication, which the MCP Toolkit
handles automatically through your browser.

## Browse the catalog

Browse available MCP servers at [hub.docker.com/mcp](https://hub.docker.com/mcp)
or directly in Docker Desktop:

1. In Docker Desktop, select **MCP Toolkit**.
2. Select the **Catalog** tab to browse available servers.
3. Select a server to view its description, tools, and configuration options.

## Add servers to a profile

To add a server from the catalog to a profile:

1. In the **Catalog** tab, select the checkbox next to a server.
2. Choose the profile to add it to from the drop-down.

For step-by-step instructions and client connection, see
[Get started with MCP Toolkit](get-started.md) or
[MCP Profiles](profiles.md).

## Custom catalogs

Custom catalogs let you curate focused collections of servers for your team or
organization. Instead of exposing all 300+ servers in the Docker catalog, you
define exactly which servers are available.

Common use cases:

- Restrict which servers your organization approves for use
- Add your organization's private MCP servers alongside public ones
- Control which server versions your team uses
- Define the server set available to AI agents using [Dynamic MCP](dynamic-mcp.md)

### Custom catalogs with Dynamic MCP

Custom catalogs work particularly well with
[Dynamic MCP](/ai/mcp-catalog-and-toolkit/dynamic-mcp/), where agents discover
and add MCP servers on-demand during conversations. When you run the gateway
with a custom catalog, the `mcp-find` tool searches only within that catalog.
If your catalog contains 20 servers instead of 300+, agents work within that
focused set, discovering and enabling tools as needed without manual
configuration each time.

### Import a custom catalog

If someone on your team has created and published a catalog, you can import it
using its OCI registry reference.

In Docker Desktop:

1. Select **MCP Toolkit** and select the **Catalog** tab.
2. Select **Import catalog**.
3. Enter the OCI reference for the catalog (for example,
   `registry.example.com/mcp/team-catalog:latest`).
4. Select **Import**.

Using the CLI:

```console
$ docker mcp catalog pull <oci-reference>
```

Once imported, the catalog appears alongside the Docker catalog and you can add
its servers to your profiles.

### Create and manage custom catalogs

Creating and managing custom catalogs requires the CLI. See
[Custom catalogs](cli.md#custom-catalogs)
in the CLI how-to for step-by-step instructions, including:

- Curating a subset of the Docker catalog
- Adding private servers to a catalog
- Building a focused catalog from scratch
- Pushing a catalog to a registry for your team to import

## Contribute an MCP server to the catalog

The MCP server registry is available at
https://github.com/docker/mcp-registry. To submit an MCP server, follow the
[contributing guidelines](https://github.com/docker/mcp-registry/blob/main/CONTRIBUTING.md).

When your pull request is reviewed and approved, your MCP server is available
within 24 hours on:

- Docker Desktop's [MCP Toolkit feature](toolkit.md).
- The [Docker MCP Catalog](https://hub.docker.com/mcp).
- The [Docker Hub](https://hub.docker.com/u/mcp) `mcp` namespace (for MCP
  servers built by Docker).


---

# Use MCP Toolkit from the CLI

*Sección: Ai*

{{< summary-bar feature_name="Docker MCP Toolkit" >}}

> [!NOTE]
> The `docker mcp` commands documented here are available in Docker Desktop
> 4.62 and later. Earlier versions may not support all commands shown.

The `docker mcp` commands let you manage MCP profiles, servers, OAuth
credentials, and catalogs from the terminal. Use the CLI for scripting,
automation, and headless environments.

## Profiles

### Create a profile

```console
$ docker mcp profile create --name <profile-id>
```

The profile ID is used to reference the profile in subsequent commands:

```console
$ docker mcp profile create --name web-dev
```

### List profiles

```console
$ docker mcp profile list
```

### View a profile

```console
$ docker mcp profile show <profile-id>
```

### Remove a profile

```console
$ docker mcp profile remove <profile-id>
```

> [!CAUTION]
> Removing a profile deletes all its server configurations and settings. This
> action can't be undone.

## Servers

### Browse the catalog

List available servers and their IDs:

```console
$ docker mcp catalog server ls mcp/docker-mcp-catalog
```

The output lists each server by name. The name (for example, `playwright` or
`github-official`) is the server ID to use in `catalog://` URIs.

To look up a server ID in Docker Desktop, open **MCP Toolkit** > **Catalog**,
select a server, and check the **Server ID** field.

### Add servers to a profile

Servers are referenced by URI. The URI format depends on where the server
comes from:

| Format                                | Source                     |
| ------------------------------------- | -------------------------- |
| `catalog://<catalog-ref>/<server-id>` | An OCI catalog             |
| `docker://<image>:<tag>`              | A Docker image             |
| `https://<url>/v0/servers/<uuid>`     | The MCP community registry |
| `file://<path>`                       | A local YAML or JSON file  |

The most common format is `catalog://`, where `<catalog-ref>` matches the
**Catalog** field and `<server-id>` matches the **Server ID** field shown in
Docker Desktop or in the `catalog server ls` output:

```console
$ docker mcp profile server add <profile-id> \
  --server catalog://<catalog-ref>/<server-id>
```

Add multiple servers in one command:

```console
$ docker mcp profile server add web-dev \
  --server catalog://mcp/docker-mcp-catalog/github-official \
  --server catalog://mcp/docker-mcp-catalog/playwright
```

To add a server defined in a local YAML file:

```console
$ docker mcp profile server add my-profile \
  --server file://./my-server.yaml
```

The YAML file defines the server image and configuration:

```yaml
name: my-server
title: My Server
type: server
image: myimage:latest
description: Description of the server
```

If the server requires OAuth authentication, authorize it in Docker Desktop
after adding. See [OAuth authentication](toolkit.md#oauth-authentication).

### List servers

List all servers across all profiles:

```console
$ docker mcp profile server ls
```

Filter by profile:

```console
$ docker mcp profile server ls --filter profile=web-dev
```

### Remove a server

```console
$ docker mcp profile server remove <profile-id> --name <server-name>
```

Remove multiple servers at once:

```console
$ docker mcp profile server remove web-dev \
  --name github-official \
  --name playwright
```

### Configure server settings

Set and retrieve configuration values for servers in a profile:

```console
$ docker mcp profile config <profile-id> --set <server-id>.<key>=<value>
$ docker mcp profile config <profile-id> --get-all
$ docker mcp profile config <profile-id> --del <server-id>.<key>
```

Server configuration keys and their expected values are defined by each server.
Check the server's documentation or its entry in Docker Desktop under
**MCP Toolkit** > **Catalog** > **Configuration**.

## Gateway

Run the MCP Gateway with a specific profile:

```console
$ docker mcp gateway run --profile <profile-id>
```

Omit `--profile` to use the default profile.

### Connect a client manually

To connect any client that isn't listed in Docker Desktop, configure it to run
the gateway over `stdio`. For example, in a JSON-based client configuration:

```json
{
  "servers": {
    "MCP_DOCKER": {
      "command": "docker",
      "args": ["mcp", "gateway", "run", "--profile", "web-dev"],
      "type": "stdio"
    }
  }
}
```

For Claude Desktop, the format is:

```json
{
  "mcpServers": {
    "MCP_DOCKER": {
      "command": "docker",
      "args": ["mcp", "gateway", "run", "--profile", "web-dev"]
    }
  }
}
```

### Connect a named client

Connect a supported client to a profile:

```console
$ docker mcp client connect <client> --profile <profile-id>
```

For example, to connect VS Code to a project-specific profile:

```console
$ docker mcp client connect vscode --profile my-project
```

This creates a `.vscode/mcp.json` file in the current directory. Because this
is a user-specific file, add it to `.gitignore`:

```console
$ echo ".vscode/mcp.json" >> .gitignore
```

## Share profiles

Share profiles with your team using OCI registries or version control.

### Share via OCI registry

Profiles are shared as OCI artifacts via any OCI-compatible registry.
Credentials are not included for security reasons. Team members configure
authentication credentials separately after pulling.

To push an existing profile called `web-dev` to an OCI registry:

```console
$ docker mcp profile push web-dev registry.example.com/profiles/web-dev:v1
```

To pull the same profile:

```console
$ docker mcp profile pull registry.example.com/profiles/team-standard:latest
```

### Share via version control

For project-specific profiles, you can use the `export` and `import` commands
and store the profiles in version control alongside your code. Team members can
import the file to get the same configuration.

To export a profile to your project directory:

```console
$ mkdir -p .docker
$ docker mcp profile export web-dev .docker/mcp-profile.json
```

Team members who clone the repository can import the profile:

```console
$ docker mcp profile import .docker/mcp-profile.json
```

This creates a profile with the servers and configuration defined in the
file. Any authentication credentials must be configured separately if needed.

## Custom catalogs

Custom catalogs let you curate a focused collection of servers for your team
or organization. For an overview of what custom catalogs are and when to use
them, see [Custom catalogs](catalog.md#custom-catalogs).

Catalogs are referenced by OCI reference, for example
`registry.example.com/mcp/my-catalog:latest`. Servers within a catalog use
the same URI schemes as when
[adding servers to a profile](#add-servers-to-a-profile).

### Customize the Docker catalog

Use the Docker catalog as a base, then add or remove servers to fit your
organization's needs. Copy it first:

```console
$ docker mcp catalog tag mcp/docker-mcp-catalog \
  registry.example.com/mcp/company-tools:latest
```

List the servers it contains:

```console
$ docker mcp catalog server ls registry.example.com/mcp/company-tools:latest
```

Remove servers your organization doesn't approve:

```console
$ docker mcp catalog server remove \
  registry.example.com/mcp/company-tools:latest \
  --name <server-name>
```

Add your own private servers, packaged as Docker images:

```console
$ docker mcp catalog server add registry.example.com/mcp/company-tools:latest \
  --server docker://registry.example.com/mcp/internal-api:latest \
  --server docker://registry.example.com/mcp/data-pipeline:latest
```

Push when ready:

```console
$ docker mcp catalog push registry.example.com/mcp/company-tools:latest
```

### Build a catalog from scratch

To include exactly what you choose and nothing else, create a catalog from
scratch. You can include servers from the Docker catalog, your own private
images, or both.

Create a catalog and specify which servers to include:

```console
$ docker mcp catalog create registry.example.com/mcp/data-tools:latest \
  --title "Data Analysis Tools" \
  --server catalog://mcp/docker-mcp-catalog/sequentialthinking \
  --server catalog://mcp/docker-mcp-catalog/brave \
  --server docker://registry.example.com/mcp/analytics:latest
```

View the result:

```console
$ docker mcp catalog show registry.example.com/mcp/data-tools:latest
```

Push to distribute:

```console
$ docker mcp catalog push registry.example.com/mcp/data-tools:latest
```

### Distribute a catalog

Push your catalog so team members can import it:

```console
$ docker mcp catalog push <oci-reference>
```

Team members can pull it using the CLI:

```console
$ docker mcp catalog pull <oci-reference>
```

Or import it using Docker Desktop: select **MCP Toolkit** > **Catalog** >
**Import catalog** and enter the OCI reference.

### Use a custom catalog with the gateway

Run the gateway with your catalog instead of the default Docker catalog:

```console
$ docker mcp gateway run --catalog <oci-reference>
```

For [Dynamic MCP](dynamic-mcp.md), where
agents discover and add servers during conversations, this limits what agents
can find to your curated set.

To enable specific servers from your catalog without using a profile:

```console
$ docker mcp gateway run --catalog <oci-reference> \
  --servers <name1> --servers <name2>
```

## Further reading

- [Get started with MCP Toolkit](get-started.md)
- [MCP Profiles](profiles.md)
- [MCP Catalog](catalog.md)
- [MCP Gateway](mcp-gateway.md)


---

# Dynamic MCP

*Sección: Ai*

Dynamic MCP enables AI agents to discover and add MCP servers on-demand during
a conversation, without manual configuration. Instead of pre-configuring every
MCP server before starting your agent session, clients can search the
[MCP Catalog](catalog.md) and add servers
as needed.

This capability is enabled automatically when you connect an MCP client to the
[MCP Toolkit](toolkit.md). The gateway
provides a set of primordial tools that agents use to discover and manage
servers during runtime.

{{% experimental %}}

Dynamic MCP is an experimental feature in early development. While you're
welcome to try it out and explore its capabilities, you may encounter
unexpected behavior or limitations. Feedback is welcome via at [GitHub
issues](https://github.com/docker/mcp-gateway/issues) for bug reports and
[GitHub discussions](https://github.com/docker/mcp-gateway/discussions) for
general questions and feature requests.

{{% /experimental %}}

## How it works

When you connect a client to the MCP Gateway, the gateway exposes a small set
of management tools alongside any MCP servers in your active profile. These
management tools let agents interact with the gateway's configuration:

| Tool             | Description                                                              |
| ---------------- | ------------------------------------------------------------------------ |
| `mcp-find`       | Search for MCP servers in the catalog by name or description             |
| `mcp-add`        | Add a new MCP server to the current session                              |
| `mcp-config-set` | Configure settings for an MCP server                                     |
| `mcp-remove`     | Remove an MCP server from the session                                    |
| `mcp-exec`       | Execute a tool by name that exists in the current session                |
| `code-mode`      | Create a JavaScript-enabled tool that combines multiple MCP server tools |

With these tools available, an agent can search the catalog, add servers,
handle authentication, and use newly added tools directly without requiring a
restart or manual configuration.

Dynamically added servers and tools are associated with your _current session
only_. They're not persisted to your profile. When you start a new session,
only servers you've added to your profile through the
[MCP Toolkit](toolkit.md) or
[Profiles](profiles.md) are available.

## Prerequisites

To use Dynamic MCP, you need:

- Docker Desktop version 4.50 or later, with [MCP Toolkit](toolkit.md) enabled
- An LLM application that supports MCP (such as Claude Desktop, Visual Studio Code, or Claude Code)
- Your client configured to connect to the MCP Gateway

See [Get started with Docker MCP Toolkit](get-started.md)
for setup instructions.

## Usage

Dynamic MCP is enabled automatically when you use the MCP Toolkit. Your
connected clients can now use `mcp-find`, `mcp-add`, and other management tools
during conversations.

To see Dynamic MCP in action, connect your AI client to the Docker MCP Toolkit
and try this prompt:

```plaintext
What MCP servers can I use for working with SQL databases?
```

Given this prompt, your agent will use the `mcp-find` tool provided by MCP
Toolkit to search for SQL-related servers in the [MCP Catalog](catalog.md).

And to add a server to a session, simply write a prompt and the MCP Toolkit
takes care of installing and running the server:

```plaintext
Add the postgres mcp server
```

## Tool composition with code mode

The `code-mode` tool is available as an experimental capability for creating
custom JavaScript functions that combine multiple MCP server tools. The
intended use case is to enable workflows that coordinate multiple services
in a single operation.

> **Note**
>
> Code mode is in early development and is not yet reliable for general use.
> The documentation intentionally omits usage examples at this time.
>
> The core Dynamic MCP capabilities (`mcp-find`, `mcp-add`, `mcp-config-set`,
> `mcp-remove`) work as documented and are the recommended focus for current
> use.

The architecture works as follows:

1. The agent calls `code-mode` with a list of server names and a tool name
2. The gateway creates a sandbox with access to those servers' tools
3. A new tool is registered in the current session with the specified name
4. The agent calls the newly created tool
5. The code executes in the sandbox with access to the specified tools
6. Results are returned to the agent

The sandbox can only interact with the outside world through MCP tools,
which are already running in isolated containers with restricted privileges.

## Security considerations

Dynamic MCP maintains the same security model as static MCP server
configuration in MCP Toolkit:

- All servers in the MCP Catalog are built, signed, and maintained by Docker
- Servers run in isolated containers with restricted resources
- Code mode runs agent-written JavaScript in an isolated sandbox that can only
  interact through MCP tools
- Credentials are managed by the gateway and injected securely into containers

The key difference with dynamic capabilities is that agents can add new tools
during runtime.

## Disabling Dynamic MCP

Dynamic MCP is enabled by default in the MCP Toolkit. If you prefer to use only
statically configured MCP servers, you can disable the dynamic tools feature:

```console
$ docker mcp feature disable dynamic-tools
```

To re-enable the feature later:

```console
$ docker mcp feature enable dynamic-tools
```

After changing this setting, you may need to restart any connected MCP clients.

## Further reading

Check out the [Dynamic MCP servers with Docker](https://docker.com/blog) blog
post for more examples and inspiration on how you can use dynamic tools.


---

# E2B sandboxes

*Sección: Ai*

[E2B](https://e2b.dev/) provides secure cloud sandboxes for AI agents with direct access to Docker's [MCP Catalog](https://hub.docker.com/mcp), a collection of 200+ tools from publishers including GitHub, Notion, and Stripe.

When you create an E2B sandbox, you specify which MCP tools it should access. E2B launches these tools and provides access through the Docker MCP Gateway.

## Example: Using GitHub and Notion MCP server

This example demonstrates how to connect multiple MCP servers in an E2B sandbox. You'll analyze data in Notion and create GitHub issues using Claude.

### Prerequisites

Before you begin, make sure you have the following:

- [E2B account](https://e2b.dev/docs/quickstart) with API access
- Anthropic API key for Claude

  > [!NOTE]
  > This example uses Claude Code, which is pre-installed in E2B sandboxes.
  > However, you can adapt the example to work with other AI assistants of your
  > choice. See [E2B's MCP documentation](https://e2b.dev/docs/mcp/quickstart)
  > for alternative connection methods.

- Node.js 18+ installed on your machine
- Notion account with:
  - A database containing sample data
  - [Integration token](https://www.notion.com/help/add-and-manage-connections-with-the-api)
- GitHub account with:
  - A repository for testing
  - Personal access token with `repo` scope

### Set up your environment

Create a new directory and initialize a Node.js project:

```console
$ mkdir mcp-e2b-quickstart
$ cd mcp-e2b-quickstart
$ npm init -y
```

Configure your project for ES modules by updating `package.json`:

```json
{
  "name": "mcp-e2b-quickstart",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  }
}
```

Install required dependencies:

```console
$ npm install e2b dotenv
```

Create a `.env` file with your credentials:

```console
$ cat > .env << 'EOF'
E2B_API_KEY=your_e2b_api_key_here
ANTHROPIC_API_KEY=your_anthropic_api_key_here
NOTION_INTEGRATION_TOKEN=ntn_your_notion_integration_token_here
GITHUB_TOKEN=ghp_your_github_pat_here
EOF
```

Protect your credentials:

```console
$ echo ".env" >> .gitignore
$ echo "node_modules/" >> .gitignore
```

### Create an E2B sandbox with MCP servers

{{< tabs group="" >}}
{{< tab name="Typescript">}}

Create a file named `index.ts`:

```typescript
import "dotenv/config";
import { Sandbox } from "e2b";

async function quickstart(): Promise<void> {
  console.log("Creating E2B sandbox with Notion and GitHub MCP servers...\n");

  const sbx: Sandbox = await Sandbox.create({
    envs: {
      ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY as string,
    },
    mcp: {
      notion: {
        internalIntegrationToken: process.env
          .NOTION_INTEGRATION_TOKEN as string,
      },
      githubOfficial: {
        githubPersonalAccessToken: process.env.GITHUB_TOKEN as string,
      },
    },
  });

  const mcpUrl = sbx.getMcpUrl();
  const mcpToken = await sbx.getMcpToken();

  console.log("Sandbox created successfully!");
  console.log(`MCP Gateway URL: ${mcpUrl}\n`);

  // Wait for MCP initialization
  await new Promise<void>((resolve) => setTimeout(resolve, 1000));

  // Connect Claude to MCP gateway
  console.log("Connecting Claude to MCP gateway...");
  await sbx.commands.run(
    `claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
    {
      timeoutMs: 0,
      onStdout: console.log,
      onStderr: console.log,
    },
  );

  console.log("\nConnection successful! Cleaning up...");
  await sbx.kill();
}

quickstart().catch(console.error);
```

Run the script:

```console
$ npx tsx index.ts
```

{{< /tab >}}
{{< tab name="Python">}}

Create a file named `index.py`:

```python
import os
import asyncio
from dotenv import load_dotenv
from e2b import Sandbox

load_dotenv()

async def quickstart():
    print("Creating E2B sandbox with Notion and GitHub MCP servers...\n")

    sbx = await Sandbox.beta_create(
        envs={
            "ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
        },
        mcp={
            "notion": {
                "internalIntegrationToken": os.getenv("NOTION_INTEGRATION_TOKEN"),
            },
            "githubOfficial": {
                "githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
            },
        },
    )

    mcp_url = sbx.beta_get_mcp_url()
    mcp_token = await sbx.beta_get_mcp_token()

    print("Sandbox created successfully!")
    print(f"MCP Gateway URL: {mcp_url}\n")

    # Wait for MCP initialization
    await asyncio.sleep(1)

    # Connect Claude to MCP gateway
    print("Connecting Claude to MCP gateway...")

    def on_stdout(output):
        print(output, end='')

    def on_stderr(output):
        print(output, end='')

    await sbx.commands.run(
        f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
        timeout_ms=0,
        on_stdout=on_stdout,
        on_stderr=on_stderr
    )

    print("\nConnection successful! Cleaning up...")
    await sbx.kill()

if __name__ == "__main__":
    try:
        asyncio.run(quickstart())
    except Exception as e:
        print(f"Error: {e}")

```

Run the script:

```console
$ python index.py
```

{{< /tab >}}
{{</tabs >}}

You should see:

```console
Creating E2B sandbox with Notion and GitHub MCP servers...

Sandbox created successfully!
MCP Gateway URL: https://50005-xxxxx.e2b.app/mcp

Connecting Claude to MCP gateway...
Added HTTP MCP server e2b-mcp-gateway with URL: https://50005-xxxxx.e2b.app/mcp

Connection successful! Cleaning up...
```

### Test with example workflow

Now, test the setup by running a simple workflow that searches Notion and creates a GitHub issue.

{{< tabs group="" >}}
{{< tab name="Typescript">}}

> [!IMPORTANT]
>
> Replace `owner/repo` in the prompt with your actual GitHub username and repository
> name (for example, `yourname/test-repo`).

Update `index.ts` with the following example:

```typescript
import "dotenv/config";
import { Sandbox } from "e2b";

async function exampleWorkflow(): Promise<void> {
  console.log("Creating sandbox...\n");

  const sbx: Sandbox = await Sandbox.create({
    envs: {
      ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY as string,
    },
    mcp: {
      notion: {
        internalIntegrationToken: process.env
          .NOTION_INTEGRATION_TOKEN as string,
      },
      githubOfficial: {
        githubPersonalAccessToken: process.env.GITHUB_TOKEN as string,
      },
    },
  });

  const mcpUrl = sbx.getMcpUrl();
  const mcpToken = await sbx.getMcpToken();

  console.log("Sandbox created successfully\n");

  // Wait for MCP servers to initialize
  await new Promise<void>((resolve) => setTimeout(resolve, 3000));

  console.log("Connecting Claude to MCP gateway...\n");
  await sbx.commands.run(
    `claude mcp add --transport http e2b-mcp-gateway ${mcpUrl} --header "Authorization: Bearer ${mcpToken}"`,
    {
      timeoutMs: 0,
      onStdout: console.log,
      onStderr: console.log,
    },
  );

  console.log("\nRunning example: Search Notion and create GitHub issue...\n");

  const prompt: string = `Using Notion and GitHub MCP tools:
1. Search my Notion workspace for databases
2. Create a test issue in owner/repo titled "MCP Toolkit Test" with description "Testing E2B + Docker MCP integration"
3. Confirm both operations completed successfully`;

  await sbx.commands.run(
    `echo '${prompt.replace(/'/g, "'\\''")}' | claude -p --dangerously-skip-permissions`,
    {
      timeoutMs: 0,
      onStdout: console.log,
      onStderr: console.log,
    },
  );

  await sbx.kill();
}

exampleWorkflow().catch(console.error);
```

Run the script:

```console
$ npx tsx index.ts
```

{{< /tab >}}
{{< tab name="Python">}}

Update `index.py` with this example:

> [!IMPORTANT]
>
> Replace `owner/repo` in the prompt with your actual GitHub username and repository
> name (for example, `yourname/test-repo`).

```python
import os
import asyncio
import shlex
from dotenv import load_dotenv
from e2b import Sandbox

load_dotenv()

async def example_workflow():
    print("Creating sandbox...\n")

    sbx = await Sandbox.beta_create(
        envs={
            "ANTHROPIC_API_KEY": os.getenv("ANTHROPIC_API_KEY"),
        },
        mcp={
            "notion": {
                "internalIntegrationToken": os.getenv("NOTION_INTEGRATION_TOKEN"),
            },
            "githubOfficial": {
                "githubPersonalAccessToken": os.getenv("GITHUB_TOKEN"),
            },
        },
    )

    mcp_url = sbx.beta_get_mcp_url()
    mcp_token = await sbx.beta_get_mcp_token()

    print("Sandbox created successfully\n")

    # Wait for MCP servers to initialize
    await asyncio.sleep(3)

    print("Connecting Claude to MCP gateway...\n")

    def on_stdout(output):
        print(output, end='')

    def on_stderr(output):
        print(output, end='')

    await sbx.commands.run(
        f'claude mcp add --transport http e2b-mcp-gateway {mcp_url} --header "Authorization: Bearer {mcp_token}"',
        timeout_ms=0,
        on_stdout=on_stdout,
        on_stderr=on_stderr
    )

    print("\nRunning example: Search Notion and create GitHub issue...\n")

    prompt = """Using Notion and GitHub MCP tools:
1. Search my Notion workspace for databases
2. Create a test issue in owner/repo titled "MCP Toolkit Test" with description "Testing E2B + Docker MCP integration"
3. Confirm both operations completed successfully"""

    # Escape single quotes for shell
    escaped_prompt = prompt.replace("'", "'\\''")

    await sbx.commands.run(
        f"echo '{escaped_prompt}' | claude -p --dangerously-skip-permissions",
        timeout_ms=0,
        on_stdout=on_stdout,
        on_stderr=on_stderr
    )

    await sbx.kill()

if __name__ == "__main__":
    try:
        asyncio.run(example_workflow())
    except Exception as e:
        print(f"Error: {e}")
```

Run the script:

```console
$ python workflow.py
```

{{< /tab >}}
{{</tabs >}}

You should see:

```console
Creating sandbox...

Running example: Search Notion and create GitHub issue...

## Task Completed Successfully

I've completed both operations using the Notion and GitHub MCP tools:

### 1. Notion Workspace Search

Found 3 databases in your Notion workspace:
- **Customer Feedback** - Database with 12 entries tracking feature requests
- **Product Roadmap** - Planning database with 8 active projects
- **Meeting Notes** - Shared workspace with 45 pages

### 2. GitHub Issue Creation

Successfully created test issue:
- **Repository**: your-org/your-repo
- **Issue Number**: #47
- **Title**: "MCP Test"
- **Description**: "Testing E2B + Docker MCP integration"
- **Status**: Open
- **URL**: https://github.com/your-org/your-repo/issues/47

Both operations completed successfully. The MCP servers are properly configured and working.
```

The sandbox connected multiple MCP servers and orchestrated a workflow across Notion and GitHub. You can extend this pattern to combine any of the 200+ MCP servers in the Docker MCP Catalog.

## Related pages

- [How to build an AI-powered code quality workflow with SonarQube and E2B](/guides/github-sonarqube-sandbox.md)
- [Docker + E2B: Building the Future of Trusted AI](https://www.docker.com/blog/docker-e2b-building-the-future-of-trusted-ai/)
- [Docker Sandboxes](../sandboxes/index.md)
- [Docker MCP Toolkit and Catalog](index.md)
- [Docker MCP Gateway](mcp-gateway.md)
- [E2B MCP documentation](https://e2b.dev/docs/mcp)


---

# MCP Toolkit FAQs

*Sección: Ai*

Docker MCP Catalog and Toolkit is a solution for securely building, sharing, and
running MCP tools. This page answers common questions about MCP Catalog and Toolkit security.

### What process does Docker follow to add a new MCP server to the catalog?

Developers can submit a pull request to the [Docker MCP Registry](https://github.com/docker/mcp-registry) to propose new servers. Docker provides detailed [contribution guidelines](https://github.com/docker/mcp-registry/blob/main/CONTRIBUTING.md) to help developers meet the required standards.

Currently, a majority of the servers in the catalog are built directly by Docker. Each server includes attestations such as:

- Build attestation: Servers are built on Docker Build Cloud.
- Source provenance: Verifiable source code origins.
- Signed SBOMs: Software Bill of Materials with cryptographic signatures.

> [!NOTE]
> When using the images with [Docker MCP gateway](mcp-gateway.md),
> you can verify attestations at runtime using the `docker mcp gateway run
--verify-signatures` CLI command.


In addition to Docker-built servers, the catalog includes select servers from trusted registries such as GitHub and HashiCorp. Each third-party server undergoes a verification process that includes:

- Pulling and building the code in an ephemeral build environment.
- Testing initialization and functionality.
- Verifying that tools can be successfully listed.

### Under what conditions does Docker reject MCP server submissions?

Docker rejects MCP server submissions that fail automated testing and validation processes during pull request review. Additionally, Docker reviewers evaluate submissions against specific requirements and reject MCP servers that don't meet these criteria.

### Does Docker take accountability for malicious MCP servers in the Toolkit?

Docker’s security measures currently represent a best-effort approach. While Docker implements automated testing, scanning, and metadata extraction for each server in the catalog, these security measures are not yet exhaustive. Docker is actively working to enhance its security processes and expand testing coverage. Enterprise customers can contact their Docker account manager for specific security requirements and implementation details.

### How are credentials managed for MCP servers?

Starting with Docker Desktop version 4.43.0, credentials are stored securely in the Docker Desktop VM. The storage implementation depends on the platform (for example, macOS, WSL2). You can manage the credentials using the following CLI commands:

- `docker mcp secret ls` - List stored credentials
- `docker mcp secret rm` - Remove specific credentials
- `docker mcp oauth revoke` - Revoke OAuth-based credentials

In the upcoming versions of Docker Desktop, Docker plans to support pluggable storage for these secrets and additional out-of-the-box storage providers to give users more flexibility in managing credentials.

### Are credentials removed when an MCP server is uninstalled?

No. MCP servers are not technically uninstalled since they exist as Docker containers pulled to your local Docker Desktop. Removing an MCP server stops the container but leaves the image on your system. Even if the container is deleted, credentials remain stored until you remove them manually.

### Why don't I see remote MCP servers in the catalog?

If remote MCP servers aren't visible in the Docker Desktop catalog, your local
catalog may be out of date. Remote servers are indicated by a cloud icon and
include services like GitHub, Notion, and Linear.

Update your catalog by running:

```console
$ docker mcp catalog update
```

After the update completes, refresh the **Catalog** tab in Docker Desktop.

### What's the difference between profiles and the catalog?

The [catalog](catalog.md) is the source of
available MCP servers - a library of tools you can choose from.
[Profiles](profiles.md) are collections of
servers you've added to organize your work. Think of the catalog as a library,
and profiles as your personal bookshelves containing the books you've selected
for different purposes.

### Can I share profiles with my team?

Yes. Profiles can be pushed to OCI-compliant registries using
`docker mcp profile push my-profile registry.example.com/profiles/my-profile:v1`.
Team members can pull your profile with
`docker mcp profile pull registry.example.com/profiles/my-profile:v1`. Note
that credentials aren't included in shared profiles for security reasons - team
members need to configure OAuth and other credentials separately.

### Do I need to create a profile to use MCP Toolkit?

Yes, MCP Toolkit requires a profile to run servers. If you're upgrading from a
version before profiles were introduced, a default profile is automatically
created for you with your existing server configurations. You can create
additional named profiles to organize servers for different projects or
environments.

### What happens to servers when I switch profiles?

Each profile contains its own set of servers and configurations. When you run
the gateway with `--profile profile-name`, only servers in that profile are
available to clients. The default profile is used when no profile is specified.
Switching between profiles changes which servers your AI applications can
access.

### Can I use the same server in multiple profiles?

Yes. You can add the same MCP server to multiple profiles, each with different
configurations if needed. This is useful when you need the same server with
different settings for different projects or environments.

## Related pages

- [Get started with MCP Toolkit](get-started.md)
- [Open-source MCP Gateway](mcp-gateway.md)


---

# Get started with Docker MCP Toolkit

*Sección: Ai*

{{< summary-bar feature_name="Docker MCP Toolkit" >}}

> [!NOTE]
> This page describes the MCP Toolkit interface in Docker Desktop 4.62 and
> later. Earlier versions have a different UI. Upgrade to follow these
> instructions exactly.

The Docker MCP Toolkit makes it easy to set up, manage, and run containerized
Model Context Protocol (MCP) servers in profiles, and connect them to AI
agents. It provides secure defaults and support for a growing ecosystem of
LLM-based clients. This page shows you how to get started quickly with the
Docker MCP Toolkit.

## Setup

Before you begin, make sure you meet the following requirements to get started with Docker MCP Toolkit.

1. Download and install the latest version of [Docker Desktop](/get-started/get-docker/).
2. Open the Docker Desktop settings and select **Beta features**.
3. Select **Enable Docker MCP Toolkit**.
4. Select **Apply**.

The **Learning center** in Docker Desktop provides walkthroughs and resources
to help you get started with Docker products and features. On the **MCP
Toolkit** page, the **Get started** walkthrough guides you through installing
an MCP server, connecting a client, and testing your setup.

Alternatively, follow the step-by-step instructions on this page:

- [Create a profile](#create-a-profile) - Your workspace for organizing servers
- [Add MCP servers to your profile](#add-mcp-servers) - Select tools from the catalog
- [Connect clients](#connect-clients) - Link AI applications to your profile
- [Verify connections](#verify-connections) - Test that everything works

Once configured, your AI applications can use all the servers in your profile.

> [!TIP]
> Prefer working from the terminal? See [Use MCP Toolkit from the CLI](cli.md)
> for instructions on using the `docker mcp` commands.

## Create a profile

Profiles organize your MCP servers into collections. Create a profile for your
work:

> [!NOTE]
> If you're upgrading from a previous version of MCP Toolkit, your existing
> server configurations are already in a `default` profile. You can continue
> using the default profile or create new profiles for different projects.

1. In Docker Desktop, select **MCP Toolkit** and select the **Profiles** tab.
2. Select **Create profile**.
3. Enter a name for your profile (e.g., "Frontend development").
4. Optionally, add servers and clients now, or add them later.
5. Select **Create**.

Your new profile appears in the profiles list.

## Add MCP servers

1. In Docker Desktop, select **MCP Toolkit** and select the **Catalog** tab.
2. Browse the catalog and select the servers you want to add.
3. Select the **Add to** button and choose whether you want to add the servers
   to an existing profile, or create a new profile.

If a server requires configuration, a **Configuration Required** badge appears
next to the server's name. You must complete the mandatory configuration before
you can use the server.

You've now successfully added MCP servers to your profile. Next, connect an MCP
client to use the servers in your profile.

## Connect clients

To connect a client to MCP Toolkit:

1. In Docker Desktop, select **MCP Toolkit** and select the **Clients** tab.
2. Find your application in the list.
3. Select **Connect** to configure the client.

If your client isn't listed, you can connect the MCP Toolkit manually over
`stdio` by configuring your client to run the gateway with your profile:

```plaintext
docker mcp gateway run --profile my_profile
```

For example, if your client uses a JSON file to configure MCP servers, you may
add an entry like:

```json {title="Example configuration"
{
  "servers": {
    "MCP_DOCKER": {
      "command": "docker",
      "args": ["mcp", "gateway", "run", "--profile", "my_profile"],
      "type": "stdio"
    }
  }
}
```

Consult the documentation of the application you're using for instructions on
how to set up MCP servers manually.

## Verify connections

Refer to the relevant section for instructions on how to verify that your setup
is working:

- [Claude Code](#claude-code)
- [Claude Desktop](#claude-desktop)
- [OpenAI Codex](#codex)
- [Continue](#continue)
- [Cursor](#cursor)
- [Gemini](#gemini)
- [Goose](#goose)
- [LM Studio](#lm-studio)
- [OpenCode](#opencode)
- [Sema4.ai](#sema4)
- [Visual Studio Code](#vscode)
- [Zed](#zed)
- [Mistral Vibe](#mistral-vibe)

### Claude Code

If you configured the MCP Toolkit for a specific project, navigate to the
relevant project directory. Then run `claude mcp list`. The output should show
`MCP_DOCKER` with a "connected" status:

```console
$ claude mcp list
Checking MCP server health...

MCP_DOCKER: docker mcp gateway run - ✓ Connected
```

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```console
$ claude "{{% param test_prompt %}}"
```

### Claude Desktop

Restart Claude Desktop and check the **Search and tools** menu in the chat
input. You should see the `MCP_DOCKER` server listed and enabled:

![Claude Desktop](images/claude-desktop.avif)

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param test_prompt %}}
```

### Codex

Run `codex mcp list` to view active MCP servers and their statuses. The
`MCP_DOCKER` server should appear in the list with an "enabled" status:

```console
$ codex mcp list
Name        Command  Args             Env  Cwd  Status   Auth
MCP_DOCKER  docker   mcp gateway run  -    -    enabled  Unsupported
```

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```console
$ codex "{{% param test_prompt %}}"
```

### Continue

Launch the Continue terminal UI by running `cn`. Use the `/mcp` command to view
active MCP servers and their statuses. The `MCP_DOCKER` server should appear in
the list with a "connected" status:

```plaintext
   MCP Servers

   ➤ 🟢 MCP_DOCKER (🔧75 📝3)
     🔄 Restart all servers
     ⏹️ Stop all servers
     🔍 Explore MCP Servers
     Back

   ↑/↓ to navigate, Enter to select, Esc to go back
```

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```console
$ cn "{{% param test_prompt %}}"
```

### Cursor

Open Cursor. If you configured the MCP Toolkit for a specific project, open the
relevant project directory. Then navigate to **Cursor Settings > Tools & MCP**.
You should see `MCP_DOCKER` under **Installed MCP Servers**:

![Cursor](images/cursor.avif)

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param test_prompt %}}
```

### Gemini

Run `gemini mcp list` to view active MCP servers and their statuses. The
`MCP_DOCKER` should appear in the list with a "connected" status.

```console
$ gemini mcp list
Configured MCP servers:

✓ MCP_DOCKER: docker mcp gateway run (stdio) - Connected
```

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```console
$ gemini "{{% param test_prompt %}}"
```

### Goose

{{< tabs >}}
{{< tab name="Desktop app" >}}

Open the Goose desktop application and select **Extensions** in the sidebar.
Under **Enabled Extensions**, you should see an extension named `Mcpdocker`:

![Goose desktop app](images/goose.avif)

{{< /tab >}}
{{< tab name="CLI" >}}

Run `goose info -v` and look for an entry named `mcpdocker` under extensions.
The status should show `enabled: true`:

```console
$ goose info -v
…
    mcpdocker:
      args:
      - mcp
      - gateway
      - run
      available_tools: []
      bundled: null
      cmd: docker
      description: The Docker MCP Toolkit allows for easy configuration and consumption of MCP servers from the Docker MCP Catalog
      enabled: true
      env_keys: []
      envs: {}
      name: mcpdocker
      timeout: 300
      type: stdio
```

{{< /tab >}}
{{< /tabs >}}

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param "test_prompt" %}}
```

### LM Studio

Restart LM Studio and start a new chat. Open the integrations menu and look for
an entry named `mcp/mcp-docker`. Use the toggle to enable the server:

![LM Studio](images/lm-studio.avif)

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param "test_prompt" %}}
```

### OpenCode

The OpenCode configuration file (at `~/.config/opencode/opencode.json` by
default) contains the setup for MCP Toolkit:

```json
{
  "mcp": {
    "MCP_DOCKER": {
      "type": "local",
      "command": ["docker", "mcp", "gateway", "run"],
      "enabled": true
    }
  },
  "$schema": "https://opencode.ai/config.json"
}
```

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```console
$ opencode "{{% param "test_prompt" %}}"
```

### Sema4.ai Studio {#sema4}

In Sema4.ai Studio, select **Actions** in the sidebar, then select the **MCP
Servers** tab. You should see Docker MCP Toolkit in the list:

![Docker MCP Toolkit in Sema4.ai Studio](./images/sema4-mcp-list.avif)

To use MCP Toolkit with Sema4.ai, add it as an agent action. Find the agent you
want to connect to the MCP Toolkit and open the agent editor. Select **Add
Action**, enable Docker MCP Toolkit in the list, then save your agent:

![Editing an agent in Sema4.ai Studio](images/sema4-edit-agent.avif)

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param test_prompt %}}
```

### Visual Studio Code {#vscode}

Open Visual Studio Code. If you configured the MCP Toolkit for a specific
project, open the relevant project directory. Then open the **Extensions**
pane. You should see the `MCP_DOCKER` server listed under installed MCP
servers.

![MCP_DOCKER installed in Visual Studio Code](images/vscode-extensions.avif)

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param test_prompt %}}
```

### Zed

Launch Zed and open agent settings:

![Opening Zed agent settings from command palette](images/zed-cmd-palette.avif)

Ensure that `MCP_DOCKER` is listed and enabled in the MCP Servers section:

![MCP_DOCKER in Zed's agent settings](images/zed-agent-settings.avif)

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```plaintext
{{% param test_prompt %}}
```

### Mistral Vibe

Mistral Vibe uses a TOML configuration file at `~/.vibe/config.toml`. Add the
MCP Toolkit as a stdio MCP server in the `[[mcp_servers]]` section:

{{< tabs >}}
{{< tab name="Linux" >}}

```toml
[[mcp_servers]]
name = "MCP_DOCKER"
transport = "stdio"
command = ["docker"]
args = ["mcp", "gateway", "run", "--profile", "my_profile"]
startup_timeout_sec = 60
disabled = false
```

{{< /tab >}}
{{< tab name="macOS" >}}

```toml
[[mcp_servers]]
name = "MCP_DOCKER"
transport = "stdio"
command = ["docker"]
args = ["mcp", "gateway", "run", "--profile", "my_profile"]
startup_timeout_sec = 60
disabled = false
```

{{< /tab >}}
{{< tab name="Windows" >}}

On Windows, the Docker installation path (`C:\Program Files\Docker\...`)
contains a space. Use a list for `command` with the full path to `docker.exe`,
and add `PROGRAMFILES` and `PROGRAMDATA` environment variables that the MCP
Python SDK doesn't inherit by default:

```toml
[[mcp_servers]]
name = "MCP_DOCKER"
transport = "stdio"
command = ["C:/Program Files/Docker/Docker/resources/bin/docker.exe"]
args = ["mcp", "gateway", "run", "--profile", "my_profile"]
env = { PROGRAMFILES = "C:\\Program Files", PROGRAMDATA = "C:\\ProgramData" }
startup_timeout_sec = 60
disabled = false
```

{{< /tab >}}
{{< /tabs >}}

The `startup_timeout_sec = 60` is recommended because the Docker MCP Gateway
takes approximately 15-25 seconds to start. The default timeout is 10 seconds,
which isn't enough for the gateway to initialize.

Restart Vibe. In a Vibe CLI session, run `/mcp` to view active MCP servers.
The `MCP_DOCKER` server should appear in the list:

```console
$ vibe
> /mcp
```

Test the connection by submitting a prompt that invokes one of your installed
MCP servers:

```console
$ vibe "{{% param test_prompt %}}"
```

## Further reading

- [MCP Profiles](profiles.md)
- [MCP Toolkit](toolkit.md)
- [MCP Catalog](catalog.md)
- [MCP Gateway](mcp-gateway.md)


---

# MCP Gateway

*Sección: Ai*

> [!NOTE]
> MCP Gateway as part of Docker AI Governance is an invite-only feature. [Contact Docker Sales](https://www.docker.com/pricing/contact-sales/) to learn more.

The MCP Gateway is Docker's open source solution for orchestrating Model
Context Protocol (MCP) servers. It acts as a centralized proxy between clients
and servers, managing configuration, credentials, and access control.

When using MCP servers without the MCP Gateway, you need to configure
applications individually for each AI application. With the MCP Gateway, you
configure applications to connect to the Gateway. The Gateway then handles
server lifecycle, routing, and authentication across all servers in your
[profiles](profiles.md).

If you use Docker Desktop with MCP Toolkit enabled, the Gateway runs
automatically in the background. You don't need to start or configure it
manually. This documentation is for users who want to understand how the Gateway works or run it directly for advanced use cases.

> [!TIP]
> E2B sandboxes now include direct access to the Docker MCP Catalog, giving developers
> access to over 200 tools and services to seamlessly build and run AI agents. For
> more information, see [E2B Sandboxes](e2b-sandboxes.md).

## How it works

MCP Gateway runs MCP servers in isolated Docker containers with restricted
privileges, network access, and resource usage. It includes built-in logging
and call-tracing capabilities to ensure full visibility and governance of AI
tool activity.

The MCP Gateway manages the server's entire lifecycle. When an AI application
needs to use a tool, it sends a request to the Gateway. The Gateway identifies
which server handles that tool and, if the server isn't already running, starts
it as a Docker container. The Gateway then injects any required credentials,
applies security restrictions, and forwards the request to the server. The
server processes the request and returns the result through the Gateway back to
the AI application.

The MCP Gateway solves a fundamental problem: MCP servers are just programs
that need to run somewhere. Running them directly on your machine means dealing
with installation, dependencies, updates, and security risks. By running them
as containers managed by the Gateway, you get isolation, consistent
environments, and centralized control.

The Gateway works with profiles to determine which servers are available. When
you run the Gateway, you specify which profile to use with the `--profile` flag
to determine which servers are made available to clients.

## Usage

To use the MCP Gateway, you'll need Docker Desktop with MCP Toolkit enabled.
Follow the [MCP Toolkit guide](toolkit.md) to enable and configure servers
through the Docker Desktop interface, or see
[Use MCP Toolkit from the CLI](cli.md) for terminal-based workflows.

### Install the MCP Gateway manually

For Docker Engine without Docker Desktop, you'll need to download and install
the MCP Gateway separately before you can run it.

1. Download the latest binary from the [GitHub releases page](https://github.com/docker/mcp-gateway/releases/latest).

2. Move or symlink the binary to the destination matching your OS:

   | OS      | Binary destination                  |
   | ------- | ----------------------------------- |
   | Linux   | `~/.docker/cli-plugins/docker-mcp`  |
   | macOS   | `~/.docker/cli-plugins/docker-mcp`  |
   | Windows | `%USERPROFILE%\.docker\cli-plugins` |

3. Make the binaries executable:

   ```bash
   $ chmod +x ~/.docker/cli-plugins/docker-mcp
   ```

You can now use the `docker mcp` command:

```bash
docker mcp --help
```

## Additional information

For more details on how the MCP Gateway works and available customization
options, see the complete documentation [on GitHub](https://github.com/docker/mcp-gateway).


---

# MCP Profiles

*Sección: Ai*

{{< summary-bar feature_name="MCP Profiles" >}}

Profiles organize your MCP servers into named collections. Without profiles,
you'd configure servers separately for every AI application you use. Each time
you want to change which servers are available, you'd update Claude Desktop, VS
Code, Cursor, and other tools individually. Profiles solve this by centralizing
your server configurations.

## What profiles do

A profile is a named collection of MCP servers with their configurations and
settings. You select servers from the [MCP
Catalog](catalog.md) (the source of
available servers) and add them to your profiles (your configured server
collections for specific work). Think of the catalog as a library of tools, and
profiles as your toolboxes organized for different jobs.

Your "web-dev" profile might include GitHub, Playwright, and database servers.
Your "data-analysis" profile might include spreadsheet, API, and visualization
servers. Connect different AI clients to different profiles, or switch between
profiles as you change tasks.

When you run the MCP Gateway or connect a client without specifying a profile,
Docker MCP uses your default profile. If you're upgrading from a previous
version of MCP Toolkit, your existing server configurations are already in the
default profile.

## Profile capabilities

Each profile maintains its own isolated collection of servers and
configurations. Your "web-dev" profile might include GitHub, Playwright, and
database servers, while your "data-analysis" profile includes spreadsheet, API,
and visualization servers. Create as many profiles as you need, each containing
only the servers relevant to that context.

> [!NOTE]
>
> OAuth credentials are an exception to profile isolation — they are shared
> across all profiles. If you need to use different accounts for different
> projects, revoke and re-authorize when switching profiles.

You can connect different AI applications to different profiles. When you
connect a client, you specify which profile it should use. This means Claude
Desktop and VS Code can have access to different server collections if needed.

Profiles can be shared with your team. Push a profile to your registry, and
team members can pull it to get the exact same server collection and
configuration you use.

## Creating and managing profiles

### Create a profile

1. In Docker Desktop, select **MCP Toolkit** and select the **Profiles** tab.
2. Select **Create profile**.
3. Enter a name for your profile (e.g., "web-dev").
4. Optionally, search and add servers to your profile now, or add them later.
5. Optionally, search and add clients to connect to your profile.
6. Select **Create**.

Your new profile appears in the profiles list.

### View profile details

Select a profile in the **Profiles** tab to view its details. The profile view
has two tabs:

- **Overview**: Shows the servers in your profile, secrets configuration, and
  connected clients. Use the **+** buttons to add more servers or clients.
- **Tools**: Lists all available tools from your profile's servers. You can
  enable or disable individual tools.

### Remove a profile

1. In the **Profiles** tab, find the profile you want to remove.
2. Select ⋮ next to the profile name, and then **Delete**.
3. Confirm the removal.

> [!CAUTION]
> Removing a profile deletes all its server configurations and settings, and
> updates the client configuration (removes MCP Toolkit). This action can't be
> undone.

### Default profile

When you run the MCP Gateway or use MCP Toolkit without specifying a profile,
Docker MCP uses a profile named `default`, or an empty configuration if a
`default` profile does not exist.

If you're upgrading from a previous version of MCP Toolkit, your existing
server configurations automatically migrate to the `default` profile. You don't
need to manually recreate your setup - everything continues to work as before.

You can always specify a different profile using the `--profile` flag with the
gateway command:

```console
$ docker mcp gateway run --profile web-dev
```

## Adding servers to profiles

Profiles contain the MCP servers you select from the catalog. Add servers to
organize your tools for specific workflows.

### Add a server

You can add servers to a profile in two ways.

From the Catalog tab:

1. Select the **Catalog** tab.
2. Select the checkbox next to servers you want to add to see which profile to
   add them to.
3. Choose your profile from the drop-down.

From within a profile:

1. Select the **Profiles** tab and select your profile.
2. In the **Servers** section, select the **+** button.
3. Search for and select servers to add.

If a server requires OAuth authentication, you're prompted to authorize it. See
[OAuth authentication](toolkit.md#oauth-authentication)
for details.

### List servers in a profile

Select a profile in the **Profiles** tab to see all servers it contains.

### Remove a server

1. Select the **Profiles** tab and select your profile.
2. In the **Servers** section, find the server you want to remove.
3. Select the delete icon next to the server.

## Configuring profiles

### Server configuration

Some servers require configuration beyond authentication. Configure server
settings within your profile.

1. Select the **Profiles** tab and select your profile.
2. In the **Servers** section, select the configure icon next to the server.
3. Adjust the server's configuration settings as needed.

### OAuth credentials

OAuth credentials are shared across all profiles. When you authorize access to
a service like GitHub or Notion, that authorization is available to any server
in any profile that needs it.

This means all profiles use the same OAuth credentials for a given service. If
you need to use different accounts for different projects, you'll need to
revoke and re-authorize between switching profiles.

See [OAuth authentication](toolkit.md#oauth-authentication)
for details on authorizing servers.

### Configuration persistence

Profile configurations persist in your Docker installation. When you restart
Docker Desktop or your system, your profiles, servers, and configurations
remain intact.

## Sharing profiles

Profiles can be shared with your team by pushing them to OCI-compliant
registries as artifacts. This is useful for distributing standardized MCP
setups across your organization. Credentials are not included in shared
profiles for security reasons. Team members configure OAuth separately after
pulling.

### Push a profile

1. Select the profile you want to share in the **Profiles** tab.
2. Select **Push to Registry**.
3. Enter the registry destination (e.g., `registry.example.com/profiles/web-dev:v1`).
4. Complete authentication if required.

### Pull a profile

1. Select **Pull from Registry** in the **Profiles** tab.
2. Enter the registry reference (e.g., `registry.example.com/profiles/team-standard:latest`).
3. Complete authentication if required.

The profile is downloaded and added to your profiles list. Configure any
required OAuth credentials separately.

### Team collaboration workflow

A typical workflow for sharing profiles across a team:

1. Create and configure a profile with the servers your team needs.
2. Test the profile to ensure it works as expected.
3. Push the profile to your team's registry with a version tag (e.g.,
   `registry.example.com/profiles/team-dev:v1`).
4. Share the registry reference with your team.
5. Team members pull the profile and configure any required OAuth credentials.

This ensures everyone uses the same server collection and configuration,
reducing setup time and inconsistencies.

## Using profiles with clients

When you connect an AI client to the MCP Gateway, you specify which profile's
servers the client can access.

### Run the gateway with a profile

Connect clients to your profile through the **Clients** section in the MCP
Toolkit. You can add clients when creating a profile or add them to existing
profiles later.

### Configure clients for specific profiles

When setting up a client manually, you can specify which profile the client
uses. This lets different clients connect to different profiles.

For example, your Claude Desktop configuration might use:

```json
{
  "mcpServers": {
    "MCP_DOCKER": {
      "command": "docker",
      "args": ["mcp", "gateway", "run", "--profile", "claude-work"]
    }
  }
}
```

While your VS Code configuration uses a different profile:

```json
{
  "mcp": {
    "servers": {
      "MCP_DOCKER": {
        "command": "docker",
        "args": ["mcp", "gateway", "run", "--profile", "vscode-dev"],
        "type": "stdio"
      }
    }
  }
}
```

### Switching between profiles

To switch the profile your clients use, update the client configuration to
specify a different `--profile` value in the gateway command arguments.

## Further reading

- [Get started with MCP Toolkit](get-started.md)
- [Use MCP Toolkit from the CLI](cli.md)
- [MCP Catalog](catalog.md)
- [MCP Toolkit](toolkit.md)


---

# Docker MCP Toolkit

*Sección: Ai*

{{< summary-bar feature_name="Docker MCP Toolkit" >}}

> [!NOTE]
> This page describes the MCP Toolkit interface in Docker Desktop 4.62 and
> later. Earlier versions have a different UI. Upgrade to follow these
> instructions exactly.

The Docker MCP Toolkit is a management interface integrated into Docker Desktop
that lets you set up, manage, and run containerized MCP servers in profiles and
connect them to AI agents. It removes friction from tool usage by offering
secure defaults, easy setup, and support for a growing ecosystem of LLM-based
clients. It is the fastest way from MCP tool discovery to local execution.

## Key features

- Cross-LLM compatibility: Works with Claude, Cursor, and other MCP clients.
- Integrated tool discovery: Browse and launch MCP servers from the Docker MCP Catalog directly in Docker Desktop.
- Zero manual setup: No dependency management, runtime configuration, or setup required.
- Profile-based organization: Create separate server collections for different projects or environments.
- Organizes MCP servers into profiles, acting as a gateway for clients to access the servers in each profile.

> [!TIP]
> The MCP Toolkit includes [Dynamic MCP](dynamic-mcp.md),
> which enables AI agents to discover, add, and compose MCP servers on-demand during
> conversations, without manual configuration. Your agent can search the catalog and
> add tools as needed when you connect to the gateway.

## How the MCP Toolkit works

MCP introduces two core concepts: MCP clients and MCP servers.

- MCP clients are typically embedded in LLM-based applications, such as the
  Claude Desktop app. They request resources or actions.
- MCP servers are launched by the client to perform the requested tasks, using
  any necessary tools, languages, or processes.

Docker standardizes the development, packaging, and distribution of
applications, including MCP servers. By packaging MCP servers as containers,
Docker eliminates issues related to isolation and environment differences. You
can run a container directly, without managing dependencies or configuring
runtimes.

Depending on the MCP server, the tools it provides might run within the same
container as the server or in dedicated containers for better isolation.

The MCP Toolkit organizes servers into profiles: named collections of servers
with their configurations. This lets you maintain different server setups for
different projects or environments. When you connect a client, you specify
which profile it should use.

## Security

The Docker MCP Toolkit combines passive and active measures to reduce attack
surfaces and ensure safe runtime behavior.

### Passive security

Passive security refers to measures implemented at build-time, when the MCP
server code is packaged into a Docker image.

- Image signing and attestation: All MCP server images under `mcp/` in the [MCP
  Catalog](catalog.md) are built by Docker and digitally signed to verify their
  source and integrity. Each image includes a Software Bill of Materials (SBOM)
  for full transparency.

### Active security

Active security refers to security measures at runtime, before and after tools
are invoked, enforced through resource and access limitations.

- CPU allocation: MCP tools are run in their own container. They are
  restricted to 1 CPU, limiting the impact of potential misuse of computing
  resources.

- Memory allocation: Containers for MCP tools are limited to 2 GB.

- Filesystem access: By default, MCP Servers have no access to the host filesystem.
  The user explicitly selects the servers that will be granted file mounts.

- Interception of tool requests: Requests to and from tools that contain sensitive
  information such as secrets are blocked.

### OAuth authentication

Some MCP servers require authentication to access external services like
GitHub, Notion, and Linear. The MCP Toolkit handles OAuth authentication
automatically. You authorize access through your browser, and the Toolkit
manages credentials securely. You don't need to manually create API tokens or
configure authentication for each service.

#### Authorize a server with OAuth

1. In Docker Desktop, go to **MCP Toolkit** and select the **Catalog** tab.
2. Find and add an MCP server that requires OAuth.
3. In the server's **Configuration** tab, select the **OAuth** authentication
   method. Follow the link to begin the OAuth authorization.
4. Your browser opens the authorization page for the service. Follow the
   on-screen instructions to complete authentication.
5. Return to Docker Desktop when authentication is complete.

View all authorized services in the **OAuth** tab. To revoke access, select
**Revoke** next to the service you want to disconnect.

## Usage examples

### Example: Use Claude Desktop as a client

Imagine you have Claude Desktop installed, and you want to use the GitHub MCP
server and the Puppeteer MCP server. You do not have to install the servers in
Claude Desktop. You can add these 2 MCP servers to your profile in the MCP
Toolkit and connect Claude Desktop as a client:

1. From the **MCP Toolkit** menu, select the **Catalog** tab and find the **Puppeteer** server and add it to your profile.
1. Repeat for the **GitHub Official** server.
1. From the **Clients** tab, select **Connect** next to **Claude Desktop**. Restart
   Claude Desktop if it's running, and it can now access all the servers in the MCP Toolkit.
1. Within Claude Desktop, run a test by submitting the following prompt using the Sonnet 3.5 model:

   ```text
   Take a screenshot of docs.docker.com and then invert the colors
   ```

### Example: Use Visual Studio Code as a client

You can interact with all your installed MCP servers in Visual Studio Code:

1. To enable the MCP Toolkit:

   {{< tabs group="" >}}
   {{< tab name="Enable globally">}}
   1. Insert the following in your Visual Studio Code's User `mcp.json`:

      ```json
      "mcp": {
       "servers": {
         "MCP_DOCKER": {
           "command": "docker",
           "args": [
             "mcp",
             "gateway",
             "run",
             "--profile",
             "my_profile"
           ],
           "type": "stdio"
         }
       }
      }
      ```

   {{< /tab >}}
   {{< tab name="Enable for a given project">}}
   1. In your terminal, navigate to your project's folder.
   1. Run:

      ```bash
      docker mcp client connect vscode --profile my_profile
      ```

      > [!NOTE]
      > This command creates a `.vscode/mcp.json` file in the current directory
      > that connects VSCode to your profile. As this is a user-specific file,
      > add it to your `.gitignore` file to prevent it from being committed to
      > the repository.
      >
      > ```console
      > echo ".vscode/mcp.json" >> .gitignore
      > ```

{{< /tab >}}
{{</tabs >}}

1. In Visual Studio Code, open a new Chat and select the **Agent** mode:

   ![Copilot mode switching](./images/copilot-mode.png)

1. You can also check the available MCP tools:

   ![Displaying tools in VSCode](./images/tools.png)

For more information about the Agent mode, see the
[Visual Studio Code documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers#_use-mcp-tools-in-agent-mode).

## Further reading

- [Use MCP Toolkit from the CLI](cli.md)
- [MCP Catalog](catalog.md)
- [MCP Gateway](mcp-gateway.md)


---

# Docker Model Runner

*Sección: Ai*

{{< summary-bar feature_name="Docker Model Runner" >}}

Docker Model Runner (DMR) makes it easy to manage, run, and
deploy AI models using Docker. Designed for developers,
Docker Model Runner streamlines the process of pulling, running, and serving
large language models (LLMs) and other AI models directly from Docker Hub,
any OCI-compliant registry, or [Hugging Face](https://huggingface.co/).

With seamless integration into Docker Desktop and Docker
Engine, you can serve models via OpenAI and Ollama-compatible APIs, package GGUF files as
OCI Artifacts, and interact with models from both the command line and graphical
interface.

Whether you're building generative AI applications, experimenting with machine
learning workflows, or integrating AI into your software development lifecycle,
Docker Model Runner provides a consistent, secure, and efficient way to work
with AI models locally.

## Key features

- [Pull and push models to and from Docker Hub or any OCI-compliant registry](https://hub.docker.com/u/ai)
- [Pull models from Hugging Face](https://huggingface.co/)
- Serve models on [OpenAI and Ollama-compatible APIs](api-reference.md) for easy integration with existing apps
- Support for [llama.cpp, vLLM, and Diffusers inference engines](inference-engines.md) (vLLM and Diffusers on Linux with NVIDIA GPUs)
- [Generate images from text prompts](inference-engines.md#diffusers) using Stable Diffusion models with the Diffusers backend
- Package GGUF and Safetensors files as OCI Artifacts and publish them to any Container Registry
- Run and interact with AI models directly from the command line or from the Docker Desktop GUI
- [Connect to AI coding tools](ide-integrations.md) like Cline, Continue, Cursor, and Aider
- [Configure context size and model parameters](configuration.md) to tune performance
- [Set up Open WebUI](openwebui-integration.md) for a ChatGPT-like web interface
- Manage local models and display logs
- Display prompt and response details
- Conversational context support for multi-turn interactions

## Requirements

Docker Model Runner is supported on the following platforms:

{{< tabs >}}
{{< tab name="Windows">}}

Windows(amd64):
-  NVIDIA GPUs
-  NVIDIA drivers 576.57+

Windows(arm64):
- OpenCL for Adreno
- Qualcomm Adreno GPU (6xx series and later)

  > [!NOTE]
  > Some llama.cpp features might not be fully supported on the 6xx series.

{{< /tab >}}
{{< tab name="MacOS">}}

- Apple Silicon

{{< /tab >}}
{{< tab name="Linux">}}

Docker Engine only:

- Supports CPU, NVIDIA (CUDA), AMD (ROCm), and Vulkan backends
- Requires NVIDIA driver 575.57.08+ when using NVIDIA GPUs

{{< /tab >}}
{{</tabs >}}

## How Docker Model Runner works

Models are pulled from Docker Hub, an OCI-compliant registry, or
[Hugging Face](https://huggingface.co/) the first time you use them and are
stored locally. They load into memory only at runtime when a request is made,
and unload when not in use to optimize resources. Because models can be large,
the initial pull may take some time. After that, they're cached locally for
faster access. You can interact with the model using
[OpenAI and Ollama-compatible APIs](api-reference.md).

### Inference engines

Docker Model Runner supports three inference engines:

| Engine | Best for | Model format |
|--------|----------|--------------|
| [llama.cpp](inference-engines.md#llamacpp) | Local development, resource efficiency | GGUF (quantized) |
| [vLLM](inference-engines.md#vllm) | Production, high throughput | Safetensors |
| [Diffusers](inference-engines.md#diffusers) | Image generation (Stable Diffusion) | Safetensors |

llama.cpp is the default engine and works on all platforms. vLLM requires NVIDIA GPUs and is supported on Linux x86_64 and Windows with WSL2. Diffusers enables image generation and requires NVIDIA GPUs on Linux (x86_64 or ARM64). See [Inference engines](inference-engines.md) for detailed comparison and setup.

### Context size

Models have a configurable context size (context length) that determines how many tokens they can process. The default varies by model but is typically 2,048-8,192 tokens. You can adjust this per-model:

```console
$ docker model configure --context-size 8192 ai/qwen2.5-coder
```

See [Configuration options](configuration.md) for details on context size and other parameters.

> [!TIP]
>
> Using Testcontainers or Docker Compose?
> [Testcontainers for Java](https://java.testcontainers.org/modules/docker_model_runner/)
> and [Go](https://golang.testcontainers.org/modules/dockermodelrunner/), and
> [Docker Compose](../compose/models-and-compose.md) support Docker
> Model Runner.

## Security and isolation

### Execution environment

Docker Model Runner isolates inference engines from your host:

- On Linux, Docker Model Runner and its inference engines, such as Diffusers,
  run inside a container, which provides the isolation boundary.
- On macOS and Windows, the engines don't run inside a container, so Docker
  Model Runner runs them in a sandboxed environment (seatbelt/sandbox-exec and Job Objects respectively)

### Networking

The Model Runner API is not authenticated. Any client that can reach it,
including other containers on the same Docker network, can pull, load, and
run models, and send inference requests.

## Known issues

### `docker model` is not recognised

If you run a Docker Model Runner command and see:

```text
docker: 'model' is not a docker command
```

It means Docker can't find the plugin because it's not in the expected CLI plugins directory.

To fix this, create a symlink so Docker can detect it:

```console
$ ln -s /Applications/Docker.app/Contents/Resources/cli-plugins/docker-model ~/.docker/cli-plugins/docker-model
```

Once linked, rerun the command.

## Privacy and data collection

Docker Model Runner respects your privacy settings in Docker Desktop. Data collection is controlled by the **Send usage statistics** setting:

- **Disabled**: No usage data is collected
- **Enabled**: Only minimal, non-personal data is collected:
  - [Model names](https://github.com/docker/model-runner/blob/eb76b5defb1a598396f99001a500a30bbbb48f01/pkg/metrics/metrics.go#L96) (via HEAD requests to Docker Hub)
  - User agent information
  - Whether requests originate from the host or containers

When using Docker Model Runner with Docker Engine, HEAD requests to Docker Hub are made to track model names, regardless of any settings.

No prompt content, responses, or personally identifiable information is ever collected.

## Share feedback

Thanks for trying out Docker Model Runner. To report bugs or request features, [open an issue on GitHub](https://github.com/docker/model-runner/issues). You can also give feedback through the **Give feedback** link next to the **Enable Docker Model Runner** setting.

## Next steps

- [Get started with DMR](get-started.md) - Enable DMR and run your first model
- [API reference](api-reference.md) - OpenAI and Ollama-compatible API documentation
- [Configuration options](configuration.md) - Context size and runtime parameters
- [Inference engines](inference-engines.md) - llama.cpp, vLLM, and Diffusers details
- [IDE integrations](ide-integrations.md) - Connect Cline, Continue, Cursor, and more
- [Open WebUI integration](openwebui-integration.md) - Set up a web chat interface


---

# DMR REST API

*Sección: Ai*

Once Model Runner is enabled, new API endpoints are available. You can use
these endpoints to interact with a model programmatically. Docker Model Runner
provides compatibility with OpenAI, Anthropic, and Ollama API formats.

## Determine the base URL

The base URL to interact with the endpoints depends on how you run Docker and
which API format you're using.

{{< tabs >}}
{{< tab name="Docker Desktop">}}

| Access from | Base URL |
|-------------|----------|
| Containers | `http://model-runner.docker.internal` |
| Host processes (TCP) | `http://localhost:12434` |

> [!NOTE]
> TCP host access must be enabled. See [Enable Docker Model Runner](get-started.md#enable-docker-model-runner-in-docker-desktop).

{{< /tab >}}
{{< tab name="Docker Engine">}}

| Access from | Base URL |
|-------------|----------|
| Containers | `http://172.17.0.1:12434` |
| Host processes | `http://localhost:12434` |

> [!NOTE]
> The `172.17.0.1` interface may not be available by default to containers
  within a Compose project.
> In this case, add an `extra_hosts` directive to your Compose service YAML:
>
> ```yaml
> extra_hosts:
>   - "model-runner.docker.internal:host-gateway"
> ```
> Then you can access the Docker Model Runner APIs at `http://model-runner.docker.internal:12434/`

{{< /tab >}}
{{</tabs >}}

### Base URLs for third-party tools

When configuring third-party tools that expect OpenAI-compatible APIs, use these base URLs:

| Tool type | Base URL format |
|-----------|-----------------|
| OpenAI SDK / clients | `http://localhost:12434/engines/v1` |
| Anthropic SDK / clients | `http://localhost:12434` |
| Ollama-compatible clients | `http://localhost:12434` |

See [IDE and tool integrations](ide-integrations.md) for specific configuration examples.

## Supported APIs

Docker Model Runner supports multiple API formats:

| API | Description | Use case |
|-----|-------------|----------|
| [OpenAI API](#openai-compatible-api) | OpenAI-compatible chat completions, embeddings | Most AI frameworks and tools |
| [Anthropic API](#anthropic-compatible-api) | Anthropic-compatible messages endpoint | Tools built for Claude |
| [Ollama API](#ollama-compatible-api) | Ollama-compatible endpoints | Tools built for Ollama |
| [Image Generation API](#image-generation-api-diffusers) | Diffusers-based image generation | Generating images from text prompts |
| [DMR API](#dmr-native-endpoints) | Native Docker Model Runner endpoints | Model management |

## OpenAI-compatible API

DMR implements the OpenAI API specification for maximum compatibility with existing tools and frameworks.

### Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/engines/v1/models` | GET | [List models](https://platform.openai.com/docs/api-reference/models/list) |
| `/engines/v1/models/{namespace}/{name}` | GET | [Retrieve model](https://platform.openai.com/docs/api-reference/models/retrieve) |
| `/engines/v1/chat/completions` | POST | [Create chat completion](https://platform.openai.com/docs/api-reference/chat/create) |
| `/engines/v1/completions` | POST | [Create completion](https://platform.openai.com/docs/api-reference/completions/create) |
| `/engines/v1/embeddings` | POST | [Create embeddings](https://platform.openai.com/docs/api-reference/embeddings/create) |

> [!NOTE]
> You can optionally include the engine name in the path: `/engines/llama.cpp/v1/chat/completions`.
> This is useful when running multiple inference engines.

### Model name format

When specifying a model in API requests, use the full model identifier including the namespace:

```json
{
  "model": "ai/smollm2",
  "messages": [...]
}
```

Common model name formats:
- Docker Hub models: `ai/smollm2`, `ai/llama3.2`, `ai/qwen2.5-coder`
- Tagged versions: `ai/smollm2:360M-Q4_K_M`
- Custom models: `myorg/mymodel`

### Supported parameters

The following OpenAI API parameters are supported:

| Parameter | Type | Description |
|-----------|------|-------------|
| `model` | string | Required. The model identifier. |
| `messages` | array | Required for chat completions. The conversation history. |
| `prompt` | string | Required for completions. The prompt text. |
| `max_tokens` | integer | Maximum tokens to generate. |
| `temperature` | float | Sampling temperature (0.0-2.0). |
| `top_p` | float | Nucleus sampling parameter (0.0-1.0). |
| `stream` | Boolean | Enable streaming responses. |
| `stop` | string/array | Stop sequences. |
| `presence_penalty` | float | Presence penalty (-2.0 to 2.0). |
| `frequency_penalty` | float | Frequency penalty (-2.0 to 2.0). |

### Limitations and differences from OpenAI

Be aware of these differences when using DMR's OpenAI-compatible API:

| Feature | DMR behavior |
|---------|--------------|
| API key | Not required. DMR ignores the `Authorization` header. |
| Function calling | Supported with llama.cpp for compatible models. |
| Vision | Supported for multi-modal models (e.g., LLaVA). |
| JSON mode | Supported via `response_format: {"type": "json_object"}`. |
| Logprobs | Supported. |
| Token counting | Uses the model's native token encoder, which may differ from OpenAI's. |

## Anthropic-compatible API

DMR provides [Anthropic Messages API](https://platform.claude.com/docs/en/api/messages) compatibility for tools and frameworks built for Claude.

### Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/anthropic/v1/messages` | POST | [Create a message](https://platform.claude.com/docs/en/api/messages/create) |
| `/anthropic/v1/messages/count_tokens` | POST | [Count tokens](https://docs.anthropic.com/en/api/messages-count-tokens) |

### Supported parameters

The following Anthropic API parameters are supported:

| Parameter | Type | Description |
|-----------|------|-------------|
| `model` | string | Required. The model identifier. |
| `messages` | array | Required. The conversation messages. |
| `max_tokens` | integer | Maximum tokens to generate. |
| `temperature` | float | Sampling temperature (0.0-1.0). |
| `top_p` | float | Nucleus sampling parameter. |
| `top_k` | integer | Top-k sampling parameter. |
| `stream` | Boolean | Enable streaming responses. |
| `stop_sequences` | array | Custom stop sequences. |
| `system` | string | System prompt. |

### Example: Chat with Anthropic API

```bash
curl http://localhost:12434/v1/messages \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ai/smollm2",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Hello!"}
    ]
  }'
```

### Example: Streaming response

```bash
curl http://localhost:12434/v1/messages \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ai/smollm2",
    "max_tokens": 1024,
    "stream": true,
    "messages": [
      {"role": "user", "content": "Count from 1 to 10"}
    ]
  }'
```

## Ollama-compatible API

DMR also provides Ollama-compatible endpoints for tools and frameworks built for Ollama.

### Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/api/tags` | GET | List available models |
| `/api/show` | POST | Show model information |
| `/api/chat` | POST | Generate chat completion |
| `/api/generate` | POST | Generate completion |
| `/api/embeddings` | POST | Generate embeddings |

### Example: Chat with Ollama API

```bash
curl http://localhost:12434/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ai/smollm2",
    "messages": [
      {"role": "user", "content": "Hello!"}
    ]
  }'
```

### Example: List models

```bash
curl http://localhost:12434/api/tags
```

## Image generation API (Diffusers)

DMR supports image generation through the Diffusers backend, enabling you to generate
images from text prompts using models like Stable Diffusion.

> [!NOTE]
> The Diffusers backend requires an NVIDIA GPU with CUDA support and is only
> available on Linux (x86_64 and ARM64). See [Inference engines](inference-engines.md#diffusers)
> for setup instructions.

### Endpoint

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/engines/diffusers/v1/images/generations` | POST | Generate an image from a text prompt |

### Supported parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `model` | string | Required. The model identifier (e.g., `stable-diffusion:Q4`). |
| `prompt` | string | Required. The text description of the image to generate. |
| `size` | string | Image dimensions in `WIDTHxHEIGHT` format (e.g., `512x512`). |

### Response format

The API returns a JSON response with the generated image encoded in base64:

```json
{
  "data": [
    {
      "b64_json": "<base64-encoded-image-data>"
    }
  ]
}
```

### Example: Generate an image

```bash
curl -s -X POST http://localhost:12434/engines/diffusers/v1/images/generations \
  -H "Content-Type: application/json" \
  -d '{
    "model": "stable-diffusion:Q4",
    "prompt": "A picture of a nice cat",
    "size": "512x512"
  }' | jq -r '.data[0].b64_json' | base64 -d > image.png
```

This command:
1. Sends a POST request to the Diffusers image generation endpoint
2. Specifies the model, prompt, and output image size
3. Extracts the base64-encoded image from the response using `jq`
4. Decodes the base64 data and saves it as `image.png`


## DMR native endpoints

These endpoints are specific to Docker Model Runner for model management:

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/models/create` | POST | Pull/create a model |
| `/models` | GET | List local models |
| `/models/{namespace}/{name}` | GET | Get model details |
| `/models/{namespace}/{name}` | DELETE | Delete a local model |

## REST API examples

### Request from within a container

To call the `chat/completions` OpenAI endpoint from within another container using `curl`:

```bash
#!/bin/sh

curl http://model-runner.docker.internal/engines/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "ai/smollm2",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user",
                "content": "Please write 500 words about the fall of Rome."
            }
        ]
    }'

```

### Request from the host using TCP

To call the `chat/completions` OpenAI endpoint from the host via TCP:

1. Enable the host-side TCP support from the Docker Desktop GUI, or via the [Docker Desktop CLI](../../desktop/features/desktop-cli.md).
   For example: `docker desktop enable model-runner --tcp <port>`.

   If you are running on Windows, also enable GPU-backed inference.
   See [Enable Docker Model Runner](get-started.md#enable-docker-model-runner-in-docker-desktop).

1. Interact with it as documented in the previous section using `localhost` and the correct port.

```bash
#!/bin/sh

curl http://localhost:12434/engines/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
      "model": "ai/smollm2",
      "messages": [
          {
              "role": "system",
              "content": "You are a helpful assistant."
          },
          {
              "role": "user",
              "content": "Please write 500 words about the fall of Rome."
          }
      ]
  }'
```

### Request from the host using a Unix socket

To call the `chat/completions` OpenAI endpoint through the Docker socket from the host using `curl`:

```bash
#!/bin/sh

curl --unix-socket $HOME/.docker/run/docker.sock \
    localhost/exp/vDD4.40/engines/v1/chat/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "ai/smollm2",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user",
                "content": "Please write 500 words about the fall of Rome."
            }
        ]
    }'
```

### Streaming responses

To receive streaming responses, set `stream: true`:

```bash
curl http://localhost:12434/engines/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
      "model": "ai/smollm2",
      "stream": true,
      "messages": [
          {"role": "user", "content": "Count from 1 to 10"}
      ]
  }'
```

## Using with OpenAI SDKs

### Python

```python
from openai import OpenAI

client = OpenAI(
    base_url="http://localhost:12434/engines/v1",
    api_key="not-needed"  # DMR doesn't require an API key
)

response = client.chat.completions.create(
    model="ai/smollm2",
    messages=[
        {"role": "user", "content": "Hello!"}
    ]
)

print(response.choices[0].message.content)
```

### Node.js

```javascript
import OpenAI from 'openai';

const client = new OpenAI({
  baseURL: 'http://localhost:12434/engines/v1',
  apiKey: 'not-needed',
});

const response = await client.chat.completions.create({
  model: 'ai/smollm2',
  messages: [{ role: 'user', content: 'Hello!' }],
});

console.log(response.choices[0].message.content);
```

## What's next

- [IDE and tool integrations](ide-integrations.md) - Configure Cline, Continue, Cursor, and other tools
- [Configuration options](configuration.md) - Adjust context size and runtime parameters
- [Inference engines](inference-engines.md) - Learn about llama.cpp, vLLM, and Diffusers options


---

# Configuration options

*Sección: Ai*

Docker Model Runner provides several configuration options to tune model behavior,
memory usage, and inference performance. This guide covers the key settings and
how to apply them.

## Context size (context length)

The context size determines the maximum number of tokens a model can process in
a single request, including both the input prompt and generated output. This is
one of the most important settings affecting memory usage and model capabilities.

### Default context size

By default, Docker Model Runner uses a context size that balances capability with
resource efficiency:

| Engine | Default behavior |
|--------|------------------|
| llama.cpp | 4096 tokens |
| vLLM | Uses the model's maximum trained context size |

> [!NOTE]
> The actual default varies by model. Most models support between 2,048 and 8,192
> tokens by default. Some newer models support 32K, 128K, or even larger contexts.

### Configure context size

You can adjust context size per model using the `docker model configure` command:

```console
$ docker model configure --context-size 8192 ai/qwen2.5-coder
```

Or in a Compose file:

```yaml
models:
  llm:
    model: ai/qwen2.5-coder
    context_size: 8192
```

### Context size guidelines

| Context size | Typical use case | Memory impact |
|--------------|------------------|---------------|
| 2,048 | Simple queries, short code snippets | Low |
| 4,096 | Standard conversations, medium code files | Moderate |
| 8,192 | Long conversations, larger code files | Higher |
| 16,384+ | Extended documents, multi-file context | High |

> [!IMPORTANT]
> Larger context sizes require more memory (RAM/VRAM). If you experience out-of-memory
> errors, reduce the context size. As a rough guide, each additional 1,000 tokens
> requires approximately 100-500 MB of additional memory, depending on the model size.

### Check a model's maximum context

To see a model's configuration including context size:

```console
$ docker model inspect ai/qwen2.5-coder
```

> [!NOTE]
> The `docker model inspect` command shows the model's maximum supported context length
> (e.g., `gemma3.context_length`), not the configured context size. The configured context
> size is what you set with `docker model configure --context-size` and represents the
> actual limit used during inference, which should be less than or equal to the model's
> maximum supported context length.

## Runtime flags

Runtime flags let you pass parameters directly to the underlying inference engine.
This provides fine-grained control over model behavior.

### Using runtime flags

Runtime flags can be provided through multiple mechanisms:

#### Using Docker Compose

In a Compose file:

```yaml
models:
  llm:
    model: ai/qwen2.5-coder
    context_size: 4096
    runtime_flags:
      - "--temp"
      - "0.7"
      - "--top-p"
      - "0.9"
```

#### Using Command Line

With the `docker model configure` command:

```console
$ docker model configure ai/qwen2.5-coder -- --temp 0.7 --top-p 0.9
```

### Common llama.cpp parameters

These are the most commonly used llama.cpp parameters. You don't need to look up
the llama.cpp documentation for typical use cases.

#### Sampling parameters

| Flag | Description | Default | Range |
|------|-------------|---------|-------|
| `--temp` | Temperature for sampling. Lower = more deterministic, higher = more creative | 0.8 | 0.0-2.0 |
| `--top-k` | Limit sampling to top K tokens. Lower = more focused | 40 | 1-100 |
| `--top-p` | Nucleus sampling threshold. Lower = more focused | 0.9 | 0.0-1.0 |
| `--min-p` | Minimum probability threshold | 0.05 | 0.0-1.0 |
| `--repeat-penalty` | Penalty for repeating tokens | 1.1 | 1.0-2.0 |

**Example: Deterministic output (for code generation)**

```yaml
runtime_flags:
  - "--temp"
  - "0"
  - "--top-k"
  - "1"
```

**Example: Creative output (for storytelling)**

```yaml
runtime_flags:
  - "--temp"
  - "1.2"
  - "--top-p"
  - "0.95"
```

#### Performance parameters

| Flag | Description | Default | Notes |
|------|-------------|---------|-------|
| `--threads` | CPU threads for generation | Auto | Set to number of performance cores |
| `--threads-batch` | CPU threads for batch processing | Auto | Usually same as `--threads` |
| `--batch-size` | Batch size for prompt processing | 512 | Higher = faster prompt processing |
| `--mlock` | Lock model in memory | Off | Prevents swapping, requires sufficient RAM |
| `--no-mmap` | Disable memory mapping | Off | May improve performance on some systems |

**Example: Optimized for multi-core CPU**

```yaml
runtime_flags:
  - "--threads"
  - "8"
  - "--batch-size"
  - "1024"
```

#### GPU parameters

| Flag | Description | Default | Notes |
|------|-------------|---------|-------|
| `--n-gpu-layers` | Layers to offload to GPU | All (if GPU available) | Reduce if running out of VRAM |
| `--main-gpu` | GPU to use for computation | 0 | For multi-GPU systems |
| `--split-mode` | How to split across GPUs | layer | Options: `none`, `layer`, `row` |

**Example: Partial GPU offload (limited VRAM)**

```yaml
runtime_flags:
  - "--n-gpu-layers"
  - "20"
```

#### Advanced parameters

| Flag | Description | Default |
|------|-------------|---------|
| `--rope-scaling` | RoPE scaling method | Auto |
| `--rope-freq-base` | RoPE base frequency | Model default |
| `--rope-freq-scale` | RoPE frequency scale | Model default |
| `--no-prefill-assistant` | Disable assistant pre-fill | Off |
| `--reasoning-budget` | Token budget for reasoning models | 0 (disabled) |

### vLLM parameters

When using the vLLM backend, different parameters are available.

Use `--hf_overrides` to pass HuggingFace model config overrides as JSON:

```console
$ docker model configure --hf_overrides '{"rope_scaling": {"type": "dynamic", "factor": 2.0}}' ai/model-vllm
```

## Configuration presets

Here are complete configuration examples for common use cases.

### Code completion (fast, deterministic)

```yaml
models:
  coder:
    model: ai/qwen2.5-coder
    context_size: 4096
    runtime_flags:
      - "--temp"
      - "0.1"
      - "--top-k"
      - "1"
      - "--batch-size"
      - "1024"
```

### Chat assistant (balanced)

```yaml
models:
  assistant:
    model: ai/llama3.2
    context_size: 8192
    runtime_flags:
      - "--temp"
      - "0.7"
      - "--top-p"
      - "0.9"
      - "--repeat-penalty"
      - "1.1"
```

### Creative writing (high temperature)

```yaml
models:
  writer:
    model: ai/llama3.2
    context_size: 8192
    runtime_flags:
      - "--temp"
      - "1.2"
      - "--top-p"
      - "0.95"
      - "--repeat-penalty"
      - "1.0"
```

### Long document analysis (large context)

```yaml
models:
  analyzer:
    model: ai/qwen2.5-coder:14B
    context_size: 32768
    runtime_flags:
      - "--mlock"
      - "--batch-size"
      - "2048"
```

### Low memory system

```yaml
models:
  efficient:
    model: ai/smollm2:360M-Q4_K_M
    context_size: 2048
    runtime_flags:
      - "--threads"
      - "4"
```

## Environment-based configuration

You can also configure models via environment variables in containers:

| Variable | Description |
|----------|-------------|
| `LLM_URL` | Auto-injected URL of the model endpoint |
| `LLM_MODEL` | Auto-injected model identifier |

See [Models and Compose](../compose/models-and-compose.md) for details on how these are populated.

## Reset configuration

Configuration set via `docker model configure` persists until the model is removed.
To reset configuration:

```console
$ docker model configure --context-size -1 ai/qwen2.5-coder
```

Using `-1` resets to the default value.

## What's next

- [Inference engines](inference-engines.md) - Learn about llama.cpp and vLLM
- [API reference](api-reference.md) - API parameters for per-request configuration
- [Models and Compose](../compose/models-and-compose.md) - Configure models in Compose applications


---

# DMR examples

*Sección: Ai*

See some examples of complete workflows using Docker Model Runner.

## Sample project

You can now start building your generative AI application powered by Docker
Model Runner.

If you want to try an existing GenAI application, follow these steps:

1. Set up the sample app. Clone and run the following repository:

   ```console
   $ git clone https://github.com/docker/hello-genai.git
   ```

1. In your terminal, go to the `hello-genai` directory.

1. Run `run.sh` to pull the chosen model and run the app.

1. Open your app in the browser at the addresses specified in the repository
   [README](https://github.com/docker/hello-genai).

You see the GenAI app's interface where you can start typing your prompts.

You can now interact with your own GenAI app, powered by a local model. Try a
few prompts and notice how fast the responses are — all running on your machine
with Docker.

## Use Model Runner in GitHub Actions

Here is an example of how to use Model Runner as part of a GitHub workflow.
The example installs Model Runner, tests the installation, pulls and runs a
model, interacts with the model via the API, and deletes the model.

```yaml {title="dmr-run.yml", collapse=true}
name: Docker Model Runner Example Workflow

permissions:
  contents: read

on:
  workflow_dispatch:
    inputs:
      test_model:
        description: 'Model to test with (default: ai/smollm2:360M-Q4_K_M)'
        required: false
        type: string
        default: 'ai/smollm2:360M-Q4_K_M'

jobs:
  dmr-test:
    runs-on: ubuntu-latest
    timeout-minutes: 30

    steps:
      - name: Set up Docker
        uses: docker/setup-docker-action@{{% param "setup_docker_action_version" %}}

      - name: Install docker-model-plugin
        run: |
          echo "Installing docker-model-plugin..."
          # Add Docker's official GPG key:
          sudo apt-get update
          sudo apt-get install ca-certificates curl
          sudo install -m 0755 -d /etc/apt/keyrings
          sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
          sudo chmod a+r /etc/apt/keyrings/docker.asc
          
          # Add the repository to Apt sources:
          echo \
          "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
          $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
          sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
          sudo apt-get update
          sudo apt-get install -y docker-model-plugin
          
          echo "Installation completed successfully"

      - name: Test docker model version
        run: |
          echo "Testing docker model version command..."
          sudo docker model version
          
          # Verify the command returns successfully
          if [ $? -eq 0 ]; then
            echo "✅ docker model version command works correctly"
          else
            echo "❌ docker model version command failed"
            exit 1
          fi

      - name: Pull the provided model and run it
        run: |
          MODEL="${{ github.event.inputs.test_model || 'ai/smollm2:360M-Q4_K_M' }}"
          echo "Testing with model: $MODEL"
          
          # Test model pull
          echo "Pulling model..."
          sudo docker model pull "$MODEL"
          
          if [ $? -eq 0 ]; then
            echo "✅ Model pull successful"
          else
            echo "❌ Model pull failed"
            exit 1
          fi
                  
          # Test basic model run (with timeout to avoid hanging)
          echo "Testing docker model run..."
          timeout 60s sudo docker model run "$MODEL" "Give me a fact about whales." || {
            exit_code=$?
            if [ $exit_code -eq 124 ]; then
              echo "✅ Model run test completed (timed out as expected for non-interactive test)"
            else
              echo "❌ Model run failed with exit code: $exit_code"
              exit 1
            fi
          }

      - name: Test API endpoint
        run: |
          MODEL="${{ github.event.inputs.test_model || 'ai/smollm2:360M-Q4_K_M' }}"
          echo "Testing API endpoint with model: $MODEL"
                  
          # Test API call with curl
          echo "Testing API call..."
          RESPONSE=$(curl -s http://localhost:12434/engines/llama.cpp/v1/chat/completions \
            -H "Content-Type: application/json" \
            -d "{
                \"model\": \"$MODEL\",
                \"messages\": [
                    {
                        \"role\": \"user\",
                        \"content\": \"Say hello\"
                    }
                ],
                \"top_k\": 1,
                \"temperature\": 0
            }")
          
          if [ $? -eq 0 ]; then
            echo "✅ API call successful"
            echo "Response received: $RESPONSE"
            
            # Check if response contains "hello" (case-insensitive)
            if echo "$RESPONSE" | grep -qi "hello"; then
              echo "✅ Response contains 'hello' (case-insensitive)"
            else
              echo "❌ Response does not contain 'hello'"
              echo "Full response: $RESPONSE"
              exit 1
            fi
          else
            echo "❌ API call failed"
            exit 1
          fi

      - name: Test model cleanup
        run: |
          MODEL="${{ github.event.inputs.test_model || 'ai/smollm2:360M-Q4_K_M' }}"
          
          echo "Cleaning up test model..."
          sudo docker model rm "$MODEL" || echo "Model removal failed or model not found"
          
          # Verify model was removed
          echo "Verifying model cleanup..."
          sudo docker model ls
          
          echo "✅ Model cleanup completed"

      - name: Report success
        if: success()
        run: |
          echo "🎉 Docker Model Runner daily health check completed successfully!"
          echo "All tests passed:"
          echo "  ✅ docker-model-plugin installation successful"
          echo "  ✅ docker model version command working"
          echo "  ✅ Model pull and run operations successful"
          echo "  ✅ API endpoint operations successful"
          echo "  ✅ Cleanup operations successful"
```

## Related pages

- [Models and Compose](../compose/models-and-compose.md)


---

# Get started with DMR

*Sección: Ai*

Docker Model Runner (DMR) lets you run and manage AI models locally using Docker. This page shows you how to enable DMR, pull and run a model, configure model settings, and publish custom models.

## Enable Docker Model Runner

You can enable DMR using Docker Desktop or Docker Engine. Follow the instructions below based on your setup.

### Docker Desktop

1. In the settings view, go to the **AI** tab.
1. Select the **Enable Docker Model Runner** setting.
1. If you use Windows with a supported NVIDIA GPU, you also see and can select
   **Enable GPU-backed inference**.
1. Optional: To enable TCP support, select **Enable host-side TCP support**.
   1. In the **Port** field, type the port you want to use.
   1. If you interact with Model Runner from a local frontend web app, in
      **CORS Allows Origins**, select the origins that Model Runner should
      accept requests from. An origin is the URL where your web app runs, for
      example `http://localhost:3131`.

You can now use the `docker model` command in the CLI and view and interact
with your local models in the **Models** tab in the Docker Desktop Dashboard.

### Docker Engine

1. Ensure you have installed [Docker Engine](/engine/install/).
1. Docker Model Runner is available as a package. To install it, run:

   {{< tabs >}}
   {{< tab name="Ubuntu/Debian">}}

   ```bash
   $ sudo apt-get update
   $ sudo apt-get install docker-model-plugin
   ```

   {{< /tab >}}
   {{< tab name="RPM-base distributions">}}

   ```bash
   $ sudo dnf update
   $ sudo dnf install docker-model-plugin
   ```

   {{< /tab >}}
   {{< /tabs >}}

1. Test the installation:

   ```bash
   $ docker model version
   $ docker model run ai/smollm2
   ```

> [!NOTE]
> TCP support is enabled by default for Docker Engine on port `12434`.

### Update DMR in Docker Engine

To update Docker Model Runner in Docker Engine, uninstall it with
[`docker model uninstall-runner`](/reference/cli/docker/model/uninstall-runner/)
then reinstall it:

```bash
docker model uninstall-runner --images && docker model install-runner
```
> [!NOTE]
> With the above command, local models are preserved and only the Docker Model Runner images are removed.
> To also delete the local models during the upgrade, add the `--models` option to the `uninstall-runner` command.

## Pull a model

Models are cached locally.

> [!NOTE]
>
> When you use the Docker CLI, you can also pull models directly from
> [HuggingFace](https://huggingface.co/).

{{< tabs group="release" >}}
{{< tab name="From Docker Desktop">}}

1. Select **Models** and select the **Docker Hub** tab.
1. Find the model you want and select **Pull**.

![Screenshot showing the Docker Hub view.](./images/dmr-catalog.png)

{{< /tab >}}
{{< tab name="From the Docker CLI">}}

Use the [`docker model pull` command](/reference/cli/docker/model/pull/).
For example:

```bash {title="Pulling from Docker Hub"}
docker model pull ai/smollm2:360M-Q4_K_M
```

```bash {title="Pulling from HuggingFace"}
docker model pull hf.co/bartowski/Llama-3.2-1B-Instruct-GGUF
```

{{< /tab >}}
{{< /tabs >}}

## Run a model

{{< tabs group="release" >}}
{{< tab name="From Docker Desktop">}}

1. Select **Models** and select the **Local** tab.
1. Select the play button. The interactive chat screen opens.

![Screenshot showing the Local view.](./images/dmr-run.png)

{{< /tab >}}
{{< tab name="From the Docker CLI" >}}

Use the [`docker model run` command](/reference/cli/docker/model/run/).

{{< /tab >}}
{{< /tabs >}}

## Configure a model

You can configure a model, such as its maximum token limit and more,
use Docker Compose.
See [Models and Compose - Model configuration options](../compose/models-and-compose.md#model-configuration-options).

## Publish a model

> [!NOTE]
>
> This works for any Container Registry supporting OCI Artifacts, not only
> Docker Hub.

You can tag existing models with a new name and publish them under a different
namespace and repository:

```bash
# Tag a pulled model under a new name
$ docker model tag ai/smollm2 myorg/smollm2

# Push it to Docker Hub
$ docker model push myorg/smollm2
```

For more details, see the [`docker model tag`](/reference/cli/docker/model/tag)
and [`docker model push`](/reference/cli/docker/model/push) command
documentation.

You can also package a model file in GGUF format as an OCI Artifact and publish
it to Docker Hub.

```bash
# Download a model file in GGUF format, for example from HuggingFace
$ curl -L -o model.gguf https://huggingface.co/TheBloke/Mistral-7B-v0.1-GGUF/resolve/main/mistral-7b-v0.1.Q4_K_M.gguf

# Package it as OCI Artifact and push it to Docker Hub
$ docker model package --gguf "$(pwd)/model.gguf" --push myorg/mistral-7b-v0.1:Q4_K_M
```

For more details, see the
[`docker model package`](/reference/cli/docker/model/package/) command
documentation.

## Troubleshooting

### Display the logs

To troubleshoot issues, display the logs:

{{< tabs group="release" >}}
{{< tab name="From Docker Desktop">}}

Select **Models** and select the **Logs** tab.

![Screenshot showing the Models view.](./images/dmr-logs.png)

{{< /tab >}}
{{< tab name="From the Docker CLI">}}

Use the [`docker model logs` command](/reference/cli/docker/model/logs/).

{{< /tab >}}
{{< /tabs >}}

### Inspect requests and responses

Inspecting requests and responses helps you diagnose model-related issues.
For example, you can evaluate context usage to verify you stay within the model's context
window or display the full body of a request to control the parameters you are passing to your models
when developing with a framework.

In Docker Desktop, to inspect the requests and responses for each model:

1. Select **Models** and select the **Requests** tab. This view displays all the requests to all models:
   - The time the request was sent.
   - The model name and version
   - The prompt/request
   - The context usage
   - The time it took for the response to be generated.
1. Select one of the requests to display further details:
   - In the **Overview** tab, view the token usage, response metadata and generation speed, and the actual prompt and response.
   - In the **Request**  and **Response** tabs, view the full JSON payload of the request and the response.

> [!NOTE]
> You can also display the requests for a specific model when you select a model and then select the **Requests** tab.

## Related pages

- [API reference](api-reference.md) - OpenAI and Ollama-compatible API documentation
- [Configuration options](configuration.md) - Context size and runtime parameters
- [Inference engines](inference-engines.md) - llama.cpp and vLLM details
- [IDE integrations](ide-integrations.md) - Connect Cline, Continue, Cursor, and more
- [Open WebUI integration](openwebui-integration.md) - Set up a web chat interface
- [Models and Compose](../compose/models-and-compose.md) - Use models in Compose applications
- [Docker Model Runner CLI reference](/reference/cli/docker/model) - Complete CLI documentation


---

# IDE and tool integrations

*Sección: Ai*

Docker Model Runner can serve as a local backend for popular AI coding assistants
and development tools. This guide shows how to configure common tools to use
models running in DMR.

## Prerequisites

Before configuring any tool:

1. [Enable Docker Model Runner](get-started.md#enable-docker-model-runner) in Docker Desktop or Docker Engine.
2. Enable TCP host access:
   - Docker Desktop: Enable **host-side TCP support** in Settings > AI, or run:
     ```console
     $ docker desktop enable model-runner --tcp 12434
     ```
   - Docker Engine: TCP is enabled by default on port 12434.
3. Pull a model:
   ```console
   $ docker model pull ai/qwen2.5-coder
   ```

> [!TIP]
> 
> The default context size for many models (such as `gpt-oss`) is 4,096 tokens, which is limiting for coding tasks.
> You can repackage it with a larger context window:
>
> ```console
> $ docker model pull gpt-oss
> $ docker model package --from ai/gpt-oss --context-size 32000 gpt-oss:32k
> ```
> Alternatively, models like ai/glm-4.7-flash, ai/qwen2.5-coder, and ai/devstral-small-2
> come with 128K context by default and work without repackaging.

## Cline (VS Code)

[Cline](https://github.com/cline/cline) is an AI coding assistant for VS Code.

### Configuration

1. Open VS Code and go to the Cline extension settings.
2. Select **OpenAI Compatible** as the API provider.
3. Configure the following settings:

| Setting | Value |
|---------|-------|
| Base URL | `http://localhost:12434/engines/v1` |
| API Key | `not-needed` (or any placeholder value) |
| Model ID | `ai/qwen2.5-coder` (or your preferred model) |

> [!IMPORTANT]
> The base URL must include `/engines/v1` at the end. Do not include a trailing slash.

### Troubleshooting Cline

If Cline fails to connect:

1. Verify DMR is running:
   ```console
   $ docker model status
   ```

2. Test the endpoint directly:
   ```console
   $ curl http://localhost:12434/engines/v1/models
   ```

3. Check that CORS is configured if running a web-based version:
   - In Docker Desktop Settings > AI, add your origin to **CORS Allowed Origins**

## Continue (VS Code / JetBrains)

[Continue](https://continue.dev) is an open-source AI code assistant that works with VS Code and JetBrains IDEs.

### Configuration

Edit your Continue configuration file (`~/.continue/config.json`):

```json
{
  "models": [
    {
      "title": "Docker Model Runner",
      "provider": "openai",
      "model": "ai/qwen2.5-coder",
      "apiBase": "http://localhost:12434/engines/v1",
      "apiKey": "not-needed"
    }
  ]
}
```

### Using Ollama provider

Continue also supports the Ollama provider, which works with DMR:

```json
{
  "models": [
    {
      "title": "Docker Model Runner (Ollama)",
      "provider": "ollama",
      "model": "ai/qwen2.5-coder",
      "apiBase": "http://localhost:12434"
    }
  ]
}
```

## Cursor

[Cursor](https://cursor.sh) is an AI-powered code editor.

### Configuration

1. Open Cursor Settings (Cmd/Ctrl + ,).
2. Navigate to **Models** > **OpenAI API Key**.
3. Configure:

   | Setting | Value |
   |---------|-------|
   | OpenAI API Key | `not-needed` |
   | Override OpenAI Base URL | `http://localhost:12434/engines/v1` |

4. In the model drop-down, enter your model name: `ai/qwen2.5-coder`

> [!NOTE]
> Some Cursor features may require models with specific capabilities (e.g., function calling).
> Use capable models like `ai/qwen2.5-coder` or `ai/llama3.2` for best results.

## Zed

[Zed](https://zed.dev) is a high-performance code editor with AI features.

### Configuration

Edit your Zed settings (`~/.config/zed/settings.json`):

```json
{
  "language_models": {
    "openai": {
      "api_url": "http://localhost:12434/engines/v1",
      "available_models": [
        {
          "name": "ai/qwen2.5-coder",
          "display_name": "Qwen 2.5 Coder (DMR)",
          "max_tokens": 8192
        }
      ]
    }
  }
}
```

## Open WebUI

[Open WebUI](https://github.com/open-webui/open-webui) provides a ChatGPT-like interface for local models.

See [Open WebUI integration](openwebui-integration.md) for detailed setup instructions.

## Aider

[Aider](https://aider.chat) is an AI pair programming tool for the terminal.

### Configuration

Set environment variables or use command-line flags:

```bash
export OPENAI_API_BASE=http://localhost:12434/engines/v1
export OPENAI_API_KEY=not-needed

aider --model openai/ai/qwen2.5-coder
```

Or in a single command:

```console
$ aider --openai-api-base http://localhost:12434/engines/v1 \
        --openai-api-key not-needed \
        --model openai/ai/qwen2.5-coder
```

## LangChain

### Python

```python
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="http://localhost:12434/engines/v1",
    api_key="not-needed",
    model="ai/qwen2.5-coder"
)

response = llm.invoke("Write a hello world function in Python")
print(response.content)
```

### JavaScript/TypeScript

```typescript
import { ChatOpenAI } from "@langchain/openai";

const model = new ChatOpenAI({
  configuration: {
    baseURL: "http://localhost:12434/engines/v1",
  },
  apiKey: "not-needed",
  modelName: "ai/qwen2.5-coder",
});

const response = await model.invoke("Write a hello world function");
console.log(response.content);
```

## LlamaIndex

```python
from llama_index.llms.openai_like import OpenAILike

llm = OpenAILike(
    api_base="http://localhost:12434/engines/v1",
    api_key="not-needed",
    model="ai/qwen2.5-coder"
)

response = llm.complete("Write a hello world function")
print(response.text)
```

## OpenCode

[OpenCode](https://opencode.ai/) is an open-source coding assistant designed to integrate directly into developer workflows. It supports multiple model providers and exposes a flexible configuration system that makes it easy to switch between them.

See [Use OpenCode with Docker Model Runner](../../../guides/opencode-model-runner.md)
for a task-focused guide that walks through model setup, configuration, and
troubleshooting.

### Configuration

1. Install OpenCode (see [docs](https://opencode.ai/docs/#install))
2. Reference DMR in your OpenCode configuration, either globally at `~/.config/opencode/opencode.json` or project specific with a `opencode.json` file in the root of your project
   ```json
   {
     "$schema": "https://opencode.ai/config.json",
     "provider": {
       "dmr": {
         "npm": "@ai-sdk/openai-compatible",
         "name": "Docker Model Runner",
         "options": {
           "baseURL": "http://localhost:12434/v1"
         },
         "models": {
           "ai/qwen2.5-coder": {
             "name": "ai/qwen2.5-coder"
           },
           "ai/llama3.2": {
             "name": "ai/llama3.2"
           }
         }
       }
     }
   }
   ```
3. Select the model you want in OpenCode

You can find more details in [this Docker Blog post](https://www.docker.com/blog/opencode-docker-model-runner-private-ai-coding/)

## Claude Code

[Claude Code](https://claude.com/product/claude-code) is [Anthropic's](https://www.anthropic.com/) command-line tool for agentic coding. It lives in your terminal, understands your codebase, and executes routine tasks, explains complex code, and handles Git workflows through natural language commands.

See [Use Claude Code with Docker Model Runner](../../../guides/claude-code-model-runner.md)
for a task-focused guide that walks through model setup, configuration, and
inspecting requests. To run Claude Code in an isolated Docker Sandbox against
a local model, see
[Run Claude Code in a Docker Sandbox with Docker Model Runner](../../../guides/claude-code-sandbox-model-runner.md).

### Configuration

1. Install Claude Code (see [docs](https://code.claude.com/docs/en/quickstart#step-1-install-claude-code))
2. Use the `ANTHROPIC_BASE_URL` environment variable to point Claude Code at DMR. On Mac or Linux, you can do this, for example if you want to use the `gpt-oss:32k` model:
    ```bash
    ANTHROPIC_BASE_URL=http://localhost:12434 claude --model qwen2.5-coder
    ```
    On Windows (PowerShell) you can do it like this:
    ```powershell
    $env:ANTHROPIC_BASE_URL="http://localhost:12434"
    claude --model gpt-oss:32k
    ```

> [!TIP]
>
> To avoid setting the variable each time, add it to your shell profile (`~/.bashrc`, `~/.zshrc`, or equivalent):
>
> ```shell
> export ANTHROPIC_BASE_URL=http://localhost:12434
> ```

You can find more details in [this Docker Blog post](https://www.docker.com/blog/run-claude-code-locally-docker-model-runner/)

> [!NOTE]
>
> While the other integrations on this page use the [OpenAI-compatible API](/ai/model-runner/api-reference/#openai-compatible-api), DMR also exposes a [Anthropic-compatible API](/ai/model-runner/api-reference/#anthropic-compatible-api) used here.

## Common issues

### "Connection refused" errors

1. Ensure Docker Model Runner is enabled and running:
   ```console
   $ docker model status
   ```

2. Verify TCP access is enabled:
   ```console
   $ curl http://localhost:12434/engines/v1/models
   ```

3. Check if another service is using port 12434.

4. If you run your tool in WSL and want to connect to DMR on the host via `localhost`, this might not directly work. Configuring WSL to use [mirrored networking](https://learn.microsoft.com/en-us/windows/wsl/networking#mirrored-mode-networking) can solve this.

### "Model not found" errors

1. Verify the model is pulled:
   ```console
   $ docker model list
   ```

2. Use the full model name including namespace (e.g., `ai/qwen2.5-coder`, not just `qwen2.5-coder`).

### Slow responses or timeouts

1. For first requests, models need to load into memory. Subsequent requests are faster.

2. Consider using a smaller model or adjusting the context size:
   ```console
   $ docker model configure --context-size 4096 ai/qwen2.5-coder
   ```

3. Check available system resources (RAM, GPU memory).

### CORS errors (web-based tools)

If using browser-based tools, add the origin to CORS allowed origins:

1. Docker Desktop: Settings > AI > CORS Allowed Origins
2. Add your tool's URL (e.g., `http://localhost:3000`)

## Recommended models by use case

| Use case | Recommended model | Notes |
|----------|-------------------|-------|
| Code completion | `ai/qwen3-coder` | Optimized for coding tasks with a large context window |
| Agentic coding | `ai/devstral-small-2` | Good fit for tools such as Claude Code and OpenCode |
| General assistant | `ai/llama3.2` | Good balance of capabilities |
| Small/fast | `ai/smollm2` | Low resource usage |
| Embeddings | `ai/all-minilm` | For RAG and semantic search |

## What's next

- [API reference](api-reference.md) - Full API documentation
- [Configuration options](configuration.md) - Tune model behavior
- [Open WebUI integration](openwebui-integration.md) - Set up a web interface


---

# Inference engines

*Sección: Ai*

Docker Model Runner supports three inference engines: **llama.cpp**, **vLLM**, and **Diffusers**.
Each engine has different strengths, supported platforms, and model format
requirements. This guide helps you choose the right engine and configure it for
your use case.

## Engine comparison

| Feature | llama.cpp | vLLM | Diffusers                           |
|---------|-----------|------|-------------------------------------|
| **Model formats** | GGUF | Safetensors, HuggingFace | DDUF                                |
| **Platforms** | All (macOS, Windows, Linux) | Linux x86_64 only | Linux (x86_64, ARM64)               |
| **GPU support** | NVIDIA, AMD, Apple Silicon, Vulkan | NVIDIA CUDA only | NVIDIA CUDA only                    |
| **CPU inference** | Yes | No | No                                  |
| **Quantization** | Built-in (Q4, Q5, Q8, etc.) | Limited | Limited                             |
| **Memory efficiency** | High (with quantization) | Moderate | Moderate                            |
| **Throughput** | Good | High (with batching) | Good                                |
| **Best for** | Local development, resource-constrained environments | Production, high throughput | Image generation                    |
| **Use case** | Text generation (LLMs) | Text generation (LLMs) | Image generation (Stable Diffusion) |

## llama.cpp

[llama.cpp](https://github.com/ggerganov/llama.cpp) is the default inference
engine in Docker Model Runner. It's designed for efficient local inference and
supports a wide range of hardware configurations.

### Platform support

| Platform | GPU support | Notes |
|----------|-------------|-------|
| macOS (Apple Silicon) | Metal | Automatic GPU acceleration |
| Windows (x64) | NVIDIA CUDA | Requires NVIDIA drivers 576.57+ |
| Windows (ARM64) | Adreno OpenCL | Qualcomm 6xx series and later |
| Linux (x64) | NVIDIA, AMD, Vulkan | Multiple backend options |
| Linux | CPU only | Works on any x64/ARM64 system |

### Model format: GGUF

llama.cpp uses the GGUF format, which supports efficient quantization for reduced
memory usage without significant quality loss.

#### Quantization levels

| Quantization | Bits per weight | Memory usage | Quality |
|--------------|-----------------|--------------|---------|
| Q2_K | ~2.5 | Lowest | Reduced |
| Q3_K_M | ~3.5 | Minimal | Acceptable |
| Q4_K_M | ~4.5 | Low | Good |
| Q5_K_M | ~5.5 | Moderate | Excellent |
| Q6_K | ~6.5 | Higher | Excellent |
| Q8_0 | 8 | High | Near-original |
| F16 | 16 | Highest | Original |

**Recommended**: Q4_K_M offers the best balance of quality and memory usage for
most use cases.

#### Pulling quantized models

Models on Docker Hub often include quantization in the tag:

```console
$ docker model pull ai/llama3.2:3B-Q4_K_M
```

### Using llama.cpp

llama.cpp is the default engine. No special configuration is required:

```console
$ docker model run ai/smollm2
```

To explicitly specify llama.cpp when running models:

```console
$ docker model run ai/smollm2 --backend llama.cpp
```

### llama.cpp API endpoints

When using llama.cpp, API calls use the llama.cpp engine path:

```text
POST /engines/llama.cpp/v1/chat/completions
```

Or without the engine prefix:

```text
POST /engines/v1/chat/completions
```

## vLLM

[vLLM](https://github.com/vllm-project/vllm) is a high-performance inference
engine optimized for production workloads with high throughput requirements.

### Platform support

| Platform | GPU | Support status |
|----------|-----|----------------|
| Linux x86_64 | NVIDIA CUDA | Supported |
| Windows with WSL2 | NVIDIA CUDA | Supported (Docker Desktop 4.54+) |
| macOS | - | Not supported |
| Linux ARM64 | - | Not supported |
| AMD GPUs | - | Not supported |

> [!IMPORTANT]
> vLLM requires an NVIDIA GPU with CUDA support. It does not support CPU-only
> inference.

### Model format: Safetensors

vLLM works with models in Safetensors format, which is the standard format for
HuggingFace models. These models typically use more memory than quantized GGUF
models but may offer better quality and faster inference on powerful hardware.

### Setting up vLLM

#### Docker Engine (Linux)

Install the Model Runner with vLLM backend:

```console
$ docker model install-runner --backend vllm --gpu cuda
```

Verify the installation:

```console
$ docker model status
Docker Model Runner is running

Status:
llama.cpp: running llama.cpp version: c22473b
vllm: running vllm version: 0.11.0
```

#### Docker Desktop (Windows with WSL2)

1. Ensure you have:
   - Docker Desktop 4.54 or later (minimum version for vLLM support)
   - NVIDIA GPU with updated drivers
   - WSL2 enabled

2. Install vLLM backend:
   ```console
   $ docker model install-runner --backend vllm --gpu cuda
   ```

### Running models with vLLM

vLLM models are typically tagged with `-vllm` suffix:

```console
$ docker model run ai/smollm2-vllm
```

To specify the vLLM backend explicitly:

```console
$ docker model run ai/model --backend vllm
```

### vLLM API endpoints

When using vLLM, specify the engine in the API path:

```text
POST /engines/vllm/v1/chat/completions
```

### vLLM configuration

#### HuggingFace overrides

Use `--hf_overrides` to pass model configuration overrides:

```console
$ docker model configure --hf_overrides '{"max_model_len": 8192}' ai/model-vllm
```

#### Common vLLM settings

| Setting | Description | Example |
|---------|-------------|---------|
| `max_model_len` | Maximum context length | 8192 |
| `gpu_memory_utilization` | Fraction of GPU memory to use | 0.9 |
| `tensor_parallel_size` | GPUs for tensor parallelism | 2 |

### vLLM and llama.cpp performance comparison

| Scenario | Recommended engine |
|----------|-------------------|
| Single user, local development | llama.cpp |
| Multiple concurrent requests | vLLM |
| Limited GPU memory | llama.cpp (with quantization) |
| Maximum throughput | vLLM |
| CPU-only system | llama.cpp |
| Apple Silicon Mac | llama.cpp |
| Production deployment | vLLM (if hardware supports it) |

## Diffusers

[Diffusers](https://github.com/huggingface/diffusers) is an inference engine
for image generation models, including Stable Diffusion. Unlike llama.cpp and
vLLM which focus on text generation with LLMs, Diffusers enables you to generate
images from text prompts.

### Platform support

| Platform | GPU | Support status |
|----------|-----|----------------|
| Linux x86_64 | NVIDIA CUDA | Supported |
| Linux ARM64 | NVIDIA CUDA | Supported |
| Windows | - | Not supported |
| macOS | - | Not supported |

> [!IMPORTANT]
> Diffusers requires an NVIDIA GPU with CUDA support. It does not support
> CPU-only inference.

### Setting up Diffusers

Install the Model Runner with Diffusers backend:

```console
$ docker model reinstall-runner --backend diffusers --gpu cuda
```

Verify the installation:

```console
$ docker model status
Docker Model Runner is running

Status:
llama.cpp: running llama.cpp version: 34ce48d
mlx: not installed
sglang: sglang package not installed
vllm: vLLM binary not found
diffusers: running diffusers version: 0.36.0
```

### Pulling Diffusers models

Pull a Stable Diffusion model:

```console
$ docker model pull stable-diffusion:Q4
```

### Generating images with Diffusers

Diffusers uses an image generation API endpoint. To generate an image:

```console
$ curl -s -X POST http://localhost:12434/engines/diffusers/v1/images/generations \
  -H "Content-Type: application/json" \
  -d '{
    "model": "stable-diffusion:Q4",
    "prompt": "A picture of a nice cat",
    "size": "512x512"
  }' | jq -r '.data[0].b64_json' | base64 -d > image.png
```

This command:
1. Sends a POST request to the Diffusers image generation endpoint
2. Specifies the model, prompt, and output image size
3. Extracts the base64-encoded image from the response
4. Decodes it and saves it as `image.png`

### Diffusers API endpoint

When using Diffusers, specify the engine in the API path:

```text
POST /engines/diffusers/v1/images/generations
```

### Supported parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `model` | string | Required. The model identifier (e.g., `stable-diffusion:Q4`). |
| `prompt` | string | Required. The text description of the image to generate. |
| `size` | string | Image dimensions in `WIDTHxHEIGHT` format (e.g., `512x512`). |

## Running multiple engines

You can run llama.cpp, vLLM, and Diffusers simultaneously. Docker Model Runner routes
requests to the appropriate engine based on the model or explicit engine selection.

Check which engines are running:

```console
$ docker model status
Docker Model Runner is running

Status:
llama.cpp: running llama.cpp version: 34ce48d
mlx: not installed
sglang: sglang package not installed
vllm: running vllm version: 0.11.0
diffusers: running diffusers version: 0.36.0
```

### Engine-specific API paths

| Engine | API path | Use case |
|--------|----------|----------|
| llama.cpp | `/engines/llama.cpp/v1/chat/completions` | Text generation |
| vLLM | `/engines/vllm/v1/chat/completions` | Text generation |
| Diffusers | `/engines/diffusers/v1/images/generations` | Image generation |
| Auto-select | `/engines/v1/chat/completions` | Text generation (auto-selects engine) |

## Managing inference engines

### Install an engine

```console
$ docker model install-runner --backend <engine> [--gpu <type>]
```

Options:
- `--backend`: `llama.cpp`, `vllm`, or `diffusers`
- `--gpu`: `cuda`, `rocm`, `vulkan`, or `metal` (depends on platform)

### Reinstall an engine

```console
$ docker model reinstall-runner --backend <engine>
```

### Check engine status

```console
$ docker model status
```

### View engine logs

```console
$ docker model logs
```

## Packaging models for each engine

### Package a GGUF model (llama.cpp)

```console
$ docker model package --gguf ./model.gguf --push myorg/mymodel:Q4_K_M
```

### Package a Safetensors model (vLLM)

```console
$ docker model package --safetensors ./model/ --push myorg/mymodel-vllm
```

## Troubleshooting

### vLLM won't start

1. Verify NVIDIA GPU is available:
   ```console
   $ nvidia-smi
   ```

2. Check Docker has GPU access:
   ```console
   $ docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi
   ```

3. Verify you're on a supported platform (Linux x86_64 or Windows WSL2).

### llama.cpp is slow

1. Ensure GPU acceleration is working (check logs for Metal/CUDA messages).

2. Try a more aggressive quantization:
   ```console
   $ docker model pull ai/model:Q4_K_M
   ```

3. Reduce context size:
   ```console
   $ docker model configure --context-size 2048 ai/model
   ```

### Out of memory errors

1. Use a smaller quantization (Q4 instead of Q8).
2. Reduce context size.
3. For vLLM, adjust `gpu_memory_utilization`:
   ```console
   $ docker model configure --hf_overrides '{"gpu_memory_utilization": 0.8}' ai/model
   ```

## What's next

- [Configuration options](configuration.md) - Detailed parameter reference
- [API reference](api-reference.md) - API documentation
- [GPU support](../../desktop/features/gpu.md) - GPU configuration for Docker Desktop


---

# Open WebUI integration

*Sección: Ai*

[Open WebUI](https://github.com/open-webui/open-webui) is an open-source,
self-hosted web interface that provides a ChatGPT-like experience for local
AI models. You can connect it to Docker Model Runner to get a polished chat
interface for your models.

## Prerequisites

- Docker Model Runner enabled with TCP access
- A model pulled (e.g., `docker model pull ai/llama3.2`)

## Quick start with Docker Compose

The easiest way to run Open WebUI with Docker Model Runner is using Docker Compose.

Create a `compose.yaml` file:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://host.docker.internal:12434
      - WEBUI_AUTH=false
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - open-webui:/app/backend/data

volumes:
  open-webui:
```

Start the services:

```console
$ docker compose up -d
```

Open your browser to [http://localhost:3000](http://localhost:3000).

## Configuration options

### Environment variables

| Variable | Description | Default |
|----------|-------------|---------|
| `OLLAMA_BASE_URL` | URL of Docker Model Runner | Required |
| `WEBUI_AUTH` | Enable authentication | `true` |
| `OPENAI_API_BASE_URL` | Use OpenAI-compatible API instead | - |
| `OPENAI_API_KEY` | API key (use any value for DMR) | - |

### Using OpenAI-compatible API

If you prefer to use the OpenAI-compatible API instead of the Ollama API:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OPENAI_API_BASE_URL=http://host.docker.internal:12434/engines/v1
      - OPENAI_API_KEY=not-needed
      - WEBUI_AUTH=false
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - open-webui:/app/backend/data

volumes:
  open-webui:
```

## Network configuration

### Docker Desktop

On Docker Desktop, `host.docker.internal` automatically resolves to the host machine.
The previous example works without modification.

### Docker Engine (Linux)

On Docker Engine, you may need to configure the network differently:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    network_mode: host
    environment:
      - OLLAMA_BASE_URL=http://localhost:12434
      - WEBUI_AUTH=false
    volumes:
      - open-webui:/app/backend/data

volumes:
  open-webui:
```

Or use the host gateway:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://172.17.0.1:12434
      - WEBUI_AUTH=false
    volumes:
      - open-webui:/app/backend/data

volumes:
  open-webui:
```

## Using Open WebUI

### Select a model

1. Open [http://localhost:3000](http://localhost:3000)
2. Select the model drop-down in the top-left
3. Select from your pulled models (they appear with `ai/` prefix)

### Pull models through the UI

Open WebUI can pull models directly:

1. Select the model drop-down
2. Enter a model name: `ai/llama3.2`
3. Select the download icon

### Chat features

Open WebUI provides:

- Multi-turn conversations with context
- Message editing and regeneration
- Code syntax highlighting
- Markdown rendering
- Conversation history and search
- Export conversations

## Complete example with multiple models

This example sets up Open WebUI with Docker Model Runner and pre-pulls several models:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://host.docker.internal:12434
      - WEBUI_AUTH=false
      - DEFAULT_MODELS=ai/llama3.2
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - open-webui:/app/backend/data
    depends_on:
      model-setup:
        condition: service_completed_successfully

  model-setup:
    image: docker:cli
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: >
      sh -c "
        docker model pull ai/llama3.2 &&
        docker model pull ai/qwen2.5-coder &&
        docker model pull ai/smollm2
      "

volumes:
  open-webui:
```

## Enabling authentication

For multi-user setups or security, enable authentication:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"
    environment:
      - OLLAMA_BASE_URL=http://host.docker.internal:12434
      - WEBUI_AUTH=true
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - open-webui:/app/backend/data

volumes:
  open-webui:
```

On first visit, you'll create an admin account.

## Troubleshooting

### Models don't appear in the drop-down

1. Verify Docker Model Runner is accessible:
   ```console
   $ curl http://localhost:12434/api/tags
   ```

2. Check that models are pulled:
   ```console
   $ docker model list
   ```

3. Verify the `OLLAMA_BASE_URL` is correct and accessible from the container.

### "Connection refused" errors

1. Ensure TCP access is enabled for Docker Model Runner.

2. On Docker Desktop, verify `host.docker.internal` resolves:
   ```console
   $ docker run --rm alpine ping -c 1 host.docker.internal
   ```

3. On Docker Engine, try using `network_mode: host` or the explicit host IP.

### Slow response times

1. First requests load the model into memory, which takes time.

2. Subsequent requests are much faster.

3. If consistently slow, consider:
   - Using a smaller model
   - Reducing context size
   - Checking GPU acceleration is working

### CORS errors

If running Open WebUI on a different host:

1. In Docker Desktop, go to Settings > AI
2. Add the Open WebUI URL to **CORS Allowed Origins**

## Customization

### Custom system prompts

Open WebUI supports setting system prompts per model. Configure these in the UI under Settings > Models.

### Model parameters

Adjust model parameters in the chat interface:

1. Select the settings icon next to the model name
2. Adjust temperature, top-p, max tokens, etc.

These settings are passed through to Docker Model Runner.

## Running on a different port

To run Open WebUI on a different port:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "8080:8080"  # Change first port number
    # ... rest of config
```

## What's next

- [API reference](api-reference.md) - Learn about the APIs Open WebUI uses
- [Configuration options](configuration.md) - Tune model behavior
- [IDE integrations](ide-integrations.md) - Connect other tools to DMR


---

# Docker Sandboxes

*Sección: Ai*

Docker Sandboxes run AI coding agents in isolated microVM sandboxes. Each
sandbox gets its own Docker daemon, filesystem, and network — the agent can
build containers, install packages, and modify files without accessing host
resources beyond those you share.

> [!NOTE]
> The `sbx` CLI is free to use, including for commercial work. Only
> [organization governance](governance/) requires a separate paid subscription.

Organization admins can
[centrally manage sandbox network, filesystem, and MCP policies](governance/access-controls/organization.md),
so the same controls apply uniformly across every developer's machine.
Available on a separate paid subscription.

## Get started

Follow the [installation guide](install.md) to check the system requirements,
install the `sbx` CLI, and sign in.

Then launch an agent in a sandbox:

```console
$ cd ~/my-project
$ sbx run claude
```

See the [get started guide](get-started.md) for a first-session walkthrough, or
jump to the [usage guide](usage.md) for basic commands.

## Learn more

- [Agents](agents/) — supported agents and per-agent configuration
- [Workflows](workflows/) — patterns for Git, local development,
  authentication, agent skills, and automation
- [Configuration](configuration/) — manage credentials, declare project
  environments, turn on GPU passthrough, and configure an upstream proxy
- [Integrations](integrations/) — connect editors and apps like VS Code and
  Cursor to a sandbox over SSH
- [MCP gateway](mcp-gateway.md) — register MCP servers and connect them to
  sandboxed agents
- [Customize](customize/) — reusable templates and declarative kits for
  extending or tailoring sandboxes
- [Architecture](architecture.md) — microVM isolation, workspace mounting,
  networking
- [Security](security/) — isolation model, credential handling, and
  network policies
- [CLI reference](/reference/cli/sbx/) — full list of `sbx` commands and options
- [Troubleshooting](troubleshooting.md) — common issues and fixes
- [FAQ](faq.md) — login requirements, telemetry, etc

## Feedback

Your feedback shapes what gets built next. If you run into a bug, hit a
missing feature, or have a suggestion, open an issue at
[github.com/docker/sbx-releases/issues](https://github.com/docker/sbx-releases/issues).


---

# Supported agents

*Sección: Ai*

Docker Sandboxes runs the following agents out of the box:

- [Claude Code](claude-code/)
- [Codex](codex/)
- [Copilot](copilot/)
- [Cursor](cursor/)
- [Devin](devin/)
- [Docker Agent](docker-agent/)
- [Droid](droid/)
- [Gemini](gemini/)
- [Kiro](kiro/)
- [OpenCode](opencode/)
- [Shell](shell/) — agent-less sandbox for manual setup or testing

Want to pre-install tools or customize an agent's environment?
See [Customize](../customize/).


---

# Claude Code

*Sección: Ai*

Official documentation: [Claude Code](https://code.claude.com/docs)

## Quick start

Launch Claude Code in a sandbox by pointing it at a project directory:

```console
$ sbx run claude ~/my-project
```

To start Claude with a specific prompt in the current directory:

```console
$ sbx run --name my-sandbox claude -- "Add error handling to the login function"
```

Everything after `--` is passed directly to Claude Code. You can also pipe in a
prompt from a file with `-- "$(cat prompt.txt)"`.

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name.

## Authentication

Claude Code requires either an Anthropic API key or a Claude subscription.

**API key**: Store your key using
[stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set anthropic
```

**Claude subscription**: If no API key is set, use the `/login` command inside
Claude Code to authenticate via OAuth.

## Configuration

Sandboxes don't pick up user-level configuration from your host, such as
`~/.claude`. Only project-level configuration in the working directory is
available inside the sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

### Remote control

To use Claude Code's `/remote-control` command inside a sandbox, turn on remote
control:

```console
$ sbx settings set claude.remoteControl true
```

### Default startup command

Without extra args, the sandbox runs:

```text
claude --dangerously-skip-permissions
```

Arguments after `--` are added after the default flags when the first one is
itself a flag (begins with `-`), so `--dangerously-skip-permissions` is
preserved:

```console
$ sbx run --name <sandbox-name> -- -c   # runs claude --dangerously-skip-permissions -c
```

When the first argument is a bare word, such as the `agents` subcommand, it
replaces the defaults instead.

See the [Claude Code CLI reference](https://code.claude.com/docs/en/cli-reference)
for available options.

## Agents view

Claude Code's [agents view](https://code.claude.com/docs/en/agent-view)
starts background sessions that run tasks in parallel. Pair it with
[clone mode](../workflows/git.md#clone-mode) to keep their changes inside the
sandbox:

```console
$ sbx run --clone claude . -- agents
```

This invocation replaces the
[default startup command](#default-startup-command), so it doesn't
include `--dangerously-skip-permissions` and you can't switch to
bypass-permissions mode inside the sandbox. To work around this, either
use Claude Code's auto mode or pass the flag explicitly:

```console
$ sbx run --clone claude . -- --dangerously-skip-permissions agents
```

Claude Code may use branches or worktrees to keep changes from its background
sessions separate. This depends on the task, Claude Code configuration, and
project instructions. The `--clone` flag doesn't control this behavior. Claude
Code creates any branches and worktrees inside the sandbox, not in your host
checkout.

To review a branch created by a session, fetch the
`sandbox-<sandbox-name>` remote from the host:

```console
$ git fetch sandbox-<sandbox-name>
$ git diff main..sandbox-<sandbox-name>/<branch>
```

See [Git workflows](../workflows/git.md) for clone-mode details.

## Base image

The sandbox uses `docker/sandbox-templates:claude-code`. See
[Templates](../customize/templates.md) to build your own image on top of
this base.

## Use a local model

The `--model` flag routes Claude Code's Anthropic API requests to a model
served on your host. This feature is experimental and isn't supported on
Windows.

Enable the feature:

```console
$ sbx settings set platform.allowExperimentalFeatures true
$ sbx settings set feature.model true
```

To use the bundled `llmman` model server, pass a GGUF model reference or short
name:

```console
$ sbx run --model gemma4 claude
```

On first use, `sbx` starts `llmman`, pulls the model, and leaves the server
running on your host. Later sandboxes reuse the server and its model store.

To use an existing Ollama installation instead, set the provider to `ollama`:

```console
$ sbx run --model gemma4 --provider ollama claude
```

Ollama must already be installed and running. `sbx` connects to it but doesn't
start or manage the Ollama process.

You can also change the model for an existing sandbox:

```console
$ sbx run --name <sandbox-name> --model <model-name>
```

Changing the model recreates the sandbox container. The workspace and
kit-owned volumes persist.

To use Docker Model Runner instead, see
[Run Claude Code in a Docker Sandbox with Docker Model Runner](/guides/claude-code-sandbox-model-runner/).


---

# Codex

*Sección: Ai*

This guide covers authentication, configuration, and usage of Codex in a
sandboxed environment.

Official documentation: [Codex CLI](https://developers.openai.com/codex/cli)

## Quick start

Create a sandbox and run Codex for a project directory:

```console
$ sbx run codex ~/my-project
```

`sbx run` defaults the workspace to the current directory:

```console
$ cd ~/my-project
$ sbx run codex
```

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name.

## Authentication

If you haven't stored an OpenAI credential, `sbx run codex` prompts you to
authenticate on your host before launching the sandbox. The flow runs on the
host, so credentials are never exposed inside the sandbox.

To set up authentication ahead of time, choose one of the following methods.

**OAuth**: Start the OAuth flow on your host with:

```console
$ sbx secret set openai --oauth
```

This opens a browser window for authentication and stores the resulting tokens
in your OS keychain. The OAuth flow runs on the host, not inside the sandbox,
so browser-based authentication works without any extra setup.

**API key**: Store your OpenAI API key using
[stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set openai
```

See [Credentials](../configuration/credentials.md) for more details.

## Configuration

Sandboxes don't pick up user-level configuration from your host, such as
`~/.codex`. Only project-level configuration in the working directory is
available inside the sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

### Default startup command

Without extra args, the sandbox runs:

```text
codex --dangerously-bypass-approvals-and-sandbox
```

Arguments after `--` are added after the default flags when the first one is
itself a flag (begins with `-`). A bare word — such as a prompt — replaces the
defaults instead, so lead with the flag to keep bypass mode:

```console
$ sbx run --name <sandbox-name> -- --dangerously-bypass-approvals-and-sandbox "fix the build"
```

## Base image

Template: `docker/sandbox-templates:codex`

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Copilot

*Sección: Ai*

This guide covers authentication, configuration, and usage of GitHub Copilot
in a sandboxed environment.

Official documentation: [GitHub Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli)

## Quick start

> [!NOTE]
> In Docker Sandboxes v0.42, use `sbx run docker.io/sbx/copilot-kit:latest`.
> The `copilot` shorthand is unavailable in this release.

Create a sandbox and run Copilot for a project directory:

```console
$ sbx run copilot ~/my-project
```

The workspace parameter is optional and defaults to the current directory:

```console
$ cd ~/my-project
$ sbx run copilot
```

## Authentication

Copilot requires a GitHub token with Copilot access. Store your token using
[stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set github --command 'gh auth token'
```

## Configuration

Sandboxes don't pick up user-level configuration from your host. Only
project-level configuration in the working directory is available inside the
sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

Copilot is configured to trust the workspace directory by default, so it
operates without repeated confirmations for workspace files.

### Default startup command

Without extra args, the sandbox runs:

```text
copilot --yolo
```

Arguments after `--` are added after the default flags when the first one is
itself a flag (begins with `-`), so `--yolo` is preserved:

```console
$ sbx run copilot -- -p "review this PR"   # runs copilot --yolo -p "review this PR"
```

When the first argument is a bare word — a subcommand or prompt — it replaces
the defaults instead.

## Base image

Template: `docker/sandbox-templates:copilot`

Preconfigured to trust the workspace directory.

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Cursor

*Sección: Ai*

This guide covers authentication, configuration, and usage of Cursor in a
sandboxed environment.

Official documentation: [Cursor CLI](https://cursor.com/cli)

## Quick start

Create a sandbox and run Cursor for a project directory:

```console
$ sbx run cursor ~/my-project
```

`sbx run` defaults the workspace to the current directory:

```console
$ cd ~/my-project
$ sbx run cursor
```

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name.

## Authentication

Cursor supports two authentication methods: an API key or OAuth.

**API key**: Store your Cursor API key using
[stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set cursor
```

**OAuth**: If no API key is set, Cursor prompts you to sign in interactively
on first run. The proxy intercepts the token exchange with
`api2.cursor.sh/auth/poll`, so credentials are managed by the host and aren't
stored inside the sandbox.

## Configuration

Sandboxes don't pick up user-level configuration from your host, such as
`~/.cursor`. Only project-level configuration in the working directory is
available inside the sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

Cursor reads `AGENTS.md` from the workspace for agent-specific instructions.

### Default startup command

Without extra args, the sandbox runs:

```text
cursor-agent --yolo
```

Arguments after `--` are added after the default flags when the first one is
itself a flag (begins with `-`), so `--yolo` is preserved:

```console
$ sbx run --name <sandbox-name> -- -p "refactor this"   # runs cursor-agent --yolo -p "refactor this"
```

When the first argument is a bare word — a subcommand or prompt — it replaces
the defaults instead.

## Base image

Template: `docker/sandbox-templates:cursor-agent-docker`

Preconfigured with HTTP/1.1 and server-sent events for agent traffic so
requests flow through the host proxy. Authentication state is persisted across
sandbox restarts.

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Devin

*Sección: Ai*

Official documentation: [Devin CLI](https://docs.devin.ai/work-with-devin/devin-cli)

## Quick start

Create a sandbox and run Devin for a project directory:

```console
$ sbx run devin ~/my-project
```

The workspace parameter is optional and defaults to the current directory:

```console
$ cd ~/my-project
$ sbx run devin
```

## Authentication

On first run, Devin prompts you to sign in interactively inside the sandbox.
After you sign in, Docker Sandboxes manages the reusable credential on the host
and supplies it to future Devin sandboxes through the proxy.

## Configuration

Sandboxes don't pick up user-level Devin configuration from your host. Only
project-level configuration in the working directory is available inside the
sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

Devin reads `AGENTS.md` from the workspace for agent-specific instructions and
uses the [shared agent skills](../workflows/agent-skills.md) store.

### Default startup command

Without extra args, the sandbox runs:

```text
devin --permission-mode dangerous --respect-workspace-trust=false
```

## Base image

Template: `docker/sandbox-templates:devin-docker`

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Docker Agent

*Sección: Ai*

Official documentation: [Docker Agent](../../docker-agent/index.md)

## Quick start

Create a sandbox and run Docker Agent for a project directory:

```console
$ sbx run docker-agent ~/my-project
```

`sbx run docker-agent` defaults the workspace to the current directory, so you
can run it from inside your project.

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name.

## Authentication

Docker Agent supports multiple providers. Store keys for the providers you want
to use with [stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set openai
$ sbx secret set anthropic
$ sbx secret set google
$ sbx secret set xai
$ sbx secret set nebius
$ sbx secret set mistral
$ sbx secret set openrouter
```

You only need to configure the providers you want to use. Docker Agent detects
available credentials and routes requests to the appropriate provider.

## Configuration

Sandboxes don't pick up user-level configuration from your host. Only
project-level configuration in the working directory is available inside the
sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

### Default startup command

Without extra args, the sandbox runs:

```text
docker-agent run --yolo
```

Arguments after `--` are added after the default flags when the first one is
itself a flag (begins with `-`). When the first argument is a bare word — such
as the `run` subcommand or a config file — it replaces the defaults, so include
`run --yolo` yourself:

```console
$ sbx run --name <sandbox-name> -- run --yolo agent.yml
```

## Base image

The sandbox uses `docker/sandbox-templates:docker-agent`. See
[Templates](../customize/templates.md) to build your own image on top of
this base.


---

# Droid

*Sección: Ai*

This guide covers authentication, configuration, and usage of Droid, an AI
coding agent by Factory, in a sandboxed environment.

Official documentation: [Droid](https://docs.factory.ai/)

## Quick start

> [!NOTE]
> In Docker Sandboxes v0.42, use `sbx run docker.io/sbx/droid-kit:latest`.
> The `droid` shorthand is unavailable in this release.

Create a sandbox and run Droid for a project directory:

```console
$ sbx run droid ~/my-project
```

The workspace parameter is optional and defaults to the current directory:

```console
$ cd ~/my-project
$ sbx run droid
```

## Authentication

Droid requires a [Factory account](https://factory.ai). Both authentication
methods authenticate you to Factory's service directly — unlike other agents
where you supply a model provider key, Factory manages model access through
your Factory account.

**API key**: Store your Factory API key using
[stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set droid
```

**OAuth**: If no API key is set, Droid prompts you to authenticate
interactively on first run. The proxy handles the OAuth flow, so credentials
aren't stored inside the sandbox.

## Configuration

Sandboxes don't pick up user-level configuration from your host. Only
project-level configuration in the working directory is available inside the
sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

### Default startup command

The sandbox runs `droid` with no implicit flags. Args after `--` are passed
straight through:

```console
$ sbx run droid -- exec "fix the build"
```

## Base image

Template: `docker/sandbox-templates:droid-docker`

Preconfigured to run without approval prompts. Authentication state is
persisted across sandbox restarts.

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Gemini

*Sección: Ai*

This guide covers authentication, configuration, and usage of Google Gemini in
a sandboxed environment.

Official documentation: [Gemini CLI](https://geminicli.com/docs/)

## Quick start

Create a sandbox and run Gemini for a project directory:

```console
$ sbx run gemini ~/my-project
```

`sbx run` defaults the workspace to the current directory:

```console
$ cd ~/my-project
$ sbx run gemini
```

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name.

## Authentication

Gemini requires either a Google API key or a Google account with Gemini access.

**API key**: Store your key using
[stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set google
```

**Google account**: If no API key is set, Gemini prompts you to sign in
interactively when it starts. Interactive authentication is scoped to the
sandbox and doesn't persist if you remove and recreate it.

## Configuration

Sandboxes don't pick up user-level configuration from your host, such as
`~/.gemini`. Only project-level configuration in the working directory is
available inside the sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

The sandbox disables Gemini's built-in sandbox tool (since the sandbox itself
provides isolation).

### Default startup command

Without extra args, the sandbox runs:

```text
gemini --yolo
```

Arguments after `--` are added after the default flags when the first one is
itself a flag (begins with `-`), so `--yolo` is preserved:

```console
$ sbx run --name <sandbox-name> -- -p "explain this"   # runs gemini --yolo -p "explain this"
```

When the first argument is a bare word — a subcommand or prompt — it replaces
the defaults instead.

## Base image

Template: `docker/sandbox-templates:gemini`

Gemini is configured to disable its built-in OAuth flow. Authentication is
managed through the proxy with API keys.

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Kiro

*Sección: Ai*

This guide covers authentication, configuration, and usage of Kiro in a
sandboxed environment.

Official documentation: [Kiro CLI](https://kiro.dev/docs/cli/)

## Quick start

> [!NOTE]
> In Docker Sandboxes v0.42, use `sbx run docker.io/sbx/kiro-kit:latest`.
> The `kiro` shorthand is unavailable in this release.

Create a sandbox and run Kiro for a project directory:

```console
$ sbx run kiro ~/my-project
```

The workspace parameter is optional and defaults to the current directory:

```console
$ cd ~/my-project
$ sbx run kiro
```

On first run, Kiro prompts you to authenticate using device flow.

## Authentication

Kiro uses device flow authentication, which requires interactive login through
a web browser. This method provides secure authentication without storing API
keys directly.

### Device flow login

When you first run Kiro, it prompts you to authenticate:

1. Kiro displays a URL and a verification code
2. Open the URL in your web browser
3. Enter the verification code
4. Complete the authentication flow in your browser
5. Return to the terminal - Kiro proceeds automatically

The authentication session is persisted in the sandbox and doesn't require
repeated login unless you destroy and recreate the sandbox.

### Manual login

You can trigger the login flow manually:

```console
$ sbx run kiro --name <sandbox-name> -- login --use-device-flow
```

This command initiates device flow authentication without starting a coding
session.

### Authentication persistence

Kiro stores authentication state in `~/.local/share/kiro-cli/data.sqlite3`
inside the sandbox. This database persists as long as the sandbox exists. If
you destroy the sandbox, you'll need to authenticate again when you recreate
it.

## Configuration

Sandboxes don't pick up user-level configuration from your host. Only
project-level configuration in the working directory is available inside the
sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

Kiro requires minimal configuration. The agent runs with trust-all-tools mode
by default, which lets it execute commands without repeated approval prompts.

### Default startup command

Without extra args, the sandbox runs:

```text
kiro chat --trust-all-tools
```

When the first argument after `--` is a flag (begins with `-`), it's added
after the defaults — for example, `sbx run kiro -- --resume` runs
`kiro chat --trust-all-tools --resume`. When the first argument is a bare word,
it replaces the defaults, which is why `sbx run kiro -- login --use-device-flow`
runs the login subcommand on its own. To run `chat` with extra arguments of
your own, include the subcommand:

```console
$ sbx run kiro -- chat --trust-all-tools --resume
```

## Base image

Template: `docker/sandbox-templates:kiro`

Authentication state is persisted across sandbox restarts.

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# OpenCode

*Sección: Ai*

This guide covers authentication, configuration, and usage of OpenCode in a
sandboxed environment.

Official documentation: [OpenCode](https://opencode.ai/docs)

## Quick start

Create a sandbox and run OpenCode for a project directory:

```console
$ sbx run opencode ~/my-project
```

`sbx run` defaults the workspace to the current directory:

```console
$ cd ~/my-project
$ sbx run opencode
```

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name.

OpenCode launches a TUI (text user interface) where you can select your
preferred LLM provider and interact with the agent.

## Authentication

OpenCode supports multiple providers. Store keys for the providers you want to
use with [stored secrets](../configuration/credentials.md#stored-secrets):

```console
$ sbx secret set openai
$ sbx secret set anthropic
$ sbx secret set google
$ sbx secret set xai
$ sbx secret set groq
$ sbx secret set aws
$ sbx secret set openrouter
```

You only need to configure the providers you want to use. OpenCode detects
available credentials and offers those providers in the TUI.

### OpenCode Zen API keys

OpenCode Zen API keys aren't part of the built-in OpenCode credentials that
`sbx secret set` supports. To use an OpenCode Zen API key, store it as a
[custom secret](../configuration/credentials.md#custom-secrets):

Set the `OPENCODE_API_KEY` environment variable on the host, then store it:

```console
$ sbx secret set-custom \
    --host opencode.ai \
    --env OPENCODE_API_KEY \
    --value "$OPENCODE_API_KEY"
```

Custom secrets keep the real key in the host secret store. The sandbox receives
`OPENCODE_API_KEY` as a placeholder, and the host-side proxy replaces that
placeholder with the real key on requests to `opencode.ai`.

OpenCode Zen also requires network access to `opencode.ai`:

```console
$ sbx policy allow network opencode.ai:443
```

If you add a global custom secret, recreate existing OpenCode sandboxes so the
new environment variable is available inside the sandbox.

## Configuration

Sandboxes don't pick up user-level configuration from your host. Only
project-level configuration in the working directory is available inside the
sandbox. See
[Why doesn't the sandbox use my user-level agent configuration?](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for workarounds.

OpenCode uses a TUI interface and doesn't require extensive configuration
files. The agent prompts you to select a provider when it starts, and you can
switch providers during a session.

### Default startup command

The sandbox runs `opencode` with no implicit flags. Args after `--` are passed
straight through. For example, to resume an existing session:

```console
$ sbx run --name <sandbox-name> -- -s <session-id>
```

### TUI mode

OpenCode launches in TUI mode by default. The interface shows:

- Available LLM providers (based on configured credentials)
- Current conversation history
- File operations and tool usage
- Real-time agent responses

Use keyboard shortcuts to navigate the interface and interact with the agent.

## Base image

Template: `docker/sandbox-templates:opencode`

OpenCode supports multiple LLM providers with automatic credential injection
through the sandbox proxy.

See [Customize](../customize/) to pre-install tools or customize this
environment.


---

# Shell

*Sección: Ai*

`sbx run shell` drops you into a Bash login shell inside a sandbox with no
pre-installed agent binary. It's useful for installing and configuring
agents manually, testing custom implementations, or inspecting a running
environment.

```console
$ sbx run shell ~/my-project
```

`sbx run` defaults the workspace to the current directory. To run a one-off
command instead of an interactive shell, pass it after `--`:

```console
$ sbx run shell -- -c "echo 'Hello from sandbox'"
```

To create a [mountless sandbox](../usage.md#choose-a-workspace), use
`sbx create` without a workspace path, then attach by name:

```console
$ sbx create --name scratch shell
$ sbx run --name scratch
```

## Default startup command

Without extra args, the sandbox runs `bash -l`. When the first argument after
`--` is a flag (begins with `-`), it's added after `-l`, so login-shell
behavior is preserved:

```console
$ sbx run shell -- -c "echo hi"   # runs bash -l -c "echo hi"
```

When the first argument is a bare word, it replaces `-l` instead.

Store credentials using [stored secrets](../configuration/credentials.md#stored-secrets)
before running the sandbox. The proxy injects them into outbound API requests;
credentials are never stored inside the VM:

```console
$ sbx secret set anthropic
$ sbx secret set openai
```

Once inside the shell, you can install agents using their standard methods,
for example `npm install -g @continuedev/cli`. For complex setups, build a
[custom template](../customize/templates.md) instead of installing
interactively each time.

## Base image

The shell sandbox uses the `shell` base image — the common base environment
without a pre-installed agent.


---

# Architecture

*Sección: Ai*

This page explains how Docker Sandboxes work under the hood. For the security
properties of the architecture, see [Sandbox isolation](security/isolation.md).

## Workspace storage

Starting with `sbx` version 0.42.0, workspace paths are optional for
`sbx create`. When you omit them, the sandbox has no host workspace bind mount.
The sandbox uses the template image's configured `WORKDIR` as its default
working directory. Docker-provided agent templates set `WORKDIR` to
`/home/agent/workspace`. A custom template can set another absolute path. If
the daemon can't resolve a usable absolute `WORKDIR` from the image config, it
falls back to `/home/agent/workspace`. Files created there stay inside the
sandbox and persist across stops and restarts.

When you pass a workspace path to `sbx create` or `sbx run`, the directory is
mounted into the sandbox through a filesystem passthrough. `sbx run` uses the
current directory when you don't pass a path. The sandbox sees your actual
host files, so changes in either direction are instant with no sync process
involved.

A directly mounted workspace appears at the same absolute path as on your
host. Preserving absolute paths means error messages, configuration files, and
build outputs all reference paths you can find on your host. The agent sees the
same directory structure, which reduces confusion when debugging or reviewing
changes.

Clone mode uses a third storage layout. The host repository is mounted
read-only at `/run/sandbox/source`, and the agent works in a private clone
inside the sandbox. See [Clone mode](usage.md#clone-mode).

> [!WARNING]
> Avoid mounting network-attached or remote storage (network drives, SMB/NFS
> shares, or cloud-synced folders) as a workspace. The sandbox accesses
> workspaces through a filesystem passthrough, so every file read and write
> goes over the network. This adds latency and slows agent performance.

## Storage and persistence

When you create a sandbox, everything inside it persists until you remove it:
Docker images and containers built or pulled by the agent, installed packages,
agent state and history, and files in mountless or cloned workspaces. Files in
a directly mounted workspace live on the host instead.

Each sandbox maintains its own Docker daemon state, image cache, and package
installations. Multiple sandboxes don't share images or layers. The
[shared agent skills store](workflows/agent-skills.md) is an exception:
supported agents mount the same host-side store read-write unless you opt out
when creating the sandbox.

Each sandbox consumes disk space for its VM image, Docker images, container
layers, and volumes, and this grows as you build images and install packages.

Virtiofs caching is enabled by default for directly mounted workspaces on all
operating systems. File reads from the sandbox VM are cached on the host side,
reducing round-trips through the filesystem passthrough and improving
performance for read-heavy workloads such as `git status` or directory scans.
To opt out, set
`DOCKER_SANDBOXES_ENABLE_VIRTIOFS_CACHE=0` when creating the sandbox:

```console
$ DOCKER_SANDBOXES_ENABLE_VIRTIOFS_CACHE=0 sbx run <agent>
```

## Networking

All outbound TCP traffic from the sandbox routes through a proxy on your host.
Agents use a forward proxy for HTTP and HTTPS; other TCP traffic is forwarded
transparently. Both paths enforce
[network access policies](governance/access-controls/network.md). The forward
proxy also handles [credential injection](configuration/credentials.md). See
[Network isolation](security/isolation.md#network-isolation) for how this
works and [Default security posture](security/defaults.md) for what is
allowed out of the box.

### Upstream proxy

The host-side proxy makes its outbound connections using your host's network
configuration and routing. When a destination is reachable through a direct
route, traffic follows that route. When reaching a destination requires an
upstream proxy, the host-side proxy forwards the request to it. Chaining to an
upstream proxy means sandbox traffic respects the same egress controls as other
applications on your host.

By default, both sandbox traffic and the daemon's own traffic follow your OS
system proxy, so this usually works without any configuration. To set a proxy
explicitly — with a proxy URL, a PAC file, a SOCKS5 proxy, or separate settings
for sandbox and daemon traffic — see
[Configure an upstream proxy](configuration/upstream-proxy.md). Upstream proxy support is
experimental and subject to change.

Only HTTP and HTTPS traffic can be forwarded to an upstream proxy. Other TCP
traffic can't be redirected to a proxy.

## MCP gateway

Supported agents connect to a single MCP gateway endpoint for the sandbox. The
gateway runs on the host side of the sandbox boundary and brokers access to
registered MCP servers.

Registered MCP servers can be remote endpoints, or they can be local stdio
servers launched on the host. Local stdio servers don't run inside the sandbox
VM. If a local stdio server is packaged as an OCI image, or if you register an
explicit `docker` command, it uses Docker on the host.

When MCP policies apply, enforcement happens on the MCP gateway path, separate
from the HTTP/HTTPS network proxy. Server registration is checked before the
server is stored, and governed MCP requests are checked by the gateway before
tool calls, resource reads, prompt retrieval, or gateway meta-tool execution.

## Lifecycle

`sbx run` initializes a VM for a specified agent and starts the agent. You can
stop and restart without recreating the VM, preserving installed packages,
Docker images, and in-sandbox files.

Sandboxes persist until explicitly removed. Stopping an agent doesn't delete
the VM; environment setup carries over between runs. Use `sbx rm` to delete
the sandbox, its VM, and all of its contents. If the sandbox used
[`--clone`](usage.md#clone-mode), the `sandbox-<name>` Git remote is also
removed from your host repository.

## Comparison to alternatives

| Approach                                            | Isolation            | Docker access      | Use case           |
| --------------------------------------------------- | -------------------- | ------------------ | ------------------ |
| Sandboxes (microVMs)                                | Full (hypervisor)    | Isolated daemon    | Autonomous agents  |
| Container with socket mount                         | Partial (namespaces) | Shared host daemon | Trusted tools      |
| [Docker-in-Docker](https://hub.docker.com/_/docker) | Partial (privileged) | Nested daemon      | CI/CD pipelines    |
| Host execution                                      | None                 | Host daemon        | Manual development |

Sandboxes trade higher resource overhead (a VM plus its own daemon) for
complete isolation. Use containers when you need lightweight packaging without
Docker access. Use sandboxes when you need to give something autonomous full
Docker capabilities without trusting it with your host environment.


---

# Configure Docker Sandboxes

*Sección: Ai*

Configure credentials and how Docker Sandboxes run for a project, host, or
network environment. These settings control sandbox creation, authentication,
and connectivity. To change the tools and agent configuration inside a
sandbox, see [Customize](../customize/).

- [Credentials](credentials.md) configures API keys, authentication
  credentials, and registry access for sandboxed agents.
- [Environment files](environment-files.md) declare reusable project
  configuration in `sbxenv.yaml`.
- [GPU passthrough](gpu-passthrough.md) configures a Linux host and sandbox for
  NVIDIA GPU workloads.
- [Registry mirror](registry-mirror.md) routes Docker Hub template, kit, and
  in-sandbox Docker image pulls through an organization's registry mirror.
- [Upstream proxy](upstream-proxy.md) routes sandbox and daemon traffic through
  an operating system or corporate proxy.


---

# Manage credentials

*Sección: Ai*

Most agents need an API key for their model provider. An HTTP/HTTPS proxy on
your host intercepts outbound requests from the sandbox, looks up the matching
credential on the host, and overwrites the auth header before forwarding. The
real credential stays on the host when proxy management is active; the sandbox
sees only a sentinel value. See
[Trust boundaries](../security/index.md#trust-boundaries) for how credential isolation
fits into the broader sandbox security model.

## How credential injection works

When a sandbox makes an outbound request, the host-side proxy decides three
things: whether the request **matches** a service the kit (or built-in agent)
declares, what **header** to write, and what **value** to inject. The kit
declares the match and the header; you provide the value on the host. For
proxy-managed credentials, the real value never enters the sandbox — the agent
sees only a sentinel like `proxy-managed`.

A kit can set OAuth `passthrough: true` to opt out of sentinel masking. This
sends the real token response into the sandbox and reduces credential isolation.
See the [`oauth` kit fields](../customize/kit-reference.md#oauth).

There are several ways to provide that value. When more than one source has a
value for the same service, the stored secret takes precedence.

| Form                                                                        | What it is                                                   | Use it when                                                                                                      |
| --------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
| [Stored secrets](#stored-secrets) (`sbx secret set`)                        | A value or dynamic source in your OS keychain, keyed by service | The default for any built-in or kit-declared service                                                          |
| [Custom secrets](#custom-secrets) (`sbx secret set-custom`)                 | A value keyed to a domain and environment variable           | The service model doesn't fit — the agent validates the variable's format, or the secret rides in a request body |
| OAuth                                                                       | A host-side sign-in flow; the token never enters the sandbox | The agent supports it, such as Claude Code, Codex, Cursor, or Droid                                              |
| [Credential bindings](#credential-bindings) (`credentials.yaml`)            | Per-service mechanism and domain approval                    | Required for third-party `schemaVersion: "2"` kits                                                               |
| [Registry credentials](#registry-credentials) (`sbx secret set --registry`) | Authentication for pulling images and kits                   | Pulling templates or kits from a private registry                                                                |

For multi-provider agents (OpenCode, Docker Agent), the proxy selects
credentials based on the API endpoint being called. See individual
[agent pages](../agents/) for provider-specific details.

## Stored secrets

`sbx secret set` stores credential values or dynamic secret sources in your OS
keychain, keyed on a service identifier. Built-in agents declare a fixed set of
services. Custom kits can declare their own. The same `sbx secret set` flow
works for both.

### Where secrets are stored

The store backing `sbx secret set` depends on your operating system:

- macOS: the system Keychain.
- Windows: the Windows Credential Manager.
- Linux: the Secret Service exposed by your desktop keyring, such as GNOME
  Keyring or KDE Wallet.

The Ubuntu package depends on GNOME Keyring, so a standard desktop install
needs no extra setup.

On Linux hosts without a running Secret Service — headless servers and some WSL
setups — `sbx` falls back to a file under your user config directory
`$XDG_CONFIG_HOME/com.docker.sandboxes`, which defaults to
`~/.config/com.docker.sandboxes` when `$XDG_CONFIG_HOME` is unset. The fallback
is automatic and needs no configuration. When you store a secret this way,
`sbx` prints a notice:

```text
No keychain detected - this secret will be stored on disk, protected by file permissions rather than a password
```

`sbx` stores the file in a directory with `0700` permissions, the same
file-permission model used for `~/.docker/config.json`. Any user or process that
can read the file can retrieve the stored credentials, so treat the directory as
sensitive. Where available, prefer a keychain, which mediates access per
application.

If you start a Secret Service on the host later, `sbx` stores new secrets in the
keychain again. For more on running sandboxes without a desktop keyring, see
[Can I use Docker Sandboxes on headless Linux?](../faq.md#can-i-use-docker-sandboxes-on-headless-linux)

### Store a secret

```console
$ sbx secret set anthropic
```

This prompts you for the secret value interactively. Service secrets are
global by default, so the secret is available to all sandboxes. To scope a
secret to a specific sandbox instead:

```console
$ sbx secret set openai --sandbox my-sandbox
```

> [!NOTE]
> A sandbox-scoped secret takes effect immediately, even if the sandbox is
> running. A global secret only applies when a sandbox is created. If
> you set or change a global secret while a sandbox is running, recreate the
> sandbox for the new value to take effect.

### Use a dynamic secret source

Dynamic secret sources let `sbx` retrieve a credential from an authenticated
host tool when the proxy needs it. The secret store contains the reference or
command instead of the credential value. Resolution and caching happen on the
host, and the sandbox still receives only the proxy-managed placeholder.

Use `--ref` with a 1Password secret reference or an AWS Secrets Manager ARN:

```console
$ sbx secret set anthropic --ref 'op://Work/Anthropic/credential'
$ sbx secret set openai \
    --ref 'arn:aws:secretsmanager:us-west-2:123456789012:secret:openai-api-key'
```

The corresponding `op` or `aws` CLI must be installed and authenticated on the
host.

> [!NOTE]
> To resolve a reference with a specific 1Password account or AWS profile, set
> `OP_ACCOUNT` or `AWS_PROFILE` when you run `sbx secret set`. `sbx` uses that
> account or profile whenever it resolves the secret. If neither variable is
> set, the provider CLI uses its default.

Use `--command` for another host tool that prints a secret to standard output:

```console
$ sbx secret set github --command 'gh auth token'
```

`sbx` runs the command through the host shell and trims its output. The command
text is stored and replayed by the daemon. Don't embed a secret directly in the
command because the text can appear in shell history and process listings.

By default, `sbx` verifies the source when you register it and reports an error
without exposing the resolver's standard error. Use `--no-verify` to store a
source that can't be resolved during registration. To troubleshoot an initial
verification failure, use `--show-error`. Provider error output can contain
sensitive information. You can't combine `--show-error` with `--no-verify`.

Resolved service secrets are cached for 55 minutes by default. To change the
cache duration, use `--refresh <duration>`. To resolve the source for every
credential use instead of caching it, pass `--refresh on-demand`:

```console
$ sbx secret set anthropic \
    --ref 'op://Work/Anthropic/credential' \
    --refresh 30m
$ sbx secret set github --command 'gh auth token' --refresh on-demand
```

`--ref` and `--command` are mutually exclusive. They can't be combined with
`--token`, `--oauth`, or `--registry`.

### Import from environment variables

If you already have API keys set in your shell, `sbx secret import` reads them
and stores them in the keychain without typing each value manually:

```console
$ sbx secret import
```

This scans your current session for the environment variables in the
[built-in services table](#built-in-services) below and prompts you to confirm
each one before writing. To import a single service:

```console
$ sbx secret import openai
```

Pass `--all` to import everything without prompting (new entries only; existing
entries are left unchanged), or `--force` to overwrite existing entries:

```console
$ sbx secret import --all
$ sbx secret import openai --force
```

Pass `--dry-run` to preview what would be imported without writing anything.
Run `sbx secret ls` afterwards to confirm what's stored. For setting up
credentials in CI, see [CI and headless use](../workflows/automation.md).

### Built-in services

Each built-in service name maps to the environment variables `sbx secret import`
reads and the API domains the proxy injects credentials into:

| Service      | Environment variables              | API domains                                                                                                                   |
| ------------ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `anthropic`  | `ANTHROPIC_API_KEY`                | `api.anthropic.com`, `console.anthropic.com`, `claude.ai`, `mcp-proxy.anthropic.com`                                          |
| `cursor`     | `CURSOR_API_KEY`                   | `api2.cursor.sh`, `api3.cursor.sh`, `repo42.cursor.sh`, `cursor.com`                                                          |
| `droid`      | `FACTORY_API_KEY`                  | `api.factory.ai`, `app.factory.ai`, `relay.factory.ai`                                                                        |
| `github`     | `GH_TOKEN`, `GITHUB_TOKEN`         | `api.github.com`, `github.com`, `raw.githubusercontent.com`, `gist.github.com`, `copilot.github.com`, `api.githubcopilot.com` |
| `google`     | `GEMINI_API_KEY`, `GOOGLE_API_KEY` | `generativelanguage.googleapis.com`, `oauth2.googleapis.com`, `aiplatform.googleapis.com`, `vertexai.googleapis.com`          |
| `groq`       | `GROQ_API_KEY`                     | `api.groq.com`                                                                                                                |
| `mistral`    | `MISTRAL_API_KEY`                  | `api.mistral.ai`                                                                                                              |
| `nebius`     | `NEBIUS_API_KEY`                   | `api.studio.nebius.com`, `api.tokenfactory.nebius.com`                                                                        |
| `openai`     | `OPENAI_API_KEY`                   | `api.openai.com`, `openai.com`, `chatgpt.com`, `www.chatgpt.com`                                                              |
| `openrouter` | `OPENROUTER_API_KEY`               | `openrouter.ai`                                                                                                               |
| `xai`        | `XAI_API_KEY`                      | `api.x.ai`                                                                                                                    |

When you store a secret with `sbx secret set <service>`, the proxy injects
it into requests to the listed API domains.

### Services declared by kits

Custom kits can declare their own service identifiers in `spec.yaml`. In
`schemaVersion: "2"`, credentials are declared under the `credentials:` list:

```yaml
credentials:
  - service: my-service
    apiKey:
      name: MY_SERVICE_TOKEN
      proxyManaged: true
      inject:
        - domain: api.my-service.com
          scheme: bearer
```

Each service declares `apiKey`, `oauth`, or both. When both resolve at runtime,
the API key takes precedence and OAuth acts as the fallback. To provide the
credential value, run `sbx secret set` with the same identifier the kit
declares:

```console
$ sbx secret set my-service
```

There's no separate registration step; the keychain entry is keyed on the
identifier the kit already uses. See
[Authenticate to external services](../customize/kits.md#authenticate-to-external-services)
for the full kit-side wiring.

### List and remove secrets

List all stored secrets:

```console
$ sbx secret ls
SCOPE      TYPE      NAME      SECRET
(global)   service   github    gho_GCaw4o****...****43qy
```

Remove a secret:

```console
$ sbx secret rm github
```

> [!NOTE]
> Running `sbx reset` deletes all stored secrets along with all sandbox state.
> You'll need to re-add your secrets after a reset.

### GitHub token

The `github` service gives the agent access to the `gh` CLI inside the
sandbox. Resolve your existing GitHub CLI token on the host:

```console
$ sbx secret set github --command 'gh auth token'
```

The daemon refreshes the token from the host command after the default cache
period. This is useful for agents that create pull requests, open issues, or
interact with GitHub APIs on your behalf.

### SSH agent

SSH agent forwarding is enabled by default. When `SSH_AUTH_SOCK` is set,
Docker Sandboxes uses the value from the client that creates, starts, or joins
each sandbox. It forwards that agent into the sandbox and sets `SSH_AUTH_SOCK`
there.

If your agent exposes a stable socket path, such as the 1Password SSH agent,
configure that path for every sandbox:

```console
$ sbx settings set ssh.agentSocketPath "$SSH_AUTH_SOCK"
```

An empty `ssh.agentSocketPath`, which is the default, uses each client's
current `SSH_AUTH_SOCK` instead. The `ssh.agentForwardingEnabled` setting is a
boolean that turns forwarding on or off.

After changing forwarding or the socket selection, restart the daemon so
existing sandboxes use the new configuration:

```console
$ sbx daemon restart
```

The private keys stay on your host. Processes inside the sandbox can request
signatures from the forwarded agent, but they can't read or copy a private key.

Use SSH agent forwarding for Git operations over SSH and SSH-based commit
signing. The signing key must be loaded in the host SSH agent for sandboxed
commit signing to work. Outbound SSH connections are still subject to sandbox
network policy. For details, see
[Commit signing](../workflows/git.md#commit-signing).

## Custom secrets

> [!IMPORTANT]
> Custom secrets are experimental. Behavior, flags, and the placeholder format may
> change without notice.

For credentials that don't fit the service-identifier model — for example,
when an agent validates the environment variable format at boot, or when the
credential lands in a request body rather than a header — use
`sbx secret set-custom`. The secret is keyed on one or more target domains, an
environment variable name, and an optional placeholder string, instead of a
service identifier.

Prefer the [service-based flow](#stored-secrets) whenever it's an option —
the kit handles the wiring; you only provide the value.

### Set a custom secret

Custom secrets are global by default. Pass `--sandbox` to scope one to a
specific sandbox.

```console
$ sbx secret set-custom \
    --host api.example.com \
    --env API_KEY \
    --value <secret>
```

> [!WARNING]
> Passing the secret as `--value <secret>` records it in your shell history
> and exposes it to other processes running as your user. Avoid pasting
> real credentials inline — read the value from a variable that's already
> in your environment, and clear shell history if a real secret was passed
> on the command line.

Inside the sandbox, `API_KEY` is set to a generated placeholder (for example,
`sbx-cs-<rand>`). When a sandboxed process sends a request to any of the
configured hosts and the placeholder appears anywhere in the request, the
proxy replaces it with the real value. The agent never sees the real secret.

### Target multiple hosts

Repeat `--host` to cover multiple domains with the same secret — useful when
an API is split across related hostnames or when two unrelated endpoints share
a credential:

```console
$ sbx secret set-custom \
    --host api.example.com \
    --host uploads.example.com \
    --env API_KEY \
    --value <secret>
```

A `--host` value can also use wildcards, with the same syntax as
[network rules](../governance/concepts.md#network-rules): `*` matches a
single label (`*.example.com` covers `api.example.com`) and `**` matches any
number (`**.example.com` covers `api.example.com` and `v2.api.example.com`).

### Resolve custom secrets dynamically

Custom secrets also accept [dynamic secret sources](#use-a-dynamic-secret-source).
Replace `--value` with either `--ref` or `--command`:

```console
$ sbx secret set-custom \
    --host api.example.com \
    --env API_KEY \
    --ref 'op://Work/Example/credential'
```

Dynamic custom secrets resolve on demand by default. Pass `--refresh` with a
duration to cache the resolved value. The verification and error-output flags
work the same as they do for service secrets. `--ref` and `--command` can't be
combined with `--value` or `--token`.

### Install npm packages from GitHub Packages

The built-in `github` service doesn't inject credentials into requests to
`npm.pkg.github.com`. To install private npm packages from GitHub Packages,
add a custom secret for that host.

On the host, authenticate the GitHub CLI with a token that can read the package.
GitHub documents a personal access token (classic) with at least `read:packages`
scope for this use. See
[Authenticating to GitHub Packages](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-npm-registry#authenticating-to-github-packages).
Then register the token source, replacing `my-sandbox` with your sandbox's name:

```console
$ sbx secret set-custom \
    --sandbox my-sandbox \
    --host npm.pkg.github.com \
    --env NODE_AUTH_TOKEN \
    --command 'gh auth token'
```

The command prints a generated placeholder. For an existing sandbox, set
`NODE_AUTH_TOKEN` to that placeholder using `sbx run -e` for an agent session,
or `/etc/sandbox-persistent.sh` for future sessions. See
[Set environment variables](../usage.md#set-environment-variables).
Use the placeholder, not the actual GitHub token.

Inside the sandbox, add the following entries to your project's `.npmrc`,
replacing `@my-org` with the package's scope. Keep `${NODE_AUTH_TOKEN}` literal
so npm reads the environment variable:

```ini
@my-org:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
```

Install the package inside the sandbox:

```console
$ npm install @my-org/my-package
```

Replace `@my-org/my-package` with your package name. npm sends the placeholder
to `npm.pkg.github.com`, and the proxy replaces it with the token retrieved by
`gh auth token` on the host.

## Credential bindings

A credential bindings file records which credential mechanisms and domains
you've approved for each service. It lives at
`~/.config/sbx/credentials.yaml`, or `%APPDATA%\sbx\credentials.yaml` on
Windows.

Third-party kits that declare `schemaVersion: "2"` require an approved binding
for each credential they use. `sbx` creates one interactively the first time you
run such a kit (see [First-run approval](#first-run-approval)); you can also
write entries by hand. Credentials declared only by embedded, built-in kits are
authorized by provenance and don't need a binding.

Each entry under `bindings` is keyed by a
[service identifier](#built-in-services) and approves one or both credential
mechanisms:

- `apiKey` — approves injecting the service's stored API key. The value comes
  from the [secret store](#stored-secrets) (`sbx secret set <service>`); the
  binding records approval, it doesn't hold or locate the value.
- `oauth` — approves the OAuth flow for the service. You sign in on the host,
  and the proxy handles token refresh and routing. OAuth domains include the
  token endpoint host and any resource hosts declared by the kit.

Each mechanism takes a `domains` list that records the domains you approved.
`sbx` asks for approval when a kit requests domains that the existing binding
doesn't cover.

```yaml
bindings:
  anthropic:
    apiKey:
      domains: [api.anthropic.com]
  github:
    apiKey:
      domains: [api.github.com, github.com]
```

A binding is only an approval record: the presence of `apiKey` or `oauth`
authorizes that mechanism. Declining a credential writes no entry at all.
The real credential isn't stored in this file.

### First-run approval

When a third-party kit needs a credential that has no binding, `sbx` walks you
through approving one. For an API key, you can use a value already in the secret
store or enter one at the prompt. For OAuth, you approve the sign-in flow. In
both cases, you approve the domains declared by the kit. `sbx` writes the entry
to `credentials.yaml`.

In non-interactive contexts (CI or `--detached`), there's no one to answer the
prompt. Without a binding, the sandbox starts with the credential withheld. If
the kit marks the credential as `required: true`, `sbx` also prints a warning.
Pre-create the binding by running the kit interactively once or by writing
`credentials.yaml` directly before running unattended.

The bindings file gates whether a third-party v2 kit can use a service
credential. The kit's credential injection rules and network permissions still
constrain which requests can carry the credential.

### Kits that require a binding

Only third-party kits that declare `schemaVersion: "2"` require a binding.
Built-in agents also use `schemaVersion: "2"`, but credentials declared only by
embedded kits are authorized by provenance and inject automatically. A
third-party kit that extends a built-in agent inherits its credentials, but not
its built-in provenance. The inherited credentials therefore require approval.
If a third-party kit declares the same service itself, that service also
requires approval. Kits on `schemaVersion: "1"` inject their declared
credentials without a binding.

## Registry credentials

Registry credentials authenticate to private OCI registries when pulling
[templates](../customize/templates.md) or [kits](../customize/kits.md), and can
also let the agent pull and push images from inside the sandbox through the
host-side proxy. Use `sbx secret set --registry <host>` to store them. For
Docker Hub, `sbx` reuses your `sbx login` session — no registry secret needed.
For other registries (GitHub Container Registry, ECR, ACR, self-hosted Nexus,
and so on), store credentials with `sbx secret set --registry`.

Choose the scope by adding `--all-sandboxes`, adding `--sandbox SANDBOX`, or
passing neither:

```text
sbx secret set [--all-sandboxes | --sandbox SANDBOX] --registry HOST
```

- **Host-only** (no scope flag): the `sbx` CLI uses it to pull templates
  and kits when creating a sandbox. The credential stays on the host and is
  never available inside the sandbox.
- **All sandboxes** (`--all-sandboxes`): same as host-only, plus the proxy
  authenticates registry login requests from sandboxes. The credential stays
  on the host and is never written to the sandbox filesystem. Use it when
  agents build and publish container images.
- **Sandbox-scoped** (`--sandbox SANDBOX`): same proxy behavior as
  `--all-sandboxes`, but only for the named sandbox. Use it when only one
  sandbox needs registry access.

### Store registry credentials

Pipe a token from stdin and target the registry hostname:

```console
$ gh auth token | sbx secret set --registry ghcr.io --password-stdin
```

For registries that require a username (for example, ACR with an admin
account), add `--username`:

```console
$ echo "$ACR_PASSWORD" | sbx secret set \
    --registry myregistry.azurecr.io \
    --username myuser \
    --password-stdin
```

Add `--all-sandboxes` to make the credential available to every new sandbox:

```console
$ gh auth token | sbx secret set --all-sandboxes --registry ghcr.io --password-stdin
$ sbx run claude
```

Store all-sandboxes registry credentials before creating a sandbox. Existing
sandboxes don't pick up all-sandboxes registry credentials added later. To add
registry access to an existing sandbox, use a sandbox-scoped credential instead.

To scope the credential to a single sandbox, store it under that sandbox's name:

```console
$ gh auth token | sbx secret set --sandbox my-app --registry ghcr.io --password-stdin
```

For Docker Hub, `sbx kit pull` and `sbx kit push` use the session from
`sbx login`. For other registries, both commands use these credentials. Both
commands fall back to the Docker credential store, so credentials from
`docker login` also work.

### Remove registry credentials

Remove both the host-only and all-sandboxes entries for a registry:

```console
$ sbx secret rm --registry ghcr.io -f
```

To remove only the all-sandboxes entry and leave the host-only credential in
place, pass `--all-sandboxes`:

```console
$ sbx secret rm --all-sandboxes --registry ghcr.io -f
```

To remove a sandbox-scoped credential, pass the sandbox name:

```console
$ sbx secret rm --sandbox my-sandbox --registry ghcr.io -f
```

## Best practices

- Use [stored secrets](#stored-secrets) to provide credentials. The OS keychain
  protects them at rest; on Linux hosts without a keychain they are held in a
  permission-protected file instead. See
  [Where secrets are stored](#where-secrets-are-stored).
- Don't set API keys manually inside the sandbox. Sandbox agents are
  pre-configured to use proxy-managed credentials.
- Registry credentials stay on the host and are injected by the proxy when a
  sandbox authenticates to the registry. Reserve them for sandboxes that need
  registry access, and prefer sandbox scope over `--all-sandboxes` to limit
  exposure.
- Several agents support OAuth as another secure option: the flow runs on the
  host, so the token is never exposed inside the sandbox. If you haven't stored
  a credential, the agent prompts you to authenticate — Codex prompts on the
  host from `sbx run codex`, while Claude Code, Cursor, and Droid prompt
  interactively inside the sandbox. To authenticate ahead of time, run
  `sbx secret set openai --oauth` for Codex or use `/login` inside Claude
  Code; Cursor and Droid have no ahead-of-time option, so their sign-in prompt
  appears when the agent starts. See the individual [agent pages](../agents/)
  for each agent's flow.
- If you store credentials in 1Password or AWS Secrets Manager, see
  [Sourcing credentials from 1Password](../workflows/authentication.md#source-credentials-from-1password)
  and [Sourcing credentials from AWS Secrets Manager](../workflows/authentication.md#source-credentials-from-aws-secrets-manager).

## Custom templates and placeholder values

When building custom templates or installing agents manually in a shell
sandbox, some agents require environment variables like `OPENAI_API_KEY` to be
set before they start. Set these to placeholder values (e.g. `proxy-managed`)
if needed. The proxy injects actual credentials regardless of the environment
variable value.


---

# Sandbox environment files

*Sección: Ai*

A sandbox environment file captures the setup for a project in a
`sbxenv.yaml` file. Share the file with project contributors so they use the
same agent, tools, resources, and credentials without reproducing CLI flags and
setup steps.

> [!NOTE]
> `sbx env` is experimental. The command interface and file format may change.

## Start an environment

Keep the environment file outside the directories you mount into the sandbox.
That includes the primary workspace and every `additionalWorkspaces` mount.
For example, place it beside your project:

```text
web-app-env/
├── sbxenv.yaml
└── web-app/
```

Create `web-app-env/sbxenv.yaml`. This example gives the agent a shared
environment variable and the Playwright browser-testing tools. It also
publishes the application's development port:

```yaml
schemaVersion: "1"
name: web-app
agent: claude
workspace: ./web-app

kits:
  - docker.io/sbx/playwright-kit:latest

env:
  NODE_ENV: test

ports:
  - sandbox: 3000
    host: 3000
```

From `web-app-env`, run the environment:

```console
$ sbx env run
```

`sbx` shows an environment plan and asks you to approve it. If you approve the
plan, the `web-app` directory becomes the workspace, while `sbxenv.yaml` remains
outside the sandbox. If the environment doesn't exist, `sbx` creates a sandbox
named `web-app`, installs Playwright and Chromium, and publishes sandbox port
`3000` on the host. It then attaches to the agent. Later runs attach to the
existing sandbox.

This placement keeps the environment file outside the agent's writable
workspace. If you later add `additionalWorkspaces`, keep `sbxenv.yaml`
outside those directories too. See the [`workspace` guidance](#workspace)
for details.

## Commands

| Command                                                                       | Description                                                                          |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| `sbx env plan [PATH...]`                                                       | Shows what applying the environment would change without changing or approving it    |
| [`sbx env run`](/reference/cli/sbx/env/run/) `[PATH...]`                      | Applies the approved plan, creates the environment if needed, and attaches            |
| [`sbx env create`](/reference/cli/sbx/env/create/) `[PATH...]`                | Applies the approved plan and creates the environment without attaching              |
| [`sbx env exec`](/reference/cli/sbx/env/exec/) `[PATH...] -- COMMAND [ARG...]` | Runs a command in an existing environment without running lifecycle commands         |
| [`sbx env rm`](/reference/cli/sbx/env/rm/) `[PATH...]`                        | Shows a destroy plan, then removes the sandbox and resources named in the plan        |

`PATH` can be a directory or a direct path to an environment file. A directory
always resolves to `sbxenv.yaml`. To use another filename, pass the file path
explicitly. With no path, `sbx` reads `sbxenv.yaml` from the working directory.

Pass the same set of paths to each `sbx env` command so they resolve the same
sandbox.

### Set user defaults

Create `~/.sbxenv.yaml` to define defaults shared across projects. When you run
an `sbx env` command without a path, `sbx` merges this file beneath the
project's `sbxenv.yaml`. Passing any path skips the user-level file.

The user-level file must not set `name` or `workspace`, because those fields
identify a project. Lists such as `ports` and `mcp.servers` concatenate across
the user and project files.

### Parameterize an environment

Declare inputs in a top-level `args` block when values need to vary between
uses of the same environment file. Each argument must have exactly one of
`default` or `required: true`:

```yaml
schemaVersion: "1"
name: web-app
agent: claude

args:
  channel:
    default: stable
    description: Release channel
    enum:
      - stable
      - beta
  endpoint:
    required: true
    description: API endpoint
  cpus:
    default: "4"
    pattern: "[1-9][0-9]*"

env:
  RELEASE_CHANNEL: ${{ env.args.channel }}
  API_ENDPOINT: ${{ env.args.endpoint }}

sandboxOptions:
  cpus: ${{ env.args.cpus }}
```

Reference a declared argument as `${{ env.args.NAME }}` anywhere a YAML value
can appear. References can't be used in field names or within the `args` block.
An unquoted reference is interpreted as a YAML value after substitution, so
the `cpus` value in this example becomes an integer. Quote a reference to
preserve it as a string.

All `sbx env` commands accept repeatable `--env-arg NAME=VALUE` flags. Values
provided with a flag replace defaults from the environment file:

```console
$ sbx env run --env-arg endpoint=https://api.example.com --env-arg channel=beta
```

Use `--env-args-file` to load values from a file. Each non-empty, non-comment
line must have the form `NAME=VALUE`:

```text
# production.args
channel=beta
endpoint=https://api.example.com
```

```console
$ sbx env run --env-args-file production.args
```

You can pass multiple argument files. Later files take precedence over earlier
files, and `--env-arg` flags take precedence over every argument file. The
command rejects undeclared arguments, missing required values, and values that
don't satisfy an argument's `enum` or `pattern`. Values can contain `=`, and
values in an argument file are read literally rather than expanded by a shell.

Argument references are the only variable expressions expanded in an
environment file. Shell-style expressions such as `${VAR}` aren't expanded
from the host environment. Other dollar signs remain literal, so a value such
as `$PATH:/opt/bin` is passed unchanged. Use `$${{ env.args.NAME }}` to produce
the literal text `${{ env.args.NAME }}`. Substituted values aren't expanded a
second time.

## Common workflows

The following examples combine environment file fields into configurations you
can adapt for a project.

### Combine team defaults and personal settings

Keep the shared configuration in a version-controlled environment directory
outside the mounted workspace. Put machine-specific settings in a file excluded
from version control. For example, commit `base.sbxenv.yaml` beside the
`web-app` directory:

```yaml
schemaVersion: "1"
name: web-app
agent: claude
workspace: ./web-app

env:
  NODE_ENV: development

sandboxOptions:
  cpus: 4
  memory: 8g
```

Add `local.sbxenv.yaml` to `.gitignore`, then use it for personal settings:

```yaml
env:
  LOG_LEVEL: debug

sandboxOptions:
  memory: 12g
```

Pass both files in merge order:

```console
$ sbx env run base.sbxenv.yaml local.sbxenv.yaml
```

Nested mappings merge by key, lists concatenate, and values from later files
replace earlier scalar values. In this example, the sandbox has four CPUs,
12 GB of memory, and both environment variables. The first file controls the
base directory for relative workspace paths and the default sandbox name.

### Work across multiple repositories

Mount related repositories alongside the primary project when the agent needs
to coordinate changes or consult shared code and documentation:

```yaml
# sbxenv.yaml in the directory above the repositories
schemaVersion: "1"
name: web-platform
agent: codex

workspace: ./web-app

additionalWorkspaces:
  - path: ./shared-components
  - path: ./architecture-docs
    readOnly: true
```

The agent starts in `web-app`, can modify `shared-components`, and can read
`architecture-docs` without changing it. The environment file stays outside all
three workspaces. Relative paths resolve from the directory of the first
environment file. Additional workspaces are mounted directly even when the
primary workspace uses clone mode.

### Reuse an environment in automation

Use the same committed environment for interactive development and automated
tasks. Developers attach to the agent with `run`:

```console
$ sbx env run
```

Automation can create the sandbox without attaching, run commands in it, and
remove it afterward:

```console
$ sbx env create --auto-approve
$ sbx env exec -- npm test
$ sbx env rm --force
```

`--auto-approve` approves the plan for that invocation without recording
consent for later invocations. Use the flag for each unattended `create` or
`run`. The `--force` flag approves the destroy plan and removes the sandbox even
when it is in use.

Commands and vault references under `secrets` resolve on the host, so the
automation runner must provide the referenced tools and authentication. The
secret values remain outside the environment file.

## Review an environment plan

`sbx env create`, `sbx env run`, and `sbx env rm` show the changes an
environment makes outside its sandbox and ask for approval before applying
them. The plan includes host commands, credentials, bindings, MCP
registrations, directories, kits, published ports, sandbox options, and
environment variables.

Run `sbx env plan` to inspect the apply plan without changing, approving, or
recording anything:

```console
$ sbx env plan
```

The plan compares the environment file with the environment's last applied
state and the resources on the host. It omits resources that are unchanged and
already approved. Literal secret values appear as SHA-256 digests. Secret
references, host commands, environment variables, ports, paths, and binding
domains remain visible so you can review them.

Interactive approval is recorded for the environment under the `sbx` state
directory. Plans without host commands apply silently on later invocations until
the environment changes or a resource is missing. An approval provided with
`--auto-approve` applies only to that invocation.

## Update an environment

For an existing sandbox, `sbx env run` applies updated `env` values to the new
agent session and reconciles declared MCP servers. Changes to workspaces, kits,
ports, secrets, bindings, and `sandboxOptions` take effect only when the
sandbox is next created. Remove the environment with `sbx env rm`, then create
it again to apply those changes.

## Remove an environment

Secrets and registry credentials are sandbox-scoped. Credential bindings and
MCP server registrations are host-global and can be shared by multiple
sandboxes.

`sbx env rm` builds a destroy plan from the resources on the host. The plan
includes all credentials stored at the sandbox's scope, including credentials
that the environment file no longer declares. After approval, `sbx` removes
only the resources named in the plan.

Global credential bindings remain unless you pass `--prune-bindings`. MCP
registrations remain available to other sandboxes.

### Clean up after a failed create

Secret provisioning, binding updates, and MCP server registration occur before
the sandbox is created. If sandbox creation fails, scoped secrets remain, and
bindings and MCP registrations may also remain. Run `sbx env rm` with the same
paths to remove the scoped secrets. Pass `--prune-bindings` if you also want to
remove the declared global bindings. MCP registrations are host-global and
remain after cleanup.

## File reference

The loader rejects unknown fields and unsupported schema versions.

### Top-level fields

| Field                  | Type             | Required | Default                        | Description                                                                     |
| ---------------------- | ---------------- | -------- | ------------------------------ | ------------------------------------------------------------------------------- |
| `schemaVersion`        | string           | Yes      | None                           | Schema version. The supported value is `"1"`                                   |
| `name`                 | string           | No       | `<agent>-<workspace-basename>` | Sandbox name                                                                    |
| `agent`                | string           | Yes      | None                           | Built-in agent or the name of an agent kit                                      |
| `args`                 | map              | No       | None                           | Environment arguments. See [`args`](#args)                                      |
| `kits`                 | list             | No       | None                           | Kits to install at creation. See [`kits`](#kits)                                 |
| `workspace`            | string or object | No       | No host mount                  | Primary workspace. See [`workspace`](#workspace)                                |
| `additionalWorkspaces` | list             | No       | None                           | Extra directories to mount. See [`additionalWorkspaces`](#additionalworkspaces) |
| `env`                  | map of strings   | No       | None                           | Environment variables for the sandbox                                           |
| `sandboxOptions`       | object           | No       | None                           | Creation options. See [`sandboxOptions`](#sandboxoptions)                        |
| `secrets`              | map              | No       | None                           | Service credentials. See [`secrets`](#secrets)                                  |
| `bindings`             | map              | No       | None                           | Credential injection approvals. See [`bindings`](#bindings)                     |
| `registries`           | map              | No       | None                           | Registry pull credentials. See [`registries`](#registries)                      |
| `mcp`                  | object           | No       | None                           | MCP servers. See [`mcp`](#mcp)                                                  |
| `ports`                | list             | No       | None                           | Port mappings. See [`ports`](#ports)                                            |
| `lifecycle`            | object           | No       | None                           | Host commands. See [`lifecycle`](#lifecycle)                                    |

### `args`

`args` maps argument names to their declarations. Names must start with a
letter or underscore and can contain letters, numbers, underscores, and
hyphens. Each declaration must set exactly one of `default` or `required:
true`.

| Field         | Type            | Default | Description                                                       |
| ------------- | --------------- | ------- | ----------------------------------------------------------------- |
| `default`     | string          | None    | Value used when the command doesn't supply the argument           |
| `required`    | boolean         | `false` | Require the command to supply the argument                         |
| `description` | string          | None    | Explanation shown in command output                               |
| `enum`        | list of strings | None    | Values accepted for the argument                                  |
| `pattern`     | string          | None    | Go (`RE2`) expression matched against the complete argument value |

`enum` and `pattern` can't be used together. A default value must satisfy the
declared `enum` or `pattern`.

### `kits`

`kits` accepts local directories, ZIP archives, OCI registry references, and
Git URLs prefixed with `git+https://` or `git+ssh://`. Kits can install tools,
configure the sandbox, and give the agent project-specific instructions. See
[Kits](../customize/kits.md) for details.

Explicit relative paths resolve from the directory of the environment file
that declares them. These include `.`, `..`, paths that start with `./` or
`../`, and relative paths that end in `.zip`. Bare references such as
`organization/kit` remain registry references.

Use an object entry to pass arguments to a kit. Set `source` to the kit
reference and map the kit's argument names to values under `args`:

```yaml
kits:
  - source: ./kits/tool
    args:
      version: ${{ env.args.channel }}
```

Remote kit sources must match the
[kit source allowlist](../customize/kits.md#restrict-kit-sources). Docker Hub is
allowed by default. To use Git kits from `docker/sbx-kits-contrib`, add its
source:

```console
$ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]'
```

The setting replaces the complete allowlist, so include any existing sources
you want to keep. For reproducible setup, pin Git kits with the `ref` URL
parameter and OCI kits with an immutable tag or digest.

### `workspace`

When specified as a string, `workspace` is the path. Use the object form for
clone mode. Omit `workspace` to create a sandbox without a host bind mount. Set
`workspace: .` to mount the directory that contains the first environment
file. If `workspace` is present, its path can't be empty or contain only
whitespace.

`sbx` mounts the environment file read-only inside the sandbox. Keep the file
outside direct-mounted workspaces or directly in a workspace root.

| Field   | Type    | Required | Default | Description                                                     |
| ------- | ------- | -------- | ------- | --------------------------------------------------------------- |
| `path`  | string  | Yes      | None    | Workspace directory. Relative paths resolve from the first file |
| `clone` | boolean | No       | `false` | Use a private clone, equivalent to `sbx create --clone`          |

You can override `workspace.clone` for one `create` or `run` invocation with
`--clone` or `--clone=false`.

### `additionalWorkspaces`

Each additional workspace is mounted after the primary workspace. Relative
paths resolve from the directory of the first environment file.

| Field      | Type    | Required | Default | Description                   |
| ---------- | ------- | -------- | ------- | ----------------------------- |
| `path`     | string  | Yes      | None    | Directory to mount            |
| `readOnly` | boolean | No       | `false` | Mount the directory read-only |

### `sandboxOptions`

| Field         | Type            | Default  | Description                                           |
| ------------- | --------------- | -------- | ----------------------------------------------------- |
| `template`    | string          | None     | Custom sandbox template image                         |
| `memory`      | string          | None     | Memory limit, such as `8g` or `512m`                   |
| `cpus`        | integer         | `0`      | Number of CPUs. `0` allocates all host CPUs            |
| `pullPolicy`  | string          | `always` | Image pull policy: `always`, `missing`, or `never`     |
| `profile`     | string          | None     | Governance profile name                               |
| `shareSkills` | boolean         | `true`   | Mount the shared agent skills store                    |
| `display`     | boolean         | `false`  | Provision a display socket for graphical applications |
| `gpu`         | boolean         | `false`  | Pass the host GPU through to the sandbox               |
| `usb`         | list of strings | None     | USB device selectors to pass through to the sandbox   |

Imported [agent skills](../workflows/agent-skills.md) are shared with the
sandbox by default. Set `shareSkills: false` to opt out.

### `lifecycle`

The `lifecycle` block declares commands that run on the host with your user
privileges. Use lifecycle commands for work that must happen outside the
sandbox, such as creating a workspace, seeding fixtures, or archiving state.

```yaml
lifecycle:
  initialize:
    - name: Prepare workspace
      command: test -d web-app || git clone https://github.com/example/web-app
      timeout: 5m
  postCreate:
    - command: ./scripts/seed-fixtures.sh
      workdir: web-app
  preRemove:
    - command: ./scripts/archive-state.sh
```

Lifecycle phases run at the following points:

| Phase        | Timing                                                                                                           |
| ------------ | ---------------------------------------------------------------------------------------------------------------- |
| `initialize` | Before other create or run actions. Runs for every `create` and `run`                                             |
| `postCreate` | After a new sandbox is created. For `run`, before attachment. Does not run when attaching to an existing sandbox   |
| `preRemove`  | After you approve removal and before `sbx` deletes resources. A failure produces a warning and removal continues  |

`sbx env exec` doesn't run lifecycle commands. Commands within a phase run in
order and stop at the first failure. Make `initialize` commands safe to run
more than once.

After `preRemove` commands finish, `sbx` generates the destroy plan again.
Removal stops if the commands introduced changes that weren't included in the
approved plan.

Each command requires `command` and accepts the following fields:

| Field     | Type   | Default           | Description                                                                    |
| --------- | ------ | ----------------- | ------------------------------------------------------------------------------ |
| `name`    | string | Command text      | Label shown in progress and plan output                                        |
| `command` | string | None              | Command passed to the user's shell                                             |
| `workdir` | string | Project directory | Host working directory. Relative paths resolve from the first file's directory |
| `timeout` | string | None              | Maximum runtime, such as `90s` or `5m`                                         |

Commands inherit the environment of the `sbx` process and receive the following
variables:

- `SBX_LIFECYCLE_PHASE`
- `SBX_ENV_FILE` and `SBX_ENV_FILES`
- `SBX_ENV_DIR`
- `SBX_SANDBOX_NAME`
- `SBX_AGENT`
- `SBX_WORKSPACE`

The environment file's `env` values and resolved secrets aren't passed to host
commands.

Plans containing lifecycle commands or credential `command` sources require
approval for every invocation by default, even when the command text hasn't
changed. Approve one invocation with `--auto-approve`, skip lifecycle commands
with `--skip-host-commands`, or remember approval until the commands change:

```console
$ sbx settings set env.rememberHostCommands true
```

### `secrets`

`secrets` maps service names to secret sources. Each entry must set exactly one
of `value`, `ref`, or `command`. The secret is stored at the sandbox scope when
the environment is created.

| Field      | Type    | Default | Description                                                                  |
| ---------- | ------- | ------- | ---------------------------------------------------------------------------- |
| `value`    | string  | None    | Literal secret value                                                         |
| `ref`      | string  | None    | Vault URI, such as `op://Vault/Item/field`                                    |
| `command`  | string  | None    | Host shell command whose standard output becomes the secret                   |
| `refresh`  | string  | None    | Resolution policy for `ref` or `command`, such as `on-demand` or `55m`        |
| `backend`  | string  | Automatic | Resolver for `ref`: `sdk` or `cli`                                          |
| `noVerify` | boolean | `false` | Skip verifying that a `ref` or `command` resolves during provisioning          |

> [!WARNING]
> A literal `value` is visible to anyone with read access to the file. Use a
> vault URI with `ref` or obtain the value at runtime with `command`.

```yaml
secrets:
  anthropic:
    ref: op://Private/Anthropic/api-key
    refresh: 55m
  github:
    command: gh auth token
```

### `bindings`

`bindings` approves credential injection domains for each service. The
environment merges these approvals into the user's global
`credentials.yaml`. Each service can contain an `apiKey` block, an `oauth`
block, or both. Each block contains a `domains` list:

```yaml
bindings:
  github:
    apiKey:
      domains:
        - api.github.com
```

`sbx env rm` preserves global bindings by default. Pass `--prune-bindings` to
remove every service binding declared by the environment file.

> [!WARNING]
> `--prune-bindings` deletes the complete global binding entry for every
> service declared in the environment file. This can affect other sandboxes
> that share those service bindings.

### `registries`

`registries` maps registry hostnames to pull credentials. Each entry requires
`secret` and accepts an optional `username`. Both fields accept a secret source
with exactly one of `value`, `ref`, or `command`.

When `username` is omitted, `sbx` stores a token-only credential. Registries
such as GHCR and GitLab accept token-only credentials.

```yaml
registries:
  ghcr.io:
    secret:
      command: gh auth token
```

### `mcp`

The `mcp.servers` list registers servers with the built-in
[MCP gateway](../mcp-gateway.md) and adds them to the sandbox. MCP registrations
are host-global and remain after `sbx env rm`.

| Field     | Type            | Required | Default | Description                                                     |
| --------- | --------------- | -------- | ------- | --------------------------------------------------------------- |
| `name`    | string          | Yes      | None    | Server name                                                     |
| `url`     | string          | No       | None    | Remote server URL, registry reference, or OCI reference          |
| `command` | string          | No       | None    | Command for a local stdio server                                 |
| `args`    | list of strings | No       | None    | Arguments passed to `command`                                   |

Each server must set exactly one of `url` or `command`.

### `ports`

`ports` publishes sandbox ports when the environment is created. Ports exposed
by a kit but omitted from this list receive an ephemeral host port.

| Field      | Type    | Required | Default                              | Description                                     |
| ---------- | ------- | -------- | ------------------------------------ | ----------------------------------------------- |
| `sandbox`  | integer | Yes      | None                                 | Sandbox port from 1 through 65535               |
| `host`     | integer | No       | Ephemeral                            | Host port from 1 through 65535                  |
| `protocol` | string  | No       | `tcp4`, or `tcp6` for IPv6 `hostIP` | `tcp`, `tcp4`, `tcp6`, `udp`, `udp4`, or `udp6` |
| `hostIP`   | string  | No       | Loopback                             | Host interface to bind                          |

Set `protocol: tcp` to bind both IPv4 and IPv6. Leave `hostIP` unset for a
dual-stack binding because an explicit address binds only its own IP family.

If a port can't be published, sandbox creation fails and removes the new
sandbox.


---

# Enable NVIDIA GPU passthrough

*Sección: Ai*

> [!IMPORTANT]
> GPU passthrough is experimental. The `--gpu` flag, the driver bundle, and the
> setup steps on this page are subject to change.

Docker Sandboxes supports GPU passthrough, which allows running
workloads against a physical NVIDIA GPU.

GPU passthrough in Docker sandboxes works via [VFIO](https://www.kernel.org/doc/html/latest/driver-api/vfio.html), a Linux feature
that assigns a PCI device directly to a virtual machine. The GPU is
bound to VFIO instead of the host's driver, and the sandboxed workload
drives the hardware itself.

## Requirements

VFIO-based GPU passthrough is supported only on `x86_64` Linux hosts (not Arm)
with NVIDIA GPUs, and requires a GPU that nothing else is using: a headless
host with a GPU, or an additional GPU.

The host also needs IOMMU turned on in its BIOS, and the `iommufd` and
`vfio_pci` kernel modules loaded:

```console
sudo modprobe -a iommufd vfio_pci
```

For the sandbox to drive the GPU, it requires:

- The `nvidia` and `nvidia-uvm` kernel modules, built for the Docker Sandboxes
  guest kernel
- The NVIDIA userspace driver libraries and firmware

Docker Sandboxes looks for these dependencies, packaged as an EROFS image, at
`/usr/libexec/nerdbox-nvidia-bundle.erofs`. This bundle isn't included with
Docker Sandboxes. To build it, see [Build the bundle](#build-the-bundle).

## Turn on the feature

The `--gpu` flag is hidden until you turn on experimental features and the GPU
feature flag:

```console
sbx settings set platform.allowExperimentalFeatures true
sbx settings set feature.sandbox-gpu true
```

## Build the bundle

A zip archive containing all the components required to build the bundle is
published with each Docker Sandboxes release, as
`nerdbox-nvidia-modules-x86_64.zip`. The archive contains the kernel modules
(`nvidia.ko` and `nvidia-uvm.ko`), the driver version they were built against
(`VERSION`), and a build script.

The build script runs a `linux/amd64` container that downloads the matching
NVIDIA driver, assembles the bundle, and installs it to
`/usr/libexec/nerdbox-nvidia-bundle.erofs`. Writing to that path requires root,
hence the `sudo` in the following commands.

Prerequisites:

- Network access to `download.nvidia.com`
- Docker

Download and unpack the archive, then run the script from the unpacked
directory:

```console
curl -fSLO https://github.com/docker/sbx-releases/releases/latest/download/nerdbox-nvidia-modules-x86_64.zip
unzip nerdbox-nvidia-modules-x86_64.zip -d nvidia-modules
cd nvidia-modules
sudo ./prepare-nvidia-bundle.sh
```

If the script can't write to the output path, it leaves the bundle in the
current directory and prints the `install` command that finishes the job.

Two environment variables override the script's default behavior:

| Variable                | Default                                    | Purpose                                                                       |
| ----------------------- | ------------------------------------------ | ----------------------------------------------------------------------------- |
| `OUTPUT`                | `/usr/libexec/nerdbox-nvidia-bundle.erofs` | Where the finished bundle is written.                                         |
| `ACCEPT_NVIDIA_LICENSE` | None                                       | Set to `1` to accept the NVIDIA license non-interactively, for scripts or CI. |

For example, the following command writes the finished bundle to
`/mnt/some-place/nerdbox-nvidia-bundle.erofs`:

```console
OUTPUT=/mnt/some-place/nerdbox-nvidia-bundle.erofs ./prepare-nvidia-bundle.sh
```

## Install the bundle

If you ran the script on the `x86_64` Linux host that runs your GPU sandboxes,
and you didn't override `OUTPUT`, the bundle is already in place. If you built
it elsewhere, copy the `nerdbox-nvidia-bundle.erofs` file it produced into that
host's `/usr/libexec` directory.

## Run a sandbox with a GPU

To run a sandbox with GPU passthrough, pass the `--gpu` flag:

```console
sbx create --gpu claude .
```

The `sbx run` command takes the same flag:

```console
sbx run --gpu claude
```

The flag takes effect when the sandbox is created. Passing it when you
re-attach to an existing sandbox has no effect.

> [!IMPORTANT]
> Each Docker Sandboxes release uses a specific guest kernel. The NVIDIA 
> kernel modules in your bundle must match that kernel. After upgrading
> Docker Sandboxes, download the new release's `nerdbox-nvidia-modules-x86_64.zip`
> archive and run the script again to rebuild the bundle.

## Troubleshooting

### The script reports `... not found in the driver download`

The extracted driver didn't contain an expected library or firmware file.
Confirm that the download completed. If a library is named differently in your
driver version, adjust `DRIVER_LIB_FAMILIES` in the script.

### GPU workloads fail after a Docker Sandboxes upgrade

The guest kernel or the pinned driver version likely changed. Download the new
release's archive, re-run the script, and reinstall the bundle.


---

# Configure a registry mirror

*Sección: Ai*

A registry mirror routes Docker Hub pulls for sandbox templates and OCI kits
through your organization's registry infrastructure. If the mirror meets
Docker Engine's requirements, Docker inside the sandbox uses it too.

## Configure the mirror

Set `platform.images.registryMirror` to the mirror host. Include a port when
needed, but omit the URL scheme:

```console
$ sbx settings set platform.images.registryMirror registry.example.com
```

You can include a path prefix for registries that store mirrored Docker Hub
content below a repository path:

```console
$ sbx settings set platform.images.registryMirror registry.example.com/docker-remote
```

Docker Sandboxes redirects image references that resolve to Docker Hub and
preserves their repository path, tag, and digest. References that explicitly
name another registry remain unchanged.

If the mirror requires authentication, configure
[registry credentials](credentials.md#registry-credentials) for the mirror
host.

## Mirror Docker pulls inside the sandbox

Docker Sandboxes configures Docker Engine inside a sandbox to use the same
mirror when the setting contains a non-loopback host without a path prefix.

| Mirror setting                         | Template and OCI kit pulls | Docker pulls inside the sandbox |
| -------------------------------------- | -------------------------- | ------------------------------- |
| `registry.example.com`                 | Mirrored                   | Mirrored                        |
| `registry.example.com:5000`            | Mirrored                   | Mirrored                        |
| `registry.example.com/docker-remote`   | Mirrored                   | Not mirrored                    |
| `localhost:5000` or `127.0.0.1`        | Mirrored                   | Not mirrored                    |

Loopback addresses refer to the sandbox itself from inside its network
namespace, so Docker Sandboxes doesn't add them to the sandbox's Docker Engine
configuration. A path prefix is also excluded because Docker Engine interprets
mirror URL paths differently from image repository prefixes.

Docker Engine connects to the mirror over HTTPS, so the sandbox must trust the
certificate that the mirror presents. For a mirror that uses an internal
certificate authority, add the CA to the sandbox's system trust store. See
[Install an internal CA certificate](../customize/kit-examples.md#install-an-internal-ca-certificate).

Template and kit pulls use the changed setting immediately. Existing sandboxes
retain the Docker Engine mirror configuration with which they were created.
Recreate a sandbox to apply a changed mirror to Docker inside it.

## Disable the mirror

Unset the setting to disable mirroring:

```console
$ sbx settings unset platform.images.registryMirror
```

An empty setting value also disables mirroring. Recreate existing sandboxes to
remove a mirror from their Docker Engine configuration.


---

# Configure an upstream proxy

*Sección: Ai*

> [!IMPORTANT]
> Upstream proxy support is experimental. Everything described on this page —
> proxy URLs, PAC files, SOCKS5, use of the OS system proxy, proxy
> authentication, and the settings that configure them — is subject to change.
> Share feedback and bug reports in the
> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository.

An upstream proxy is the corporate or network proxy that Docker Sandboxes
forwards outbound traffic through on its way to the internet. This is separate
from the [network policy](../governance/access-controls/network.md), which decides
_which_ destinations are allowed. The upstream proxy decides _how_ allowed
traffic reaches them.

Docker Sandboxes sends two kinds of outbound traffic, and you can proxy them
independently:

- Sandbox traffic — network access from inside your sandboxes.
- Daemon traffic — the `sbx` daemon's own access: image pulls, telemetry,
  sign-in, and feature flags.

## Default behavior

By default, both kinds of traffic use your operating system's proxy settings,
including any PAC URL configured there. You don't need to configure anything. On
macOS and Windows, `sbx` tracks the OS proxy setting while it runs, so a change
to your network, VPN, or PAC configuration is picked up without a restart. If
your OS has no proxy configured, traffic goes direct.

## Set a proxy manually

Use `sbx settings set` to override the default for one or both kinds of traffic:

```console
$ sbx settings set proxy http://proxy.corp:3128          # both kinds of traffic
$ sbx settings set proxy.sandbox socks5://proxy.corp:1080 # sandbox traffic only
$ sbx settings set proxy.daemon direct                    # daemon traffic only
```

A proxy value can be any of the following:

| Value                                                                                  | Meaning                                                                                          |
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| _(unset)_                                                                              | Fall back to the wider scope, then environment variables, then the OS system proxy (the default) |
| `http://host:port` or `https://host:port`                                              | An HTTP or HTTPS proxy                                                                           |
| `socks5://host:port` or `socks5h://host:port`                                          | A SOCKS5 proxy                                                                                   |
| `pac+http://host/proxy.pac`, `pac+https://host/proxy.pac`, or `file:///path/proxy.pac` | A PAC (proxy auto-config) file                                                                   |
| `system`                                                                               | Force the use of the OS system proxy                                                             |
| `direct`                                                                               | Force a direct connection with no proxy                                                          |

With `socks5://`, DNS is resolved locally before the connection is handed to the
proxy. With `socks5h://`, DNS resolution is delegated to the proxy.

### Exclude destinations from the proxy

Exclusion lists mirror the same scopes. Each takes a comma-separated list of
hosts, domain suffixes, IP addresses, or CIDR ranges, or `*` to bypass the
proxy entirely:

```console
$ sbx settings set no_proxy "*.internal.corp,10.0.0.0/8"    # both kinds of traffic
$ sbx settings set no_proxy.sandbox "*.svc.cluster.local"   # sandbox traffic only
$ sbx settings set no_proxy.daemon "registry.internal"      # daemon traffic only
```

## Environment variables

Because `sbx` runs from your shell, it also honors the standard and legacy proxy
environment variables, so existing setups keep working without migration:

- `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` (and their lowercase forms) — the
  standard variables. They apply to both kinds of traffic when no `proxy` or
  `no_proxy` setting is configured.
- `DOCKER_SANDBOXES_PROXY` and `DOCKER_SANDBOXES_NO_PROXY` — the environment
  form of `proxy.sandbox` and `no_proxy.sandbox`. They apply to sandbox traffic
  only and never affect daemon traffic.

The daemon reads these variables when it starts, so set them before your first
`sbx` command, or restart the daemon for a change to take effect.

## Precedence

For each kind of traffic, the first match wins:

1. The scope-specific value:
   - `proxy.sandbox` or `DOCKER_SANDBOXES_PROXY` for sandbox traffic
   - `proxy.daemon` for daemon traffic
2. The `proxy` setting
3. `HTTP_PROXY` or `HTTPS_PROXY` from the shell
4. The OS system proxy (the default)
5. Direct

The matching exclusion list (`no_proxy.<scope>`, then `no_proxy`) applies to the
chosen proxy, and the standard `NO_PROXY` variable still applies on the
environment path.

For example, if `proxy` specifies a shared proxy and `proxy.sandbox` is set to
`direct`, sandbox traffic connects directly while daemon traffic uses the
shared proxy. If no proxy setting is configured, `HTTP_PROXY` takes precedence
over the OS system proxy.

## When changes take effect

The two kinds of traffic are resolved at different times:

- Sandbox scope (`proxy.sandbox`, `no_proxy.sandbox`, and the sandbox side of
  `proxy` and `no_proxy`) is re-resolved every time a sandbox is created or
  restarted. A change takes effect on the next sandbox you create or restart;
  already-running sandboxes keep the proxy they were created with.
- Daemon scope (`proxy.daemon`, `no_proxy.daemon`, and the daemon side of
  `proxy` and `no_proxy`) is resolved once when the daemon starts. A change
  requires a daemon restart.

The `DOCKER_SANDBOXES_*` environment variables are a separate case. They control
sandbox traffic only, as described in
[Environment variables](#environment-variables), but `sbx` reads them from the
daemon's environment as the daemon starts, so changing one also requires a
daemon restart.

When a `system` or PAC proxy is in use, `sbx` still tracks OS-level proxy changes
(such as switching networks, connecting a VPN, or updated PAC contents) live.

## Authentication

If the upstream proxy requires you to authenticate to it, `sbx` supports two
mechanisms.

### Credentials in the proxy URL

Put the credentials in the proxy URL: `http://user:pass@host:port` for an HTTP
or HTTPS proxy, or `socks5://user:pass@host:port` for SOCKS5. This works on all
platforms and covers proxies that challenge with Basic authentication.

### Integrated Windows authentication

Proxies that answer `CONNECT` with a `407` challenge and accept only integrated
schemes — NTLM or Kerberos/Negotiate — can instead authenticate you with your
Windows sign-in identity. This is opt-in and off by default:

```console
$ sbx settings set proxy.integratedAuth true
```

The setting isn't scoped: it applies to both sandbox and daemon traffic. If the
proxy offers several schemes, the strongest one is used, preferring Negotiate
over NTLM. A change takes effect on the same schedule as the other proxy
settings: on the next sandbox you create or restart for sandbox traffic, and
after `sbx daemon restart` for daemon traffic.

Your identity stays on the host. Authentication to the upstream proxy happens
on the host side of the sandbox boundary, after network policy has already been
applied, so no credential enters the sandbox and nothing about which
destinations a sandbox may reach changes.

This depends on Windows SSPI, so it has no effect on macOS or Linux. On those
platforms, credentials in the proxy URL remain the only option.

## Related pages

- [Network isolation](../security/isolation.md) — how traffic leaves a sandbox and
  the network policy it passes through
- [Troubleshooting: API calls fail with a certificate error](../troubleshooting.md#api-calls-fail-with-a-certificate-error)
  — installing an internal root CA when your proxy inspects HTTPS traffic


---

# Customizing sandboxes

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

Docker Sandboxes offers two ways to customize a sandbox beyond the built-in
defaults:

- [Templates](templates.md) — reusable sandbox images with tools, packages,
  and configuration baked in. Extend a base image with a Dockerfile, or
  save a running sandbox as a template.
- [Kits](kits.md) — declarative YAML artifacts that extend an agent with
  tools, credentials, network rules, and files at runtime, or define a new
  agent from scratch.

Kits are experimental. The kit file format, CLI commands, and experience for
creating, loading, and managing kits are subject to change as the feature
evolves. Share feedback and bug reports in the
[docker/sbx-releases](https://github.com/docker/sbx-releases) repository.

## Templates and kits, side by side

A template is a Docker image that the sandbox runs. It's built ahead
of time with a Dockerfile (or saved from a running sandbox), pushed to a
registry, and pulled when a sandbox is created. Use templates for things
that belong in an image: system packages, language toolchains, large
dependencies — anything you'd rather not reinstall on every sandbox start.

A kit is a YAML artifact applied at sandbox creation. The kit can run
install commands, drop files into the sandbox, declare network and
credential rules, and (for sandbox kits) define which template image the
agent runs in. Use kits for things that vary per agent or per team:
shared linter config, project-specific install steps, credential
injection for a service the agent talks to.

Templates and kits work together. A sandbox kit's `sandbox.image` field
points at a template: the template provides the base environment, the
kit layers config, secrets, and runtime behavior on top. A team can ship
one heavy template and several thin kits without rebuilding the image
each time something changes.

## When to use which

| Goal                                                      | Option                                                        |
| --------------------------------------------------------- | ------------------------------------------------------------- |
| Pre-install tools and packages into a reusable base image | [Template](templates.md)                                      |
| Capture a configured running sandbox for reuse            | [Saved template](templates.md#saving-a-sandbox-as-a-template) |
| Add a tool, credential, or config to agent runs via YAML  | [Kit (mixin)](kits.md)                                        |
| Define a new agent from scratch                           | [Kit (sandbox)](kits.md#define-an-agent)                      |

Templates and kits can be used together. A template bakes heavy tools into
the image for fast sandbox startup; a kit layered on top adds per-run
credentials, config, or extra capabilities.

## Tutorials

- [Build your own agent kit](build-an-agent.md) — step-by-step walkthrough
  for packaging [Amp](https://ampcode.com/) as a sandbox kit.


---

# Build your own agent kit

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

> [!NOTE]
> Kits are experimental. The kit file format, CLI commands, and experience
> for creating, loading, and managing kits are subject to change as the
> feature evolves. Share feedback and bug reports in the
> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository.

This tutorial walks through building an agent kit for the
[Amp](https://ampcode.com/) coding agent. Each step explains the decision
behind a part of the spec, so you can apply the same reasoning to other agents.

For reference on every field, see the [Kit spec reference](kit-reference.md).
This tutorial focuses on the journey.

The finished kit is also published as a runnable sample at
[docker/sbx-kits-contrib](https://github.com/docker/sbx-kits-contrib/tree/main/amp) —
useful as a reference while you follow along.

## Choose a base image

An agent kit needs a container image that satisfies the
[base image requirements](kit-reference.md#base-image-requirements): non-root
`agent` user at UID 1000, passwordless sudo, `/home/agent/` home, and HTTP
proxy environment variable forwarding.

Rather than build an image from scratch, extend one of the published
sandbox templates. Three common starting points:

- `docker/sandbox-templates:shell`. Generic base with no pre-installed
  agent.
- `docker/sandbox-templates:shell-docker`. Same, with Docker Engine inside
  the sandbox.
- Agent-specific variants (`claude-code`, `codex`, etc.). Only useful if
  you're extending that specific agent.

For Amp, pick `shell-docker`:

- Amp isn't pre-installed in any variant, so you need a generic base
  (`shell`).
- Docker support is handy since coding agents often need to run containers.
- If you don't need Docker inside the sandbox, use the `shell` tag for a
  lighter, non-privileged environment.

## Plan authentication

Amp authenticates with an API key in `AMP_API_KEY`. To keep the real key
out of the VM, you split the work in two:

- The kit's network section maps the API host to a service identifier
  and tells the proxy which header to inject.
- You provide your key once on the host, via sbx's secret store. The
  real value stays on the host; only a placeholder reaches the sandbox.

Inside the sandbox `AMP_API_KEY` is set to that placeholder. The proxy
substitutes the real key on outbound requests to the API host, so the
secret never enters the sandbox. A later section walks through the
specific command for storing the key.

## Write the sandbox block

The `sandbox:` block tells the sandbox how to launch Amp when the user
attaches.

```yaml {title="amp/spec.yaml"}
schemaVersion: "1"
kind: sandbox
name: amp
displayName: Amp
description: The frontier coding agent.

sandbox:
  image: "docker/sandbox-templates:shell-docker"
  aiFilename: AGENTS.md
  entrypoint:
    run: [amp, --dangerously-allow-all]
```

- `aiFilename: AGENTS.md` tells the sandbox to create `AGENTS.md` at launch
  and append the [`agentContext`](#prime-amp-with-memory) block to it. Amp reads
  this file for instructions.
- `entrypoint.run` runs `amp` in "YOLO-mode" when the sandbox starts. Adjust if
  you want to pass different args on startup.

## Install Amp

Amp installs via a curl-to-bash script:

```yaml
commands:
  install:
    - command: "curl -fsSL https://ampcode.com/install.sh | bash"
      user: "1000"
      description: Install Amp
```

Note `user: "1000"`. That's the agent user. Install commands run as root
(UID 0) by default, and Amp's installer puts the binary in the user's home
directory. Running as root would land the binary in `/root/` where the
agent can't reach it.

## Allow network access

The network block does two things: it lists the hosts the sandbox can
reach (`allowedDomains`), and it wires the kit-side half of the auth flow
from [Plan authentication](#plan-authentication) with `serviceDomains` and
`serviceAuth`.

```yaml
network:
  serviceDomains:
    ampcode.com: amp
  serviceAuth:
    amp:
      headerName: Authorization
      valueFormat: "Bearer %s"
  allowedDomains:
    - "ampcode.com:443"
    - "*.ampcode.com:443"
```

`allowedDomains` here covers the apex (`ampcode.com`) and the
install/CDN subdomains (`*.ampcode.com`). Treat it as a starting point;
Amp may reach other domains (model providers, analytics, updates) that
you'll discover by watching `sbx policy log` while testing.

Kits can also declare `deniedDomains` for hosts the sandbox should not
reach, such as telemetry endpoints. Deny rules take precedence over
allow rules and apply only to sandboxes that use the kit.

For the auth wiring, when the agent makes an outbound request to
`ampcode.com`, the proxy looks up the host in `serviceDomains` to find
the service id `amp`, then uses `serviceAuth.amp` to inject an
`Authorization: Bearer <key>` header. The `<key>` value comes from the
secret you'll register in
[Register your API key](#register-your-api-key), matched by host. The
service id (`amp`) is just a label that ties the two blocks together —
pick any name.

> [!IMPORTANT]
> Keep `serviceDomains` narrow. Mapping `*.ampcode.com` would push the
> proxy into TLS-intercepting mode for every subdomain — including the
> binary CDN the install script downloads from — which corrupts those
> downloads. List only the host that actually needs auth.

## Prime Amp with memory

The `agentContext` field appends markdown to `AGENTS.md` at sandbox creation.
Use it to tell Amp about the sandbox environment so it knows the
conventions when it starts.

```yaml
agentContext: |
  ## Sandbox environment

  You are running inside a Docker sandbox. The workspace is mounted at
  its absolute host path. `sudo` is passwordless; use it for package
  installs. Docker is available inside the sandbox; containers you start
  are isolated in the microVM.
```

Keep this short and sandbox-specific. For project instructions, put a
regular `AGENTS.md` in the workspace.

## The full spec

Putting it all together:

```yaml {title="amp/spec.yaml"}
schemaVersion: "1"
kind: sandbox
name: amp
displayName: Amp
description: The frontier coding agent.

sandbox:
  image: "docker/sandbox-templates:shell-docker"
  aiFilename: AGENTS.md
  entrypoint:
    run: [amp, --dangerously-allow-all]

network:
  serviceDomains:
    ampcode.com: amp
  serviceAuth:
    amp:
      headerName: Authorization
      valueFormat: "Bearer %s"
  allowedDomains:
    - "ampcode.com:443"
    - "*.ampcode.com:443"

commands:
  install:
    - command: "curl -fsSL https://ampcode.com/install.sh | bash"
      user: "1000"
      description: Install Amp

agentContext: |
  ## Sandbox environment

  You are running inside a Docker sandbox. The workspace is mounted at
  its absolute host path. `sudo` is passwordless; use it for package
  installs.
```

## Register your API key

Register your Amp API key on the host with `sbx secret set-custom`. The
value goes into the host secret store, and a placeholder is exposed
inside every sandbox you launch from this kit.

Amp validates `AMP_API_KEY`'s format at startup, so the placeholder needs
to look like a real Amp key. Pick a placeholder shape that matches Amp's
expected format:

```console
$ sbx secret set-custom \
    --host ampcode.com \
    --env AMP_API_KEY \
    --placeholder "sgamp-{rand}" \
    --value "$AMP_API_KEY"
```

`{rand}` expands to a random suffix at registration time. Inside the
sandbox `AMP_API_KEY` is set to that placeholder; Amp accepts it as a
syntactically valid key, and the proxy substitutes the real secret on
outbound requests to `ampcode.com`.

> [!TIP]
> `sbx secret set-custom` is only required because Amp validates the
> key's format. If your agent reads the env var without a local format
> check, you can declare `environment.proxyManaged: [AMP_API_KEY]` in
> the kit instead and skip this user-side step — the proxy uses a
> default sentinel value (`proxy-managed`) that the agent never sees
> rejected.

> [!NOTE]
> `sbx secret set-custom` is experimental and may change in future
> releases. This tutorial surfaces it because there's no other path to
> register a custom-format placeholder.

## Run it

Validate the spec:

```console
$ sbx kit validate ./amp/
```

Launch the sandbox by passing the kit directory in place of a built-in agent
name:

```console
$ sbx run ./amp/
```

The published copy of this kit also runs directly from the contrib
repository:

```console
$ sbx run "git+https://github.com/docker/sbx-kits-contrib.git#dir=amp"
```

## Iterate

As you use the kit, you'll likely hit missing domains or install quirks.
Two loops help:

- Watch the network policy log (`sbx policy log`) to catch blocked
  requests, then add their domains to `allowedDomains`.
- Add domains to `deniedDomains` when the agent should stay blocked from
  a host even if another policy permits it.
- Edit the spec and re-run `sbx run ./amp/` to pick up changes.
  Remove the sandbox first (`sbx rm <name>`) for a clean start.

Flesh out the `agentContext` block as you refine how Amp should behave in the
sandbox.

## Publish

Once the kit works, share it by packaging as a ZIP, pushing to an OCI
registry, or committing to a Git repository. See
[Packaging and distribution](kits.md#packaging-and-distribution) for the
`sbx kit` subcommands.

## Adapt this to another agent

Most of the specifics here are Amp's. To port the pattern, work through
the same decisions for your agent:

- **Base image**: `shell-docker` if you need Docker inside the sandbox,
  `shell` otherwise. Or extend either with your own image if the install
  is heavy.
- **Install**: a `commands.install` block at runtime, or bake the agent
  into a custom image. Pick install if it's a one-line script; bake if
  the install is slow or you need a pinned version.
- **Network mapping**: list only the API host in `serviceDomains`, not
  a wildcard. Keep install/CDN paths out of TLS-intercepting mode. Use
  `deniedDomains` for hosts the agent should not reach.
- **Credential injection**: if the agent validates the API key's format
  locally, register with `sbx secret set-custom` and pick a matching
  placeholder. If it accepts the env var as-is, declare
  `environment.proxyManaged` in the kit and skip the user-side step.

The rest — agent-context block, network-policy iteration, packaging — is the
same regardless of agent.

## Remove the stored secret

To remove the entry created earlier with `sbx secret set-custom`, pass
the host to `sbx secret rm`:

```console
$ sbx secret rm --host ampcode.com
```

The `--host` flag is part of the experimental `set-custom` surface and doesn't appear in `sbx secret rm --help`.


---

# Kit examples

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

> [!NOTE]
> Kits are experimental. The kit file format, CLI commands, and experience
> for creating, loading, and managing kits are subject to change as the
> feature evolves. Share feedback and bug reports in the
> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository.

Each section below shows one `spec.yaml` snippet that demonstrates a
single kit pattern. These aren't complete, distributable kits — they're
small, focused examples you can lift into your own kit. For the full
spec reference, see [Kit spec reference](kit-reference.md).

## Drop a shared config file

Use static files under `files/workspace/` when the content is the same
across every sandbox and doesn't need any runtime values substituted
in. Typical use cases: linter rules, editor settings, a shared
`.editorconfig`, team dotfiles.

```text
ruff-lint/
├── spec.yaml
└── files/
    └── workspace/
        └── ruff.toml
```

```yaml {title="ruff-lint/spec.yaml"}
schemaVersion: "2"
kind: mixin
name: ruff-lint
displayName: Ruff
description: Python linting with shared team config

setup:
  install:
    - command: "uv tool install ruff@latest"
      user: "1000"
```

```toml {title="ruff-lint/files/workspace/ruff.toml"}
line-length = 80

[lint]
select = ["E", "F", "I"]
```

## Install a tool at sandbox creation

`setup.install` runs once per sandbox, at creation time. It's where
anything that needs to land in the image goes — package managers
(`apt-get`, `pip`, `npm`), binary downloads, or vendor install scripts.

> [!TIP]
> Each new sandbox runs all `setup.install` commands. The results aren't
> cached between sandboxes. Creating a kit avoids building and distributing an
> image, so kits work well for smaller, composable changes. For substantial
> build or installation steps, consider a
> [custom template](templates.md#build-a-custom-template). Sandboxes reuse
> template images from the local cache.

```yaml
setup:
  install:
    - command: "apt-get update && apt-get install -y jq"
    - command: "curl -fsSL https://example.com/install.sh | sh"
```

Install commands run as root by default. Set `user: "1000"` when the
step should run as the agent user — for example, `npm install -g`
against a user-scoped prefix, or anything that writes to
`/home/agent/`.

Install steps run under `sh`, not bash, so bash-only builtins such as
`source` fail with `sh: source: not found`. Pipe explicitly to `bash`
(`curl … | bash`) or wrap the step in `bash -c '…'` when you need them.

Downloads are subject to the sandbox's
[network access rules](../governance/access-controls/network.md). A domain that
resolves from your host can still be blocked inside the sandbox — for
example, `get.sdkman.io` returns a 403 until you allow it with
`sbx policy allow network get.sdkman.io`. A tool may also need base
packages that aren't in the image: [SDKMAN!](https://sdkman.io/), for
instance, needs `zip` and `unzip`, so add an
`apt-get install -y zip unzip` step (as root) before installing it.

> [!WARNING]
> `curl … | bash` masks download failures. The pipe's exit status is
> bash's, and bash exits `0` on empty input, so a blocked or failed
> download still reports success — the sandbox is created with no error
> even though nothing was installed. Download first, then run, so a
> failed fetch fails the step:
>
> ```yaml
> setup:
>   install:
>     - command: "curl -fsSL https://example.com/install.sh -o /tmp/install.sh && bash /tmp/install.sh"
>       user: "1000"
> ```

## Customize the shell environment

Some tools install into a versioned directory and expect you to source
an init script from your shell profile so their commands land on `PATH`.
Version managers like [nvm](https://github.com/nvm-sh/nvm) and
[SDKMAN!](https://sdkman.io/) follow this pattern. To make the tool
available in every shell, append the source line to
`/etc/sandbox-persistent.sh` in an install command.

`/etc/sandbox-persistent.sh` is the sandbox's persistent environment
file. It's sourced before every bash invocation — interactive shells and
non-interactive ones, including agents started with `sbx run` and
commands run with `sbx exec`. Appending here makes the tool available to
the agent regardless of how its shell is launched. Use
[`environment.variables`](kit-reference.md#environment) for ordinary variables
declared by a kit. To pass variables when creating a sandbox, use
[`-e` or `--env-file`](../usage.md#set-environment-variables).

```yaml {title="nvm/spec.yaml"}
schemaVersion: "2"
kind: mixin
name: nvm
displayName: nvm
description: Node version manager available in every shell

setup:
  install:
    - command: "curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash"
      user: "1000"
      description: Install nvm
    - command: |
        cat >> /etc/sandbox-persistent.sh <<'EOF'
        export NVM_DIR="$HOME/.nvm"
        unset NPM_CONFIG_PREFIX
        [ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
        EOF
      user: "1000"
      description: Source nvm for every shell
```

Both install steps run as `user: "1000"`. This installs the tool under
`/home/agent/` and can update `/etc/sandbox-persistent.sh`, which the agent user
owns. The `$HOME` in the appended lines resolves per user at source time, so the
agent user finds its own install. Append to the file rather than overwriting it
— the sandbox relies on its existing contents.

The base image ships its own Node and sets `NPM_CONFIG_PREFIX`, which
nvm won't activate alongside. `unset NPM_CONFIG_PREFIX` before sourcing
`nvm.sh` clears that conflict. Sourcing makes the `nvm` command
available; it doesn't put a Node version on `PATH`. Run
`nvm install --lts` to add one — wrap it in `bash -c '…'` if you script
it as an install step, since install steps run under `sh`.

Append only the init script, not the tool's tab-completion script.
Because `/etc/sandbox-persistent.sh` is sourced before every command,
completion scripts — which rely on variables that exist only during
completion — can break non-interactive shells that agents rely on.

## Install an internal CA certificate

If your organization uses a proxy that inspects HTTPS traffic, install
the proxy's internal root CA in the sandbox trust store. This helps
agents and SDKs trust certificates signed by the proxy.

```text
internal-ca/
├── spec.yaml
└── files/
    └── home/
        └── internal-ca.crt
```

Use a PEM-encoded certificate with a `.crt` extension. Files under
`files/home/` land in `/home/agent/` in the sandbox, so
`files/home/internal-ca.crt` becomes `/home/agent/internal-ca.crt` —
which is the path the install command reads from. If traffic can be
signed by more than one internal proxy, include each proxy's root CA in
the kit and install each certificate before running
`update-ca-certificates`.

```yaml {title="internal-ca/spec.yaml"}
schemaVersion: "2"
kind: mixin
name: internal-ca

setup:
  install:
    - command: "install -m 0644 /home/agent/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt && update-ca-certificates"
      user: "0"
      description: Install internal CA certificate
```

`update-ca-certificates` adds the certificate to the system trust
store, so tools and SDKs that read the system bundle trust the proxy's
certificates without further configuration.

## Run a background service

`setup.startup` runs on every sandbox start. To keep a long-running
service such as a dev server or daemon alive, set `background: true`. The
sandbox runs the command in the background and replays startup commands on
each start, so the service comes back after a stop/start cycle:

```yaml
setup:
  startup:
    - command: ["my-service", "--port", "8080"]
      user: "1000"
      background: true
```

A background service doesn't write to your terminal. To capture its output
for debugging, wrap the command in a shell and redirect to a log file. Let
`background: true` run the command in the background rather than adding a
trailing `&` yourself:

```yaml
setup:
  startup:
    - command:
        - sh
        - -c
        - my-service --port 8080 > /tmp/my-service.log 2>&1
      user: "1000"
      background: true
```

An empty log file tells you the wrapper ran; a populated one tells you why
the service failed.

## Write runtime values to a file

When a config file needs a value that isn't known until sandbox start
— most often the absolute workspace path — use `setup.files`.
The `${WORKDIR}` placeholder expands to the primary workspace path
when the file is written.

```yaml
setup:
  files:
    - path: /home/agent/.local/bin/start-code-server.sh
      content: |
        exec code-server --bind-addr 0.0.0.0:8080 --auth none "${WORKDIR}"
      mode: "0755"
  startup:
    - command:
        - sh
        - -c
        - nohup /home/agent/.local/bin/start-code-server.sh > /tmp/code-server.log 2>&1 &
      user: "1000"
```

`mode: "0755"` makes the generated file executable so the startup
command can invoke it directly.

Use `setup.files` instead of a static file whenever the content depends
on a runtime value. Use a static file otherwise.

> [!TIP]
> This snippet is lifted from the
> [code-server kit](https://github.com/docker/sbx-kits-contrib/tree/main/code-server)
> in the contrib repository, which is also a runnable sample that demonstrates
> the full pattern.

## Ship a Claude Code skill

Claude Code reads project-scoped skills from
`.claude/skills/<name>/SKILL.md` in the workspace. Drop one into
`files/workspace/` and it's available in the sandbox.

```text
docker-review/
├── spec.yaml
└── files/
    └── workspace/
        └── .claude/
            └── skills/
                └── docker-review/
                    └── SKILL.md
```

```yaml {title="docker-review/spec.yaml"}
schemaVersion: "2"
kind: mixin
name: docker-review
displayName: Dockerfile review skill
description: Ships a Claude Code skill that reviews Dockerfiles
```

```markdown {title="docker-review/files/workspace/.claude/skills/docker-review/SKILL.md"}
---
name: docker-review
description: Review a Dockerfile for best practices. Use when the user asks to review, audit, or improve a Dockerfile.
---

When reviewing a Dockerfile, check:

1. Base image — pinned tag or digest, appropriate for the workload
2. Layer order — dependencies copied before application source
3. Image size — multi-stage builds, `.dockerignore`, package-manager cache flags
4. Security — non-root `USER`, no secrets in `ARG`/`ENV`
5. Reproducibility — pinned package versions, frontend directive where relevant
```

Kits have to target the workspace rather than `~/.claude/` because
sandboxes don't pick up user-level agent configuration from the host.
See the
[FAQ](../faq.md#why-doesnt-the-sandbox-use-my-user-level-agent-configuration)
for details.

## Customize agent settings

Some agents combine settings from several files. When the agent supports it,
place kit settings in a separate file instead of replacing
[sandbox-managed agent configuration](kits.md#sandbox-managed-agent-configuration).

Claude Code's `--settings` option loads an additional settings file. Extend the
built-in `claude` kit to add the option without reproducing its configuration,
and place the additional file outside the path the sandbox manages:

```text
claude-sonnet/
├── spec.yaml
└── files/
    └── home/
        └── .config/
            └── claude/
                └── sonnet.json
```

```yaml {title="claude-sonnet/spec.yaml"}
schemaVersion: "2"
kind: sandbox
name: claude-sonnet
extends: claude

sandbox:
  command:
    - --dangerously-skip-permissions
    - --settings
    - /home/agent/.config/claude/sonnet.json
```

```json {title="claude-sonnet/files/home/.config/claude/sonnet.json"}
{
  "model": "sonnet"
}
```

Claude Code merges the additional file with the sandbox-managed user settings.
Because the file is under `files/home/`, it stays inside the sandbox instead of
being written into a directly mounted host workspace. Launch the sandbox by
passing the child kit directory in place of a built-in agent name:

```console
$ sbx run ./claude-sonnet
```

When you launch the kit for the first time, `sbx` prompts you to approve its
inherited Anthropic credentials. Because this is a third-party schema v2 kit,
`sbx` records your approval as a
[credential binding](../configuration/credentials.md#credential-bindings).

OpenCode supports an additional config file through `OPENCODE_CONFIG`. Keep the
kit's config separate from the sandbox-managed
`/home/agent/.config/opencode/opencode.json`, for example at
`/home/agent/.config/opencode/team.json`:

```text
opencode-team/
├── spec.yaml
└── files/
    └── home/
        └── .config/
            └── opencode/
                └── team.json
```

```yaml {title="opencode-team/spec.yaml"}
schemaVersion: "2"
kind: mixin
name: opencode-team
requires:
  agent: opencode

environment:
  variables:
    OPENCODE_CONFIG: /home/agent/.config/opencode/team.json
```

```json {title="opencode-team/files/home/.config/opencode/team.json"}
{
  "$schema": "https://opencode.ai/config.json",
  "autoupdate": false
}
```

OpenCode merges the custom file with its global and project config files. See
the OpenCode [config precedence](https://opencode.ai/docs/config/#precedence-order)
for the complete order.

Agent settings mechanisms differ. If an agent doesn't support an additional
config file, launch option, or environment variable for the setting, kits can't
replace the sandbox-managed user settings before the agent launches.
`setup.startup` doesn't gate the agent entrypoint, so don't use it for settings
the agent must read during initialization.

## Fork an existing agent

Sandbox kits (`kind: sandbox`) define a full agent from scratch. The most
common variant is a fork of a built-in agent. Use `extends:` to inherit the
parent's complete configuration and declare only the fields you want to change.
This example replaces the built-in `claude` entrypoint so Claude Code uses
manual permission mode instead of bypassing approval prompts:

```yaml {title="claude-safe/spec.yaml"}
schemaVersion: "2"
kind: sandbox
name: claude-safe
displayName: Claude Code (with approval prompts)
description: Claude Code in manual permission mode

extends: claude

sandbox:
  entrypoint: [claude, "--permission-mode", "manual"]
```

The child inherits the built-in image, credentials, network permissions,
persistent volumes, settings, MCP integration, agent instructions, setup
entries, and environment variables. Its `sandbox.entrypoint` replaces the
inherited entrypoint.

Launch by passing the sandbox kit in place of a built-in agent name:

```console
$ sbx run ./claude-safe
```

For a step-by-step walkthrough of building a new sandbox kit from
scratch, see [Build an agent](build-an-agent.md).

## More examples

These patterns are all drawn from working kits in the
[sbx-kits-contrib](https://github.com/docker/sbx-kits-contrib)
repository, which contains each example as a complete, loadable kit.
Use it to study the full shape of a kit. Load a mixin with `--kit`:

```console
$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=<kit>"
```

For a `kind: sandbox` kit, pass the reference in place of the agent name:

```console
$ sbx run "git+https://github.com/docker/sbx-kits-contrib.git#dir=<kit>"
```


---

# Kit spec reference

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

> [!NOTE]
> Kits are experimental. The kit file format, CLI commands, and experience
> for creating, loading, and managing kits are subject to change as the
> feature evolves. Share feedback and bug reports in the
> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository.

This page documents every field in a kit's `spec.yaml`. For an overview of
what kits are and how to use them, see [Kits](kits.md).

For the normative v2 grammar used by the parser and tests, see the
[`schemaVersion: "2"` specification](https://github.com/docker/sbx-kits-contrib/blob/main/spec/SPEC-v2.md)
in the `docker/sbx-kits-contrib` repository.

A kit directory has a required `spec.yaml` and an optional `files/` tree:

```text
my-kit/
├── spec.yaml       # required
└── files/          # optional — static files to inject
    ├── home/
    └── workspace/
```

## Schema versions

Starting with Docker Sandboxes version 0.36, two schema versions are supported.
Use `schemaVersion: "2"` for new kits. Version `"1"` remains accepted through
the legacy path.

The loader forks on `schemaVersion`. A v2 spec uses the v2 grammar only. Legacy
v1 fields in a `schemaVersion: "2"` spec are rejected during decode instead of
being folded into the v2 model. Keep each `spec.yaml` on one grammar.

What changed in v2:

| v1                                          | v2                                       |
| ------------------------------------------- | ---------------------------------------- |
| `credentials.sources.<id>`                  | `credentials:` list entry with `service` |
| `network.allowedDomains` / `deniedDomains`  | `permissions.network.allow` / `deny`     |
| `network.serviceDomains` / `serviceAuth`    | `credentials[].apiKey.inject`            |
| `network.publishedPorts` / `publishedPorts` | top-level `ports`                        |
| standalone `oauth:` block                   | `credentials[].oauth`                    |
| `oauth.skipIfEnv`                           | Accepted but ignored                     |
| `environment.proxyManaged`                  | `credentials[].apiKey.proxyManaged`      |
| `memory` / `agentContext`                   | `agentInstructions.content`              |
| `kind: agent` / `agent:` block              | `kind: sandbox` / `sandbox:` block       |
| `sandbox.aiFilename`                        | `agentInstructions.filename`             |
| `sandbox.entrypoint.run`                    | `sandbox.entrypoint`                     |
| `sandbox.entrypoint.args`                   | `sandbox.command.default`                |
| `sandbox.entrypoint.ttyArgs`                | `sandbox.command.interactive`            |
| `tmpfs:`                                    | `volumes:` entries with `type: tmpfs`    |
| `volumes:` (mapping form)                   | `volumes:` sequence (`- path: <path>`)   |
| `commands:` / `commands.initFiles`          | `setup:` / `setup.files`                 |
| `settings:` / `kitDir` / `persistence`      | Removed                                  |

Credential discovery also moved out of the kit in v2: a kit declares which
credentials it needs and how to inject them, but where each value comes from is
controlled by the user through
[credential bindings](../configuration/credentials.md#credential-bindings).

> [!NOTE]
> `mixins` and `sandbox.build` are accepted by the parser, but runtime support
> is pending. A kit that sets `sandbox.build` must also set `sandbox.image`.

## Top-level fields

```yaml
schemaVersion: "2"
kind: <mixin | sandbox>
name: <name>
version: <version>
displayName: <name>
description: <text>
sourceURL: <url>
licenses:
  - MIT
locked:
  - sandbox.image
security:
  privileged: false
args:
  channel:
    default: stable
    enum: [stable, beta]
```

| Field           | Required | Description                                                                                     |
| --------------- | -------- | ----------------------------------------------------------------------------------------------- |
| `schemaVersion` | Yes      | Spec schema version. Use `"2"` for this grammar.                                                |
| `kind`          | Yes      | `mixin` for kits that extend an agent; `sandbox` for kits that define one.                      |
| `name`          | Yes      | Unique identifier. Lowercase alphanumeric with hyphens, 1 to 64 characters.                     |
| `version`       | No       | Kit version.                                                                                    |
| `displayName`   | No       | Human-readable name.                                                                            |
| `description`   | No       | Short description.                                                                              |
| `sourceURL`     | No       | Source repository or documentation URL.                                                         |
| `licenses`      | No       | SPDX license identifiers.                                                                       |
| `locked`        | No       | Dotted paths child kits may not override.                                                       |
| `security`      | No       | Container security settings. `security.privileged: true` runs the container in privileged mode. |
| `args`          | No       | Arguments supplied when the kit is loaded. Schema v2 only.                                      |

A kit also declares behavior blocks such as `agentInstructions`,
`permissions`, `ports`, `credentials`, `environment`, `setup`, and `volumes`.

## Arguments

A schema v2 kit can declare arguments and reference them anywhere in
`spec.yaml` or under `files/` as `${{ kit.args.<name> }}`. Substitution happens
before the spec is decoded.

```yaml
args:
  version:
    default: latest
    description: Tool version to install
    pattern: '^(latest|[0-9]+\.[0-9]+\.[0-9]+)$'
  channel:
    default: stable
    enum: [stable, beta, nightly]
  target:
    required: true
    description: Build target

environment:
  variables:
    TOOL_VERSION: "${{ kit.args.version }}"
```

Don't use kit arguments for API tokens, passwords, or other secrets. Use
[Credentials](../configuration/credentials.md) to provide sensitive values to
a sandbox.

| Field         | Description                                                                                                  |
| ------------- | ------------------------------------------------------------------------------------------------------------ |
| Argument name | Starts with a letter or underscore and contains only letters, digits, underscores, and hyphens.             |
| `default`     | String to use when the caller supplies no value. Mutually exclusive with `required: true`.                   |
| `required`    | Set to `true` when the caller must supply a value. Mutually exclusive with `default`.                        |
| `description` | Optional help text shown when a required value is missing.                                                   |
| `enum`        | Optional list of accepted values. Mutually exclusive with `pattern`.                                         |
| `pattern`     | Optional Go RE2 regular expression matched against the complete value. Mutually exclusive with `enum`.       |

Each argument must declare either `default`, including an empty-string
default, or `required: true`. A declared default must satisfy its own `enum` or
`pattern`. Every `${{ kit.args.<name> }}` reference must have a matching
declaration.

Argument values are strings, but substitution happens before YAML decoding.
Quote a placeholder in a string-valued field so a value such as `1.20` isn't
decoded as a number.

Supply values with `--kit-arg` or `--kit-args-file` when loading the kit. See
[Pass arguments to kits](kits.md#pass-arguments-to-kits) for scoping,
precedence, and validation behavior.

## Kit kinds

### `kind: mixin`

A mixin layers capabilities onto an existing sandbox. It must not declare a
`sandbox:` block, `extends:`, or `mixins:`. A mixin can declare `requires:` to
pin the base agent it is designed for:

```yaml
schemaVersion: "2"
kind: mixin
name: github-tools
requires:
  agent: claude
```

`requires.agent` takes one base-agent name. It is validated as a kit name and
enforced during composition.

### `kind: sandbox`

A sandbox kit defines a full agent. A root sandbox must declare a `sandbox:`
block. A sandbox that uses `extends:` can inherit the parent image and omit its
own `sandbox:` block:

```yaml
schemaVersion: "2"
kind: sandbox
name: claude-safe
extends: claude
```

`extends:` is sandbox-only. The parent must resolve to a sandbox kit. `mixins:`
is also sandbox-only and accepted by the parser, but runtime composition support
is pending.

## Sandbox block

```yaml
sandbox:
  image: <image-ref>
  build:
    context: .
    dockerfile: Dockerfile
    args:
      AGENT_VERSION: "1.0.0"
    target: runtime
    platforms:
      - linux/amd64
  entrypoint: [my-agent, "--flag"]
  command:
    default: ["--task-mode"]
    interactive: []
  resources:
    cpu: 2
    memory: 4g
    gpu: "1"
```

| Field                | Required | Description                                                                                                     |
| -------------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `sandbox.image`      | When `extends:` is omitted | Docker image reference.                                                                                         |
| `sandbox.build`      | No       | Build configuration. Runtime support is pending, so a kit with `build:` must also set `image:`.                 |
| `sandbox.entrypoint` | No       | Fixed process prefix as a string array. The first element is the agent binary.                                  |
| `sandbox.command`    | No       | Mode-specific argument tail. Use a list shorthand for `default`, or a mapping with `default` and `interactive`. |
| `sandbox.resources`  | No       | Optional CPU, memory, and GPU constraints. Memory uses byte-size strings such as `4096m` or `4g`.               |

The effective command is `entrypoint` plus `command.default` for non-interactive
launches, and `entrypoint` plus `command.interactive` for TTY sessions. If
`interactive` is omitted, it falls back to `default`.

For a kit that uses `extends:`, `sandbox.command` replaces the full inherited
argument tail, including flags after the binary in the parent's
`sandbox.entrypoint`. It doesn't append to that tail. Define every argument the
child needs. For example, a child of `claude` that adds `--settings` must also
include `--dangerously-skip-permissions` to preserve that behavior.

The agent's container image must provide:

- A non-root `agent` user at UID 1000 with passwordless sudo.
- A `/home/agent/` home directory owned by `agent`.
- HTTP proxy environment variables (`HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`) preserved across sudo.
- The agent binary, either baked in or installed with [`setup.install`](#setup).

Build on top of `docker/sandbox-templates:shell-docker` to get these base
requirements.

## Agent instructions

```yaml
agentInstructions:
  filename: CLAUDE.md
  content: |
    Ruff is installed. Run `ruff check` before committing.
```

| Field      | Description                                                                                         |
| ---------- | --------------------------------------------------------------------------------------------------- |
| `filename` | AI profile filename. Meaningful for `kind: sandbox`; ignored with a warning for `kind: mixin`.      |
| `content`  | Markdown instructions. For a sandbox, inlined into the profile. For a mixin, written to kit memory. |

For mixins, the engine writes `content` to
`<dir-of-AI-file>/kits-memory/<kit-name>.md` and adds a `## Kits` pointer
section to the base AI file. This keeps each mixin's instructions in a separate
file.

## Credentials

A kit declares the credentials it needs and how the proxy injects them into
outbound requests. It does not declare a host discovery source. The user
provides the value through the secret store or the first-run prompt, and a
[credential binding](../configuration/credentials.md) authorizes its use. A kit
can't read arbitrary host environment variables or files.

```yaml
credentials:
  - service: <service-id>
    description: <text> # optional
    required: <true | false> # optional, default false
    provider: <provider> # optional, reserved
    apiKey:
      name: <ENV_VAR>
      proxyManaged: true
      inject:
        - domain: <domain>
          header: <header>
          format: <format>
        - domain: <domain>
          scheme: bearer
        - domain: <domain>
          scheme: basic
          username: <user> # required with scheme: basic
    oauth:
      tokenEndpoint:
        host: <host>
        path: <path>
      sentinels:
        accessToken: <sentinel>
        refreshToken: <sentinel>
      credentialFile:
        path: <path>
        structure:
          <key>:
            accessToken: "{{.AccessToken}}"
            refreshToken: "{{.RefreshToken}}"
            expiresAt: "{{.ExpiresAt}}"
            scopes: "{{.Scopes}}"
```

`credentials` is a list; each entry names a `service` and configures one or more
auth mechanisms.

| Field         | Description                                                                                                                                 |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `service`     | Credential identifier, matched against the value stored with `sbx secret set`. Lowercase kebab-case.                                        |
| `description` | Optional. Shown to the user when approving a [binding](../configuration/credentials.md#credential-bindings).                                     |
| `required`    | Marks the credential as essential to the agent. If it has no binding, `sbx` warns and starts with the credential withheld. Default `false`. |
| `provider`    | Reserved for a provider registry. Accepted with a warning and no runtime effect.                                                            |
| `apiKey`      | API-key injection (see [apiKey](#apikey)).                                                                                                  |
| `oauth`       | OAuth interception (see [oauth](#oauth)).                                                                                                   |

Each service must declare `apiKey`, `oauth`, or both. When both resolve at
runtime, the API key takes precedence and OAuth acts as the fallback.

### `apiKey`

| Field               | Description                                                                                                                                       |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | Environment variable name for the credential (for example, `ANTHROPIC_API_KEY`).                                                                  |
| `proxyManaged`      | If `true`, `sbx` sets `name` inside the container to the `proxy-managed` sentinel. Default `false`.                                               |
| `inject[].domain`   | Domain to inject the credential into. Must also be allowed in [`permissions.network`](#network).                                                  |
| `inject[].header`   | HTTP header the proxy sets (for example, `x-api-key`, `Authorization`).                                                                           |
| `inject[].format`   | Header value format, with one `%s` placeholder (for example, `"%s"` or `"Bearer %s"`). Mutually exclusive with `scheme`.                          |
| `inject[].scheme`   | Shorthand for common auth schemes. `bearer` expands to `Authorization: Bearer %s`; `basic` requires `username`. Mutually exclusive with `format`. |
| `inject[].username` | Username for HTTP Basic auth, for example `x-access-token` for Git over HTTPS.                                                                    |

### `oauth`

For agents that authenticate with OAuth (for example, Claude Code), the proxy
intercepts token responses and replaces real tokens with sentinels, then swaps
the real token back in on outbound requests. By default, the token never enters
the sandbox. Setting `passthrough: true` opts out of sentinel masking and sends
the real token response into the sandbox.

| Field                                    | Description                                                                                                                                                                                       |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokenEndpoint.host` / `path`            | The OAuth token endpoint the proxy intercepts.                                                                                                                                                    |
| `sentinels.accessToken` / `refreshToken` | Sentinel values written into the container in place of the real tokens.                                                                                                                           |
| `credentialFile.path`                    | Where to write the credential file inside the container (`~` expands).                                                                                                                            |
| `credentialFile.structure`               | Declarative JSON shape. Supports `{{.AccessToken}}`, `{{.RefreshToken}}`, `{{.ExpiresAt}}`, and `{{.Scopes}}`.                                                                                   |
| `credentialFile.template`                | Go template. Supports `{{.AccessToken}}`, `{{.RefreshToken}}`, `{{.ExpiresAt}}`, `{{.Scopes}}`, and `{{.ScopesJSON}}`.                                                                          |
| `resourceHosts`                          | API hosts where the proxy attaches the token on outbound requests, distinct from the token endpoint host.                                                                                         |
| `skipIfEnv`                              | Accepted for compatibility, but ignored for schema v2. A v2 binding is authoritative instead of host environment variables.                                                                       |
| `responseFields`                         | Overrides the default field names the proxy reads from the token response.                                                                                                                        |
| `passthrough`                            | If `true`, the proxy passes the token response through unchanged instead of replacing the tokens with sentinels.                                                                                  |

`credentialFile.structure` provides a declarative alternative to
`credentialFile.template`. The engine renders it as well-formed JSON. If both
fields are set, `structure` takes precedence.

## Network

Network egress is declared under `permissions.network`. Credentials no longer carry
their own domain mapping — the proxy injects a credential only into the domains
its [`apiKey.inject`](#apikey) lists, and every domain the
sandbox reaches must be allowed here.

```yaml
permissions:
  network:
    allow: [<domain>, ...]
    deny: [<domain>, ...]
```

| Field                       | Description                                                                                                     |
| --------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `permissions.network.allow` | Domains the sandbox can reach.                                                                                  |
| `permissions.network.deny`  | Domains the sandbox is blocked from reaching. Deny takes precedence over allow, including across composed kits. |

Allow and deny patterns:

| Pattern               | Example                  | Status                      |
| --------------------- | ------------------------ | --------------------------- |
| Exact host            | `api.example.com`        | Enforced                    |
| Exact host and port   | `api.example.com:8080`   | Enforced                    |
| Single-label wildcard | `*.example.com`          | Enforced                    |
| Multi-label wildcard  | `**.example.com`         | Parsed; enforcement pending |
| Port range            | `api.example.com:80-443` | Parsed; enforcement pending |
| Port wildcard         | `api.example.com:*`      | Parsed; enforcement pending |
| CIDR                  | `10.0.0.0/8`             | Parsed; enforcement pending |

In v1 this was the `network:` block (`allowedDomains` / `deniedDomains`, plus
`serviceDomains` / `serviceAuth`). In v2, those fields are decode errors.

## Ports

Use `ports` to expose sandbox services to the host:

```yaml
ports:
  - container: 8080
    name: web
```

| Field       | Description                                                         |
| ----------- | ------------------------------------------------------------------- |
| `container` | Container port, 1 to 65535.                                         |
| `protocol`  | `tcp` or `udp`. Empty publishes one family; see below.              |
| `name`      | Optional label surfaced by tools that list published port bindings. |

Host ports are allocated ephemerally. Leave `protocol` empty unless the service
listens on IPv6: an empty value publishes IPv4 only (`127.0.0.1`), which is what
a service bound to `0.0.0.0` needs, while `tcp` publishes both `127.0.0.1` and
`::1` — and a client arriving over `::1` is accepted and then reset if nothing
in the sandbox is listening there. Users can pin host ports with
`sbx ports --publish <host>:<container>`.

## Environment

```yaml
environment:
  variables:
    <NAME>: <value>
```

| Field       | Description                                    |
| ----------- | ---------------------------------------------- |
| `variables` | Key-value pairs set directly in the container. |

Variable names must be valid shell identifiers (`[A-Za-z_][A-Za-z0-9_]*`).

Do not set `DASH_`, `SBX_`, or `DOCKER_` variables, and avoid overriding
`HOME`, `USER`, `SHELL`, `PATH`, `LD_PRELOAD`, and `LD_LIBRARY_PATH`. The
runtime reserves these names and may override them.

## Setup

```yaml
setup:
  install:
    - command: <shell-string>
      user: <uid>
      description: <text>
  startup:
    - command: [<argv>, ...]
      user: <uid>
      background: <true | false>
      description: <text>
  files:
    - path: <path>
      content: <text>
      mode: <octal>
      onlyIfMissing: <true | false>
      description: <text>
```

### Execution order

When a sandbox is created, kit content is applied in this order:

1. Network permissions and environment variables.
2. Static files under `files/home/`.
3. `setup.install` commands, in declaration order.
4. `setup.files` entries.
5. `setup.startup` commands are registered for each sandbox start.
6. Static files under `files/workspace/`, after the workspace is ready. With
   `--clone`, this means after the repository has been cloned.

For stacked kits, entries in each stage are applied in `--kit` order. An install
command can consume a bundled file from `files/home/`, but not one from
`files/workspace/` or `setup.files`, because those files land later.

`sbx kit add` recreates the sandbox rather than modifying it in place. It
supports mixin kits limited to
`environment.variables`, `setup.install`, and `permissions.network.allow`,
which follow the same order as sandbox creation. It rejects a kit that declares
static files, `setup.startup`, or `setup.files`. To use those fields, recreate
the sandbox with the kit.

### install

Runs synchronously when a kit is applied, either during sandbox creation or
through `sbx kit add`. Shell strings are passed to `sh -c`.

Kit install commands start in the template image's configured `WORKDIR`.
Docker-provided templates use `/home/agent/workspace`, which isn't necessarily
the primary workspace in a direct-mounted or clone-mode sandbox. Don't rely on
the current directory to locate workspace files. Use absolute paths for bundled
assets from `files/home/`.

| Field         | Default | Description                   |
| ------------- | ------- | ----------------------------- |
| `command`     | —       | Shell command string.         |
| `user`        | `"0"`   | User to run as. `"0"` = root. |
| `description` | —       | Human-readable description.   |

### startup

Runs at every sandbox start. String array, not interpreted by a shell.

| Field         | Default  | Description                         |
| ------------- | -------- | ----------------------------------- |
| `command`     | —        | Command and args as a string array. |
| `user`        | `"1000"` | User to run as. `"1000"` = agent.   |
| `background`  | `false`  | Block later startup commands until this command finishes. Set to `true` to let later commands run without waiting. |
| `description` | —        | Human-readable description.         |

Startup commands are non-interactive. They run before the agent
attaches, with no terminal connected, so they can't prompt the user
(for example, an interactive `aws login` will hang or fail). They also
don't gate the agent's entrypoint: the agent launches once startup
commands have been dispatched, regardless of `background`. A value of
`false` waits within the startup dispatcher before it runs the next command;
it doesn't delay the agent entrypoint. Use startup commands
for work that can run alongside the agent. Use `setup.files` for any value that
needs to land on disk before the agent runs.

Startup commands must be idempotent. They run on every sandbox start
and replay on container restarts, so a command that fails or
misbehaves on a second invocation breaks the restart path. Guard
work with existence checks, use upserts instead of inserts, and
prefer commands that converge to the same end state regardless of
how many times they run.

### files

Files written at sandbox start, with runtime substitution.

| Field           | Default  | Description                                               |
| --------------- | -------- | --------------------------------------------------------- |
| `path`          | —        | Absolute container path.                                  |
| `content`       | —        | File content. `${WORKDIR}` expands to the workspace path. |
| `mode`          | `"0644"` | File permissions in octal.                                |
| `onlyIfMissing` | `false`  | Skip if the file already exists.                          |

The runtime writes these files as the agent user with UID 1000. The target
path must be writable by that user. To write to a root-owned path such as
`/etc`, use an `install` command, which runs as root by default. Set ownership
in the install command if the agent needs to modify the file later.

## Static files

```text
my-kit/files/
├── home/       → /home/agent/
└── workspace/  → primary workspace path
```

| Kit path           | Container destination                   |
| ------------------ | --------------------------------------- |
| `files/home/`      | `/home/agent/` (config files, dotfiles) |
| `files/workspace/` | The primary workspace path              |

Parent directories are created automatically. Existing files are
overwritten. Absolute paths and path-traversal sequences (`../../`) are
rejected.

## Volumes

```yaml
volumes:
  - path: /workspace
    size: 10g
    mode: "0755"
  - path: /tmp/scratch
    type: tmpfs
    size: 512m
    mode: "1777"
```

| Field  | Description                                                         |
| ------ | ------------------------------------------------------------------- |
| `path` | Required absolute container path.                                   |
| `type` | Empty for a block-backed volume, or `tmpfs` for RAM-backed storage. |
| `size` | Optional byte-size string.                                          |
| `mode` | Optional octal permissions.                                         |

Volumes are applied only when a sandbox is created. `sbx kit add` cannot attach
volumes to a running container.


---

# Kits

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

> [!NOTE]
> Kits are experimental. The kit file format, CLI commands, and experience
> for creating, loading, and managing kits are subject to change as the
> feature evolves. Share feedback and bug reports in the
> [docker/sbx-releases](https://github.com/docker/sbx-releases) repository.

A kit packages a set of capabilities a sandbox can use, such as:

- Tools to install
- Environment variables to set
- Credentials to inject
- Network rules to allow or deny domains
- Files to drop in
- Startup commands to run
- Memory instructions to give the agent

You declare these in a single `spec.yaml` file, point the CLI at the
directory (or a ZIP, OCI artifact, or Git URL), and the sandbox applies
and enforces them at runtime. Credentials stay on the host and go through
a proxy instead of entering the VM, and outbound traffic is restricted to
the domains permitted by the kit's network rules.

A kit is either a mixin or a sandbox:

- Mixin kits (`kind: mixin`) extend an existing agent with extra
  capabilities. Stack several on the same sandbox.
- Sandbox kits (`kind: sandbox`) define a full agent from scratch: its image,
  entrypoint, network policies, and everything else the agent needs.

## What kits can do

### Run commands

A kit can run commands inside the sandbox automatically. **Install
commands** run once at creation; **startup commands** run each time
the sandbox starts.

Install commands are the place to put anything an agent needs into the
image, via `apt`, `pip`, `npm`, `curl | bash`, or whatever fits:

```yaml
setup:
  install:
    - command: "apt-get update && apt-get install -y jq"
```

Startup commands are for work that can run alongside the agent, such as a
background service. They must be idempotent — see the
[`startup`](kit-reference.md#startup) spec reference:

```yaml
setup:
  startup:
    - command: ["my-daemon"]
      background: true
```

### Inject files

Kits can inject files into the sandbox in two ways: **static files** bundled
with the kit, and **`setup.files`** written at startup with runtime values
substituted in.

Static files work well for content that doesn't vary between sandboxes, such
as tool configurations, shared linter rules, helper scripts the agent can
invoke, or reference material like a style guide or API cheatsheet.

```text
my-kit/
├── spec.yaml
└── files/
    ├── home/
    │   └── .config/my-tool/settings.json
    └── workspace/
        └── .editorconfig
```

`setup.files` cover content that depends on runtime values, such as an
absolute workspace path that a tool needs to bake into its config file
at startup:

```yaml
setup:
  files:
    - path: /home/agent/.my-tool/config.json
      content: '{"workspace": "${WORKDIR}"}'
      onlyIfMissing: true
```

See [`setup.files`](kit-reference.md#files) in the spec reference for all
fields.

#### Sandbox-managed agent configuration

Built-in agent kits reserve the following paths for sandbox setup. Treat these
paths as sandbox-managed, even if a file is only needed for a particular
feature. Don't target them with static files, `setup.files`, or install
commands. Later setup can replace your content or depend on settings that your
file removes. In this table, `~` is `/home/agent`.

| Built-in agent kit | Managed configuration paths |
| ------------------ | --------------------------- |
| `claude` | `~/.claude.json`, `~/.claude/settings.json`, `~/.claude/.config.json` |
| `codex` | `~/.codex/config.toml` |
| `copilot` | `~/.copilot/config.json` |
| `cursor` | `~/.cursor/cli-config.json` |
| `devin` | `~/.config/devin/config.json`, `~/.config/devin/mcp_config.json` |
| `gemini` | `~/.gemini/settings.json` |
| `kiro` | `~/.kiro/settings/mcp.json` |
| `opencode` | `~/.config/opencode/opencode.json` |

Use a separate settings layer when the agent supports one. For example, Claude
Code can load an additional settings file with `--settings`, and OpenCode can
load one from the path in `OPENCODE_CONFIG`. See
[Customize agent settings](kit-examples.md#customize-agent-settings) for
examples. Don't use `setup.startup` for settings the agent must read during
initialization because startup commands don't gate the agent entrypoint.

### Set environment variables

Environment variables set by the kit are available to the agent at
runtime:

```yaml
environment:
  variables:
    MY_TOOL_WORKSPACE: /home/agent/my-tool
```

For credentials, see
[Authenticate to external services](#authenticate-to-external-services).
Don't put secret values directly in `environment.variables` — they'd
be visible inside the sandbox VM.

> [!IMPORTANT]
> The sandbox manages proxy settings for you. It sets `HTTP_PROXY`,
> `HTTPS_PROXY`, `NO_PROXY`, and their lowercase equivalents automatically so
> that traffic flows through its built-in forward proxy, which enforces
> network policy and injects credentials. Leave these variables to the
> sandbox — setting them in a kit points traffic away from the forward proxy,
> so it can no longer apply network policy or inject credentials, and those
> requests typically fail to connect. To send sandbox traffic through an
> upstream corporate proxy, configure it on the host. See
> [Upstream proxy](../architecture.md#upstream-proxy).

### Control network access

Network rules define which domains the sandbox can reach or block. Kit
network rules apply only to sandboxes that use the kit:

```yaml
permissions:
  network:
    allow:
      - api.example.com
      - "*.cdn.example.com"
    deny:
      - telemetry.example.com
```

Use `allow` for hosts the agent needs, such as package
registries, install endpoints, or external APIs. Use `deny` for
hosts the agent should not reach, such as telemetry endpoints. If a domain
matches both an allow rule and a deny rule, the deny rule wins.

> [!IMPORTANT]
> When organization governance is active, only organization allow rules grant
> access, so kit-defined `allow` rules are ignored — including any domains a kit
> allows for the agent to reach. Kit-defined `deny` rules still apply, because a
> deny can only restrict access further. For details, see
> [Policy precedence](../governance/concepts.md#precedence).

For authenticated services, see
[Authenticate to external services](#authenticate-to-external-services).

### Authenticate to external services

A kit can attach credentials to outbound requests through the
host-side proxy. The agent inside the VM works with a sentinel value;
the proxy reads the real credential on the host and overwrites the
auth header before the request leaves the sandbox.

A kit declares the service, the in-container environment variable, and how
to inject the credential. It doesn't declare a host discovery source. The user
provides the value through the secret store or first-run prompt, and a
[credential binding](../configuration/credentials.md) authorizes its use:

```yaml
credentials:
  - service: my-service
    apiKey:
      name: MY_SERVICE_API_KEY # in-VM env var, set to a sentinel
      proxyManaged: true
      inject:
        - domain: api.example.com # inject on requests to this domain
          header: Authorization # overwrite this header
          format: "Bearer %s"

permissions:
  network:
    allow:
      - api.example.com # the domain must also be reachable
```

The agent boots with `MY_SERVICE_API_KEY=proxy-managed`, sends a
request with that sentinel in `Authorization`, and the proxy overwrites
the header with the real credential before forwarding. The real
secret never enters the VM.

See [Credentials](../configuration/credentials.md) for how to provide the
credential value on your host, other approaches for cases the example
above doesn't fit, and what the proxy does at request time. See
[Credential bindings](../configuration/credentials.md) to approve the mechanisms
and domains declared by a third-party v2 kit.

### Inject agent memory

A kit can append content to the agent's memory file, such as `CLAUDE.md`
or `AGENTS.md`. The agent reads this file at startup. Use it to give
the agent project conventions, usage tips for a tool the kit installs,
or other guidance that should be in scope when the sandbox runs.

```yaml
agentInstructions:
  content: |
    Ruff is installed. Run `ruff check` before committing.
    Shared config lives at `/workspace/ruff.toml`.
```

Both mixin and sandbox kits can declare `agentInstructions.content`. The active
sandbox kit sets `agentInstructions.filename`, which determines the memory
file's name. The sandbox kit's content is written inline in that file. Each
mixin's content is written to its own `<kit-name>.md` file under a sibling
`kits-memory/` directory, and the main memory file gets a `## Kits` section that
points to each mixin file:

```text
/Users/you/
├── myproject/              # workspace
├── AGENTS.md               # main memory file with a "## Kits" index
└── kits-memory/
    ├── ruff-lint.md
    ├── vale.md
    └── git-ssh-sign.md
```

See [`agentInstructions`](kit-reference.md#agent-instructions) in the spec
reference for the full field schema.

### Define an agent

Sandbox kits declare a `sandbox:` block with the image the agent runs in and
the command the user attaches to when they launch the sandbox:

```yaml
sandbox:
  image: "my-registry/my-agent:latest"
  entrypoint: [my-agent, "--yolo"]
```

See [Sandbox kits](#sandbox-kits) for use cases and an example.

## Mixin kits

A mixin kit extends an existing agent with extra capabilities. Common use
cases:

- Pre-install tools: linters, libraries, or other custom programs
- Grant the agent access to a new authenticated service (a database, a
  vendor API)
- Inject shared team config (linter rules, editor settings, dotfiles)

See [Drop a shared config file](kit-examples.md#drop-a-shared-config-file) and
[Install a tool at sandbox creation](kit-examples.md#install-a-tool-at-sandbox-creation)
for complete mixin examples.

## Sandbox kits

A sandbox kit defines a full agent from scratch — image, entrypoint, and
everything the agent needs. Common use cases:

- Package a custom agent you've built so others can run it
- Ship a team-internal agent with defaults baked in
- Run a fork of an existing agent with your own config
- Prototype a new agent integration

Sandbox kits declare everything a mixin kit can, plus an
[`sandbox:` block](kit-reference.md#sandbox-block) that tells the sandbox how to launch the
agent. For a step-by-step walkthrough, see
[Build your own agent kit](build-an-agent.md).

### Extend a built-in agent

Use `extends:` to create a variant of a built-in agent without reproducing its
configuration. The child kit inherits the parent's image, credentials, network
permissions, persistent volumes, settings, MCP integration, and agent
instructions. It also inherits the parent's environment variables and all
`setup.install`, `setup.startup`, and `setup.files` entries. Parent setup entries
run before child entries. If both kits set the same environment variable, the
child's value wins. Use `extends:` for a single parent agent; use a mixin to add
an independent capability that can work with one or more agents. See
[Fork an existing agent](kit-examples.md#fork-an-existing-agent) for an example
that changes Claude Code's permission mode.

## Using kits

Kits can be loaded from a local path (a directory or ZIP file), a Git
repository, or an OCI registry. To launch a sandbox kit, pass its reference in
place of a built-in agent name to `sbx run` or `sbx create`. Use `--kit` for
mixins, and repeat the flag to apply multiple mixins to the same sandbox.

Starting with Docker Sandboxes version 0.42.0, pass the sandbox kit reference
as the first argument:

```console
$ sbx run <sandbox-kit-ref> [PATH...]
$ sbx create <sandbox-kit-ref> [PATH...]
```

The previous form, `sbx run <sandbox-kit-name> --kit <sandbox-kit-ref>`, is
deprecated.

> [!IMPORTANT]
> A mixin passed with `--kit` only takes effect when a sandbox is created.
> Passing it against an
> existing sandbox name fails with
> `--kit can only be used when creating a new sandbox`. To add a supported
> mixin kit to a running sandbox, use [`sbx kit add`](#local) instead.
> `sbx kit add` restarts the sandbox to apply the updated kit set.
> VM state — installed packages, Docker images, volumes, and agent history
> — is preserved across the restart. It supports mixin kits limited to
> `environment.variables`, `setup.install`, and `permissions.network.allow`.
> To use other fields, recreate the sandbox with the mixin.

### Pass arguments to kits

A schema v2 kit can declare inputs in a top-level `args:` block and reference
them in `spec.yaml` or static files with `${{ kit.args.<name> }}`. Supply a
value with `--kit-arg name=value`:

```console
$ sbx run ./my-agent/ --kit-arg channel=beta
```

Kit argument values are plain text. Values supplied with `--kit-arg` can remain
in your shell history, and argument files store their values unencrypted. Don't
use kit arguments for secrets. Use [Credentials](../configuration/credentials.md)
instead.

An argument without a kit name prefix applies to every kit that declares it.
To target one kit, prefix the argument with the value of that kit's `name`
field and a period:

```console
$ sbx run ./my-agent/ \
    --kit ./my-mixin/ \
    --kit-arg version=1.2.3 \
    --kit-arg my-mixin.version=2.0.0
```

The kit-specific value takes precedence over the shared value for `my-mixin`.

Use `--kit-args-file` for a reusable set of `name=value` entries. Blank lines
and lines that start with `#` are ignored:

```text {title="kit.args"}
version=1.2.3
my-mixin.channel=beta
```

```console
$ sbx create ./my-agent/ . \
    --kit ./my-mixin/ \
    --kit-args-file ./kit.args \
    --kit-arg my-mixin.channel=stable
```

When you pass multiple argument files, a value in a later file overrides the
same key in an earlier file. Values passed with `--kit-arg` override every
file. For repeated `--kit-arg` entries with the same key, the last value wins.

Argument validation happens before the sandbox is created. `sbx` rejects a
missing required value, a value outside its declared `enum` or `pattern`, a
placeholder without a declaration, and a supplied argument that no resolved
kit declares. Pass the same argument flags to `sbx kit validate` or
`sbx kit inspect` when the kit requires values. See
[Kit arguments](kit-reference.md#arguments) for the declaration fields.

### Local

Launch a local sandbox kit by passing its directory or ZIP file in place of the
agent name. Relative paths must start with `./` or `../` so `sbx` can
distinguish them from agent and sandbox names:

```console
$ sbx run ./my-agent/
$ sbx create ../my-agent-1.0.zip .
```

Pass a local mixin with `--kit`:

```console
$ sbx run claude --kit ./my-mixin/
$ sbx run claude --kit ../my-mixin-1.0.zip
```

While iterating on a supported mixin kit, apply changes to a running sandbox
with `sbx kit add`:

```console
$ sbx kit add my-sandbox ./my-kit/
```

`sbx kit add` restarts the sandbox to apply the updated kit set.
VM state — installed packages, Docker images, volumes, and agent history — is
preserved across the restart. Kits can't be removed from a running sandbox —
remove and recreate it to start clean.

### Git repository

Launch a sandbox kit from a Git repository:

```console
$ sbx run "git+https://github.com/docker/sbx-kits-contrib.git#ref=v0.1.0&dir=amp"
```

Pass a Git-hosted mixin with `--kit`:

```console
$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#ref=v0.1.0&dir=code-server"
```

- `#ref=<branch|tag|commit>` pins to a specific revision. Defaults to the
  repository's default branch.
- `#dir=<path>` loads a kit from a subdirectory.
- `git+ssh://` URLs also work, using your local SSH agent, Git credential
  helpers, and `.netrc`.
- Quote the URL in shells where `&` starts a background job.

### OCI registry

Launch a sandbox kit from an OCI registry:

```console
$ sbx run docker.io/sbx/droid-kit:latest
```

Pass an OCI-hosted mixin with `--kit`:

```console
$ sbx run claude --kit ghcr.io/myorg/my-kit:1.0
```

For Docker Hub, include the full `docker.io` prefix. See
[Packaging and distribution](#packaging-and-distribution) for publishing.

> [!IMPORTANT]
> For Docker Hub, `sbx` reuses your `sbx login` session to pull private
> kits. For other registries, store pull credentials with
> [`sbx secret set --registry`](../configuration/credentials.md#registry-credentials)
> before running the sandbox. These credentials take priority over credentials
> in the Docker credential store:
>
> ```console
> $ gh auth token | sbx secret set --registry ghcr.io --password-stdin
> ```
>
> Without credentials from either store, pulls from non-Docker Hub registries
> are anonymous and private kits fail to pull.

### Restrict kit sources

`sbx` restricts which sources a kit can install from. A kit's install
commands run with root privileges inside the sandbox, so limiting where kits
come from reduces supply-chain risk. By default, only kits hosted on Docker
Hub (`docker.io/`) are allowed. Loading a kit from any other source fails:

```console
$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale"
ERROR: resolve kits: kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" cannot be installed — its source is not in your allowlist.
```

To allow another publisher, add its host or host/path prefix to the
`kit.allowedSources` setting. The setting replaces the whole list, so include
the entries you want to keep:

```console
$ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]'
```

Entries match as prefixes on a path-segment boundary, so `github.com/docker/`
allows `github.com/docker/sbx-kits-contrib` but not `github.com/docker-evil/kit`.
To remove the restriction and allow any remote source, set the list to
`["*"]`. This isn't recommended.

Installing from a local directory or ZIP file is governed separately by the
`kit.allowLocalKits` setting, which defaults to `true`. Set it to `false` to
require a remote source:

```console
$ sbx settings set kit.allowLocalKits false
```

For non-interactive use, both settings have environment-variable equivalents:
`DOCKER_SANDBOXES_KIT_ALLOWED_SOURCES` and `DOCKER_SANDBOXES_KIT_ALLOW_LOCAL`.

## Sign and verify kits

Use cosign-compatible Sigstore signatures to verify who approved a kit and
that its signed content hasn't changed. Signing is keyless by default. Verify a
keyless signature with the certificate identity and OpenID Connect (OIDC)
issuer:

```console
$ sbx kit sign ./my-kit/
$ sbx kit verify \
    --certificate-identity user@example.com \
    --certificate-oidc-issuer https://accounts.google.com \
    ./my-kit/
```

For key-based signing, use an ECDSA P-256 key pair:

```console
$ sbx kit sign --key cosign.key ./my-kit/
$ sbx kit verify --key cosign.pub ./my-kit/
```

For a local directory, `sbx kit sign` writes a `kit.sig.bundle` file next to
`spec.yaml`. Commit this file so consumers can verify a kit loaded from the Git
repository. For an OCI kit, the signature is stored as an OCI referrer. You can
sign an OCI kit after pushing it, or push and sign it in one step:

```console
$ sbx kit push ./my-kit/ ghcr.io/myorg/my-kit:1.0 --sign
```

ZIP kits can't carry verifiable signatures.

### Require signed kits

Set a trusted signer policy for the identities or keys you trust before
requiring signatures. Otherwise, `sbx` uses the default policy, which trusts
Docker employee identities attested by Google's OpenID Connect issuer. A
keyless policy must specify both the certificate identity and its OpenID
Connect issuer:

```console
$ sbx settings set kit.trustedSigners \
    '[{"identity":"release-bot@example.com","issuer":"https://accounts.google.com"}]'
$ sbx settings set kit.requireSignature true
```

To trust a key-based signature, set the policy to the public key path:

```console
$ sbx settings set kit.trustedSigners '[{"key":"/path/to/cosign.pub"}]'
$ sbx settings set kit.requireSignature true
```

When `kit.requireSignature` is `true`, `sbx` rejects unsigned kits, signatures
that don't match `kit.trustedSigners`, and ZIP kits. This policy applies when a
kit is loaded from a local directory, Git repository, or OCI registry.

The signature covers `spec.yaml` and the kit's `files/` content, but not mutable
dependencies such as image tags or content downloaded by install and startup
commands. Pin those dependencies by digest or checksum when they must remain
immutable.

## Packaging and distribution

The `sbx kit` subcommands validate, inspect, and publish kits:

- `sbx kit validate <path>` — check that a kit directory or ZIP is
  well-formed.
- `sbx kit inspect <path>` — display kit details. Add `--json` for
  machine-readable output.
- `sbx kit pack <path> -o <file.zip>` — package a directory as a ZIP file
  for sharing.
- `sbx kit push <path> <ref>` — publish to an OCI registry (for example,
  `ghcr.io/myorg/my-kit:1.0`).
- `sbx kit pull <ref>` — download a kit from a registry as a ZIP file to
  the working directory.

For Docker Hub, include the full `docker.io` prefix — `sbx` doesn't add it
automatically.

For Docker Hub, `sbx kit pull` and `sbx kit push` use the session from
`sbx login`. For other registries, they prefer credentials stored with
[`sbx secret set --registry`](../configuration/credentials.md#registry-credentials).
Both commands fall back to the Docker credential store, so credentials from
`docker login` also work.

## Spec reference

For a field-by-field reference of every `spec.yaml` block — top-level
fields, arguments, credentials, network, environment, setup, static files,
agent instructions, and the sandbox block — see [Kit spec reference](kit-reference.md).

## Debugging

When a kit doesn't behave as expected, start with the network policy log
and direct inspection inside the sandbox:

- `sbx policy log` shows every outbound request the sandbox proxy saw,
  the rule it matched, extra context when available, and its `PROXY`
  value, such as `forward`, `forward-bypass`, `transparent`, or
  `browser-open`. Use it to diagnose install-time download failures,
  blocked domains, and unexpected TLS interception. If downloads fail or
  arrive corrupted after you add a credential's `apiKey.inject`, check
  whether an injection domain is too broad. Inject only on the hosts that
  need credentials.
- `sbx exec <sandbox> -- <cmd>` runs an arbitrary command inside an
  existing sandbox. Useful for inspecting post-install state without
  recreating: `which mytool`, `ls /home/agent/.local/bin/`,
  `cat /home/agent/.config/...`, and so on.

Install and startup command output is only emitted during `sbx run` or
`sbx create`; `sbx` doesn't retain it for later inspection. To repeat
setup with fresh output, remove and recreate the sandbox:
`sbx rm <sandbox> && sbx run ...`.


---

# Templates

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes sbx" >}}

Every sandbox is customizable — agents install packages, pull images, and
configure tools as they work, and those changes persist for the sandbox's
lifetime. Templates capture a configured environment into a reusable image
so you don't have to set it up again every time.

## Custom templates

Custom templates are reusable sandbox images that extend one of the built-in
agent environments with additional tools and configuration baked in. Instead
of asking the agent to install packages every time, build a template once and
reuse it across sandboxes and team members.

Templates make sense when multiple people need the same environment, when
setup involves steps that are tedious to repeat, or when you need pinned
versions of specific tools. For one-off work, the default image is fine —
ask the agent to install what's needed.

> [!NOTE]
> Custom templates customize an existing agent's environment — they don't
> create new agent runtimes. The agent that launches inside the sandbox is
> determined by the base image variant you extend and the agent you specify
> in the `sbx run` command, not by binaries installed in the template. To
> define a new agent from scratch, see [Kits](kits.md#define-an-agent).

### Base images

All sandbox templates are published as
`docker/sandbox-templates:<variant>`. They are based on Ubuntu and run as a
non-root `agent` user with sudo access. Most variants include Git, Docker
CLI, and common development tools like Node.js, Python, Go, and Java.

| Variant               | Agent                                                                |
| --------------------- | -------------------------------------------------------------------- |
| `claude-code`         | [Claude Code](https://claude.ai/download)                            |
| `claude-code-minimal` | Claude Code with a minimal toolset (no Node.js, Python, Go, or Java) |
| `codex`               | [OpenAI Codex](https://github.com/openai/codex)                      |
| `copilot`             | [GitHub Copilot](https://github.com/github/copilot-cli)              |
| `cursor-agent`        | [Cursor](https://cursor.com/cli)                                     |
| `devin`               | [Devin CLI](https://docs.devin.ai/work-with-devin/devin-cli)         |
| `docker-agent`        | [Docker Agent](https://github.com/docker/docker-agent)               |
| `droid`               | [Droid](https://www.factory.ai)                                      |
| `gemini`              | [Gemini CLI](https://github.com/google-gemini/gemini-cli)            |
| `kiro`                | [Kiro](https://kiro.dev)                                             |
| `opencode`            | [OpenCode](https://opencode.ai)                                      |
| `shell`               | No agent pre-installed. Use for manual agent setup.                  |

Each variant also has a `-docker` version (for example, `claude-code-docker`)
that includes a full Docker Engine running inside the sandbox — no local Docker
daemon required. When you pick a built-in agent without specifying a custom
template, `sbx run` and `sbx create` use the `-docker` template variants by
default.

The agent containers created from the `-docker` templates run in privileged
mode inside the microVM (not on your host), with a dedicated block volume at
`/var/lib/docker`, and `dockerd` starts automatically inside the sandbox. The
block volume defaults to 10 GB and uses a sparse file, so it only consumes
disk space as Docker writes to it.

To change the volume size for a sandbox, set
`DOCKER_SANDBOXES_DOCKER_SIZE` when you create it:

```console
$ DOCKER_SANDBOXES_DOCKER_SIZE=20g sbx run claude
```

The volume size must be at least 512 MiB. The environment variable doesn't
resize existing volumes.

Use the non-Docker variant if you don't need to build or run containers
inside the sandbox and want a lighter, non-privileged environment. Specify
it explicitly with `--template`:

```console
$ sbx run claude --template docker.io/docker/sandbox-templates:claude-code
```

### Build a custom template

Building a custom template requires
[Docker Desktop](../../../desktop/index.md).

Write a Dockerfile that extends one of the base images. Pick the variant
that matches the agent you plan to run. For example, extend `claude-code`
to customize a Claude Code environment, or `codex` to customize an OpenAI
Codex environment.

The following example creates a Claude Code template with Rust and
protocol buffer tools pre-installed:

```dockerfile
FROM docker/sandbox-templates:claude-code
USER root
RUN apt-get update && apt-get install -y protobuf-compiler
USER agent
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
```

Use `root` for system-level package installations (`apt-get`), and switch
back to `agent` before installing user-level tools. Tools that install into
the home directory, such as `rustup`, `nvm`, or `pyenv`, must run as
`agent` — otherwise they install under `/root/` and aren't available in
the sandbox.

Build the image and push it to an OCI registry, such as Docker Hub:

```console
$ docker build -t my-org/my-template:v1 --push .
```

> [!NOTE]
> The Docker daemon used by Docker Sandboxes pulls templates from a
> registry directly; it doesn't share the image store of your local Docker
> daemon on the host. To route Docker Hub image pulls through your
> organization's registry infrastructure, configure a
> [registry mirror](../configuration/registry-mirror.md).

> [!IMPORTANT]
> For Docker Hub, `sbx` reuses your `sbx login` session to pull private
> images. For other registries (GitHub Container Registry, ECR, ACR, a
> self-hosted Nexus, and so on), store pull credentials with
> [`sbx secret set --registry`](../configuration/credentials.md#registry-credentials)
> before running the sandbox:
>
> ```console
> $ gh auth token | sbx secret set --registry ghcr.io --password-stdin
> ```
>
> Without stored credentials, pulls from non-Docker Hub registries are
> anonymous and private images fail to pull.

For locally-built images, save the image to a tar and load it directly
into the sandbox runtime instead of pulling from a registry:

```console
$ docker image save my-org/my-template:v1 -o my-template.tar
$ sbx template load my-template.tar
$ sbx run --template my-org/my-template:v1 claude
```

`sbx template load` imports the tar into the sandbox runtime's image
store, so the image doesn't need to be reachable from a registry at
sandbox creation time.

Unless you use the permissive `allow-all` network policy, you may also need
to allow-list any domains that your custom tools depend on:

```console
$ sbx policy allow network "*.example.com:443,example.com:443"
```

Then run a sandbox with your template. The agent you specify must match
the base image variant your template extends:

```console
$ sbx run --template docker.io/my-org/my-template:v1 claude
```

Because this template extends the `claude-code` base image, you run it
with `claude`. If you extend `codex`, use `codex`; if you extend `shell`,
use `shell` (which drops you into a Bash shell with no agent).

> [!NOTE]
> Unlike Docker commands, `sbx` does not automatically resolve the Docker
> Hub domain (`docker.io`) in image references.

### Template caching

Template images are cached locally. The first use pulls from the registry;
subsequent sandboxes reuse the cache. Cached images persist across sandbox
creation and deletion, and are cleared when you run `sbx reset`.

## Saving a sandbox as a template

Instead of writing a Dockerfile, you can save a running sandbox's state as
a template. This captures installed packages, configuration changes, and
files into a reusable image — useful when you've set up an environment
interactively and want to preserve it.

> [!WARNING]
> Saving a sandbox captures its entire filesystem, including any secrets
> stored on it. If you manually added API keys, tokens, or other
> credentials to the sandbox, they're embedded in the saved template and
> shared with anyone you distribute it to. To keep credentials out of
> templates, manage them with `sbx secret set` instead — the proxy injects
> them at runtime so they're never written to the filesystem. For more
> information, see [Manage credentials](../configuration/credentials.md).

### Save and reuse

Stop the sandbox (or let the CLI prompt you), then save it with a name and
tag:

```console
$ sbx template save my-sandbox my-template:v1
```

The image is stored in the sandbox runtime's local image store. Create a
new sandbox from it with the `-t` flag:

```console
$ sbx run -t my-template:v1 claude
```

### List and remove templates

List all saved templates:

```console
$ sbx template ls
```

Remove a template you no longer need:

```console
$ sbx template rm my-template:v1
```

### Export and import

To share a saved template or move it to another machine, export it as a
tar file:

```console
$ sbx template save my-sandbox my-template:v1 --output my-template.tar
```

On the other machine, load the tar file and use it:

```console
$ sbx template load my-template.tar
$ sbx run -t my-template:v1 claude
```

### Limitations

Agent configuration files are always recreated when a sandbox is created.
Changes to user-level agent configuration files, such as
`/home/agent/.claude/settings.json` and `/home/agent/.claude.json`, do not
persist in saved templates.

If the saved template was built for a different agent than the one you
specify in `sbx run`, you get a warning. For example, saving a Claude
sandbox and running it with `codex` produces:

```text
⚠ WARNING: template "my-template:v1" was built for the "claude" agent but you are using "codex".
  The sandbox may not work correctly. Consider using: sbx run -t my-template:v1 claude
```


---

# FAQ

*Sección: Ai*

## Is Docker Sandboxes free? Can I use it commercially?

Yes to both. The `sbx` CLI is free to use, including for commercial and
professional work, with no per-seat fee. Install it, sign in with a free
Docker account, and run sandboxes at no cost.

The only paid component is organization governance: centrally managed network,
filesystem, and MCP policies,
[sign-in enforcement](governance/monitor-and-enforce/sign-in-enforcement.md),
and [audit logs](governance/audit/). These
[organization governance features](governance/) require a separate paid
subscription —
[contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
to get started. Everything else, including running agents in isolated
sandboxes, is free.

## Why do I need to sign in?

Docker Sandboxes is built around the idea that you and your agents are a team.
Signing in gives each sandbox a verified identity, which lets Docker:

- **Tie sandboxes to a real person.** Governance matters when agents can build
  containers, install packages, and push code. Your Docker identity is the
  anchor.
- **Enable team features.** Team-scale features like
  [organization governance](governance/), shared environments, and audit logs
  need a concept of "who," and adding that later would be worse for everyone.
- **Authenticate against Docker infrastructure.** Sandboxes pull images, run
  daemons, and talk to Docker services. A Docker account authenticates those
  requests.

Your Docker account email is only used for authentication, not marketing.

## Can I enforce sandbox policies across my organization?

Yes. Admins can centrally manage network, filesystem, and MCP policies. These
controls apply to every sandbox in the organization. When organization
governance is active, only organization allow rules grant access: local allow
rules set with `sbx policy` are no longer evaluated, while local deny rules
still apply on top.

See [Organization policies](governance/access-controls/organization.md). This
feature requires a separate paid subscription —
[contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
to get started.

## Which domains do I need to allow for Docker Sandboxes to work?

If your organization restricts outbound network access with a firewall or
proxy, add the following domains to your allowlist so that `sbx` can
authenticate, pull images, and report diagnostics.

| Domain                                             | Description             |
| -------------------------------------------------- | ----------------------- |
| https://login.docker.com                           | Authentication          |
| https://hub.docker.com                             | Docker Hub              |
| https://api.docker.com                             | Docker API              |
| https://marlin-2.docker.com                        | Telemetry               |
| https://marlin-api.docker.com                      | Telemetry               |
| https://registry-1.docker.io                       | Docker pull/push        |
| https://auth.docker.io                             | Registry authentication |
| https://dhi.io                                     | Docker Hardened Images  |
| https://sbx-diagnostics.s3.us-east-1.amazonaws.com | Diagnostics upload      |

## Does the CLI collect telemetry?

The `sbx` CLI collects basic usage data about CLI invocations:

- Which command you ran
- Whether it succeeded or failed
- How long it took
- If you're signed in, your Docker username is included

Docker Sandboxes doesn't monitor sessions, read your prompts, or access your
code. Your code stays in the sandbox and on your host.

To opt out of all analytics, set the `SBX_NO_TELEMETRY` environment variable:

```console
$ export SBX_NO_TELEMETRY=1
```

## How do I set custom environment variables inside a sandbox?

Starting with `sbx` version 0.39.0, use `-e`/`--env` or `--env-file` with
`sbx run` and `sbx create`. See
[Set environment variables](usage.md#set-environment-variables) for syntax,
precedence rules, persistent configuration for an existing sandbox, and
guidance for credentials.

Variables in `/etc/sandbox-persistent.sh` are available to interactive sessions
and agents started with `sbx run`. A variable only takes effect for sessions
and agents started after it's added. Restart a running agent, or stop and start
the sandbox, to pick up the new value.

## Why do agents run without approval prompts?

The sandbox itself is the safety boundary. Because agents run inside an
isolated microVM with [network policies](governance/access-controls/network.md),
[credential isolation](security/isolation.md#credential-isolation), and no access to your host
system outside explicitly shared paths, the usual reasons for approval prompts
(preventing destructive commands, network access, file modifications) are
handled by the sandbox isolation layers instead.

If you prefer to re-enable approval prompts, change the permission mode
inside the session. Most agents let you switch permission modes after
startup. In Claude Code, use the `/permissions` command to change the mode
interactively.

To make approval prompts the default for every session, define a custom
sandbox kit that overrides the agent's entrypoint to drop the
permission-skipping flag. For example, a kit that launches Claude Code
without `--dangerously-skip-permissions`:

```yaml {title="claude-safe/spec.yaml"}
schemaVersion: "1"
kind: sandbox
name: claude-safe
sandbox:
  image: "docker/sandbox-templates:claude-code-docker"
  entrypoint:
    run: [claude]
```

Run it with `sbx run ./claude-safe/`. See
[Sandbox kits](customize/kits.md#sandbox-kits) for the full pattern.

## How do I know if my agent is running in a sandbox?

Ask the agent. The agent can see whether or not it's running inside a sandbox.
In Claude Code, use the `/btw` slash command to ask without interrupting an
in-progress task:

```text
/btw are you running in a sandbox?
```

## Why doesn't the sandbox use my user-level agent configuration?

Sandboxes don't import your complete user-level agent configuration. Hooks,
settings, and other files under directories such as `~/.claude` remain on the
host. Project-level configuration in the working directory remains available
inside the sandbox.

Shared agent skills are the exception. Use `sbx skills add` to install skills
from a Git repository, or run `sbx skills import` to copy skills from supported
host directories. `sbx` keeps the skills in a persistent store shared with
sandboxes. See [Share agent skills](workflows/agent-skills.md) for repository
management, supported host directories, mount behavior, and per-sandbox
opt-out.

Keep project-specific skills and other agent configuration in the project
itself. This versions the configuration alongside the code. Don't use symlinks
to host paths because a sandboxed agent can't follow them outside the sandbox.

## Can I paste images into an agent?

Yes, but it's off by default. Text paste already works, because the terminal
sends it directly. Pasting an image or screenshot with `Ctrl+V` is different:
the agent reads it from your host clipboard, and the sandbox blocks that access
unless you opt in.

Turn it on with a local setting:

```console
$ sbx settings set clipboard.imagePaste true
```

`Ctrl+V` then pastes host images into agents that read the clipboard, including
Claude Code and Codex. The setting takes effect within a few seconds, even for
running sandboxes.

This is opt-in because it relaxes the sandbox's isolation: when enabled, a process
inside the sandbox can read your host clipboard through the host-side proxy. The
exposure is narrow — reads happen only on a paste, return image data only
(`image/png`), and clipboard content is never cached or logged — but it's still
host data crossing into the sandbox, so it stays off until you turn it on.

To turn it back off:

```console
$ sbx settings set clipboard.imagePaste false
```

## Can I use Docker Sandboxes on headless Linux?

Yes. On Linux, `sbx` stores secrets in the Secret Service exposed by your
desktop keyring, such as GNOME Keyring or KDE Wallet. Headless servers and some
WSL setups have no running Secret Service, so `sbx` falls back to a file under
`$XDG_CONFIG_HOME/com.docker.sandboxes`, which defaults to
`~/.config/com.docker.sandboxes` when `$XDG_CONFIG_HOME` is unset. No setup is
required. When you store a secret on such a host, `sbx` prints a notice:

```text
No keychain detected - this secret will be stored on disk, protected by file permissions rather than a password
```

`sbx` stores the file in a directory with `0700` permissions, the same
file-permission model used for `~/.docker/config.json`. Any user or process that
can read the file can retrieve the stored credentials, so treat the directory as
sensitive. Where available, prefer a keychain, which mediates access per
application.

To keep secrets in a keyring instead, run a Secret Service on the host before
storing them: install `gnome-keyring` and start `dbus-run-session`, or run the
keyring daemon under a login session that unlocks it. Once a working Secret
Service is available, `sbx` stores new
secrets in the keychain again. For where each platform keeps secrets, see
[Where secrets are stored](configuration/credentials.md#where-secrets-are-stored).


---

# Get started with Docker Sandboxes

*Sección: Ai*

Docker Sandboxes run AI coding agents in isolated microVM sandboxes. Each
sandbox gets its own Docker daemon, filesystem, and network — the agent can
build containers, install packages, and modify files without accessing host
resources beyond those you share.

This page walks through your first session: run an agent in a sandbox, see how
the sandbox isolates it, control what it can reach on the network, and clean
up.

## Prerequisites

- [Install the `sbx` CLI](install.md) and sign in to Docker
- Configure an authentication method for the agent you want to use. Most agents
  require an API key for their model provider. See the [agent pages](agents/)
  for provider-specific instructions.

## Authenticate your agent

For Claude Code with a Claude subscription (Max, Team, or Enterprise), no
upfront setup is needed — use the `/login` command inside the sandbox to sign
in with OAuth. The session token stays on your host and is never stored inside
the sandbox.

If you prefer to authenticate with an API key, see
[Credentials](configuration/credentials.md) for how to store one with
`sbx secret set`.

To give the agent access to GitHub for creating pull requests or interacting
with repositories:

```console
$ sbx secret set github --command 'gh auth token'
```

## Run your first sandbox

Pick a project directory and launch an agent with
[`sbx run`](/reference/cli/sbx/run/):

```console
$ cd ~/my-project
$ sbx run --name my-sandbox claude
```

The first time you run a sandbox, the CLI prompts you to choose a default
network preset:

```plaintext
Initialize the global network policy for your sandboxes:

  Applies to all sandboxes, current and future — change it later with
  "sbx policy allow/deny/rm". Kits, including built-in agent kits, may
  also add per-sandbox rules.

     1. Open         — All network traffic allowed, no restrictions.
  ❯  2. Balanced     — Default deny, with common dev sites allowed.
     3. Locked Down  — All network traffic blocked unless you allow it.

  Use ↑/↓ or 1–3 to navigate, Enter to confirm, Esc to cancel.
```

**Balanced** is a good starting point — it permits traffic to common
development services while blocking everything else. You can adjust individual
rules later. See [Local policy](governance/access-controls/local.md) for a full
description of each option.

Replace `claude` with the agent you want to use — see [Agents](agents/) for the
full list.

The first run takes a little longer while the agent image is pulled. Subsequent
runs reuse the cached image and start in seconds.

This attaches you to the agent running inside the sandbox. Give it a real
task — ask it to add a feature, install a dependency, or build and run your
project. The agent has a full Linux environment with its own Docker daemon, so
it can install packages, build images, and start containers on its own while it
works.

## See what the agent can touch

From another terminal, list your sandboxes:

```console
$ sbx ls
SANDBOX       AGENT    STATUS    PORTS   WORKSPACE
my-sandbox    claude   running           ~/my-project
```

Each row shows a sandbox's name, the agent running in it, its status, any
[published ports](usage.md#publish-ports), and its
workspace — the host directory shared into the sandbox. That workspace is the
one part of your machine the agent can see.

When you run `sbx run` from a project directory without passing a workspace
path, the current directory is mounted read-write. The agent and your host see
the same files. Edits the agent makes to your project appear in your working
tree as it writes them, and you review them as an ordinary Git diff before
committing.

Everything else runs inside the microVM, isolated from your host:

- The agent has its own filesystem, Docker daemon, and network.
- Packages it installs, images it pulls, and containers it starts stay inside
  the sandbox. Your host system is untouched, and removing the sandbox discards
  them.

If you'd rather the agent not touch your working tree at all — for example,
when running several agents on one repository — use
[clone mode](usage.md#clone-mode), which gives it a private clone instead.

## Control what the agent can reach

Isolation isn't only about the filesystem. You also control what the sandbox
can reach on the network. You chose a default policy before the sandbox
started, and you can inspect or adjust it at any time.

Check which rules are in effect:

```console
$ sbx policy ls
```

To allow a specific host:

```console
$ sbx policy allow network registry.npmjs.org
```

With **Locked Down**, even your model provider API is blocked unless you
explicitly allow it. With **Balanced**, common development services are
permitted by default. See
[local policy](governance/access-controls/local.md) for the full rule set
and how to customize it.

## Clean up

Sandboxes persist after the agent exits, so you can stop one and pick up where
you left off later:

```console
$ sbx stop my-sandbox
```

Installed packages, Docker images, and configuration changes are preserved
across restarts. When you're done with a sandbox, remove it to reclaim disk
space:

```console
$ sbx rm my-sandbox
```

Removing a sandbox deletes everything inside it — installed packages, Docker
images, and the in-sandbox Git clone if you used clone mode. Files in your
host working tree are unaffected.

## What's next

You've run an agent, seen how the sandbox isolates it, and controlled its
network access. A few directions from here.

Run `sbx` with no arguments to open the interactive dashboard: a live view of
every sandbox where you can attach to agents, open shells, and manage network
rules from one place.

![The interactive dashboard showing sandbox status, resource usage, and network governance controls.](images/sbx-dashboard.png)

Then explore:

- [Usage guide](usage.md) — basic commands, reconnecting, workspaces, and port
  publishing.
- [Workflow patterns](workflows/) — Git strategies, local services, CI, and
  authenticated tools.
- [Sandbox environment files](configuration/environment-files.md) — declare and share
  repeatable local sandbox configurations with `sbxenv.yaml`.
- [Customize with kits](customize/) — package an agent, its tools, and its
  network rules into a reusable definition you launch with a single flag.
- [Agents](agents/) — the full list of supported agents and how to configure
  each one.
- [Governance](governance/) — centrally manage network, filesystem, and MCP
  policies across a team.


---

# Governance

*Sección: Ai*

Sandbox governance covers the policy system that controls what sandboxes can
access over the network, on the filesystem, and through MCP. For MCP setup and
server registration, see [MCP gateway](../mcp-gateway.md). Governance operates
at two layers:

**Local policy** is configured per machine using the `sbx policy` CLI. It
lets individual developers customize which domains their sandboxes can reach.
See [Local policy](access-controls/local.md).

**Organization policy** is configured centrally in Docker Home. Network and
filesystem policies can also be managed via the
[Governance API](/reference/api/ai-governance/). Controls defined at the org
level apply uniformly across every sandbox in the organization. Organization
governance can also include MCP policies for sandbox MCP activity. When
organization governance is active, only organization allow rules grant access:
local `sbx policy` allow rules are no longer evaluated, while local deny rules
still apply on top. See
[Organization policies](access-controls/organization.md).

Alongside this access-control policy, admins can require developers to sign in
as members of their organization before using sandboxes at all.
[Sign-in enforcement](monitor-and-enforce/sign-in-enforcement.md) is deployed
through endpoint management and ensures developers can't bypass organization
policy by using a personal account.

> [!NOTE]
> Organization governance is available on a separate paid subscription.
> [Contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
> to request access.

## Learn more

Start with [Policy concepts](concepts.md) for the resource model, rule syntax,
MCP policy basics, evaluation, and precedence.

### Access controls

- [Local policy](access-controls/local.md): configure network rules on your
  machine with the `sbx policy` CLI.
- [Organization policies](access-controls/organization.md): centrally manage
  sandbox policies across your organization.
- [Network access policies](access-controls/network.md): control outbound network
  access from sandboxes.
- [Filesystem access policies](access-controls/filesystem.md): control which
  host paths sandboxes can mount as workspaces.
- [MCP access policies](access-controls/mcp.md): control MCP server registration,
  tool calls, resources, prompts, and approval gates.

### Monitor and enforce

- [Monitoring policies](monitor-and-enforce/monitoring.md): inspect active
  rules and monitor sandbox network traffic with `sbx policy ls` and
  `sbx policy log`.
- [Audit logs](audit/): view, configure, export, and collect governance audit
  records.
- [Sign-in enforcement](monitor-and-enforce/sign-in-enforcement.md): require
  developers to sign in as organization members, enforced through endpoint
  management.

### Reference

- [AI Governance API](/reference/api/ai-governance/): manage network and
  filesystem org policies programmatically.
- [MCP policy reference](reference/mcp-policy.md): look up Docker MCP policy
  actions, resources, attributes, context fields, and approval behavior.


---

# Access controls

*Sección: Ai*

Access controls are expressed as policies. Local and organization pages
describe where policies apply. Network and filesystem pages describe the rules
inside those policies. MCP policies use Cedar statements instead of the network
and filesystem rule format.

## Policy scope

- [Local policy](local.md): configure network rules on a developer machine with
  the `sbx policy` CLI.
- [Organization policies](organization.md): manage centralized policies for an
  organization or team.

## Access surfaces

- [Network access policies](network.md): control outbound network access from
  sandboxes.
- [Filesystem access policies](filesystem.md): control which host paths
  sandboxes can mount as workspaces.
- [MCP access policies](mcp.md): control MCP server registration, tool calls,
  resources, prompts, and approval gates with Cedar policy.


---

# Filesystem access policies

*Sección: Ai*

Filesystem access policies control which host paths a sandbox can mount as a
workspace. Each policy contains one or more rules that restrict sandbox
workspaces to approved directories.

Filesystem access is managed with [organization policies](organization.md). When
organization governance is active, organization rules determine which paths a
sandbox can mount, and the local filesystem allow rules from the default preset
become inactive. `sbx policy deny` applies to network access only, so there are
no local filesystem deny rules to layer on top. See
[Precedence](../concepts.md#precedence).

## Rule syntax

Filesystem rules use the actions `read` and `write`. Resources are host path
patterns.

A writable workspace mount must be allowed by both a `read` rule and a `write`
rule. A read-only workspace needs only `read`.

Examples:

- `~/**`
- `/data/project/**`
- `C:\data\project\**`
- `\\wsl.localhost\<distro>\data\project\**`

Use `**` to match a directory tree recursively. A single `*` matches only one
path segment. For exact path matching behavior across macOS, Linux, Windows,
and WSL, see [Filesystem rules](../concepts.md#filesystem-rules).

## Organization filesystem rules

Organization filesystem rules belong to policies that can apply to the whole
organization or to selected teams. For setup steps and team scoping, see
[Organization policies](organization.md).

Filesystem policy is checked when a workspace is mounted, which happens when a
sandbox is created. To apply a filesystem policy change to a running workflow,
remove the sandbox and create a new one.

## Troubleshooting

### Sandbox cannot mount workspace

If a sandbox fails to mount with a `mount policy denied` error, verify that the
filesystem allow rule uses `**` rather than `*`. A single `*` doesn't match
across directory separators.


---

# Local policy

*Sección: Ai*

The `sbx policy` command manages the local policy on your machine. The local
policy contains network access rules. Rules apply to all sandboxes on the
machine when you use the global scope, or to a single sandbox when scoped by
name.

Local policy interacts with organization governance as follows:

- **No org governance**: the local policy controls what sandboxes can access.
- **Org governance active**: only organization allow rules grant access, so
  local allow rules are inactive and can't expand what the organization permits.
  Local deny rules are still evaluated, so you can restrict access further than
  the organization policy does. To list inactive rules, run
  `sbx policy ls --include-inactive`. See
  [Monitoring](../monitor-and-enforce/monitoring.md#showing-inactive-rules).

See [Organization policies](organization.md) for how organization governance
works.

For domain patterns, wildcards, CIDR ranges, and filesystem path syntax, see
[Policy concepts](../concepts.md#rule-syntax).

## Default preset

Outbound TCP traffic passes through a proxy on your host, which enforces access
rules on every connection. Non-HTTP TCP traffic, including SSH, can be allowed
with a hostname rule (for example, `sbx policy allow network "myhost:22"`) or an
address-based rule. UDP and ICMP are blocked at the network layer and can't be
unblocked with policy rules.

If you haven't chosen a default preset, the CLI prompts you before it runs a
sandbox. Running `sbx policy reset` clears the preset and prompts you to choose
again:

```plaintext
Initialize the global network policy for your sandboxes:

  Applies to all sandboxes, current and future — change it later with
  "sbx policy allow/deny/rm". Kits, including built-in agent kits, may
  also add per-sandbox rules.

     1. Open         — All network traffic allowed, no restrictions.
  ❯  2. Balanced     — Default deny, with common dev sites allowed.
     3. Locked Down  — All network traffic blocked unless you allow it.

  Use ↑/↓ or 1–3 to navigate, Enter to confirm, Esc to cancel.
```

| Preset      | Description                                                                                                                                       |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| Open        | All outbound traffic is allowed. Equivalent to adding a wildcard allow rule with `sbx policy allow network "**"`.                                 |
| Balanced    | Default deny, with a baseline allowlist covering AI provider APIs, package managers, code hosts, container registries, and common cloud services. |
| Locked Down | All outbound traffic is blocked, including model provider APIs (for example, `api.anthropic.com`). You must explicitly allow everything you need. |

The **Balanced** preset's baseline allowlist is a good starting point for most
workflows. Run `sbx policy ls` to see exactly which rules it includes. As of
v0.35.0, the Balanced preset also allows VS Code domains, Azure Blob Storage
(`*.blob.core.windows.net`), and `dhi.io` over HTTP.

> [!NOTE]
> If your organization manages sandbox policies centrally, organization rules
> take precedence over the preset you select here. See
> [Organization policies](organization.md).

### Non-interactive environments

In non-interactive environments such as CI pipelines or headless servers, the
interactive prompt can't be displayed. Use `sbx policy init` to set the
preset before running any other `sbx` commands:

```console
$ sbx policy init balanced
```

Available values are `allow-all`, `balanced`, and `deny-all`.

## Managing rules

Use [`sbx policy allow`](/reference/cli/sbx/policy/allow/) and
[`sbx policy deny`](/reference/cli/sbx/policy/deny/) to add or restrict access
on top of the active preset. Changes take effect immediately. Rules apply to
all sandboxes by default:

```console
$ sbx policy allow network api.anthropic.com
$ sbx policy deny network ads.example.com
```

Pass `--sandbox <name>` to scope a rule to one sandbox:

```console
$ sbx policy allow network --sandbox my-sandbox api.example.com
$ sbx policy deny network --sandbox my-sandbox ads.example.com
```

As of v0.38.0, you can also set per-sandbox deny rules at creation time with
`--deny-network` on `sbx create` or `sbx run`, instead of adding them after the
fact:

```console
$ sbx create --deny-network ads.example.com claude .
$ sbx run --deny-network ads.example.com claude
```

Pass the flag multiple times to deny more than one host. Rules added this way
appear in `sbx policy ls <name>` and can be removed with
`sbx policy rm network --sandbox <name> --resource <host>`.

Specify multiple hosts in one command with a comma-separated list:

```console
$ sbx policy allow network "api.anthropic.com,*.npmjs.org,*.pypi.org"
```

Remove a rule by resource or by rule ID:

```console
$ sbx policy rm network --resource ads.example.com
$ sbx policy rm network --id 2d3c1f0e-4a73-4e05-bc9d-f2f9a4b50d67
```

To remove a sandbox-scoped rule, pass `--sandbox <name>`:

```console
$ sbx policy rm network --sandbox my-sandbox --resource api.example.com
```

To inspect which policies are active and where they come from, use
`sbx policy ls`. Use `--source` to filter by origin (`local`, `org`, `kit`),
`--decision` to filter by outcome (`allow`, `deny`), and `--wide` for
rule-level detail including rule IDs. To inspect a single policy or rule in
full, use `sbx policy inspect`. See
[Monitoring](../monitor-and-enforce/monitoring.md).

## Testing policy

Before running a sandbox, you can check whether the current policy would allow
a network request with `sbx policy check network`:

```console
$ sbx policy check network api.anthropic.com
Allowed: api.anthropic.com

$ sbx policy check network blocked.example.com
Denied: blocked.example.com
```

The target can be a hostname, a `host:port` pair, an IP address, or a URL.
Bare hostnames and IP addresses are evaluated against port 443. This is useful
for verifying custom rules or checking what the Locked Down preset blocks
before you start an agent.

To check policy in the context of a specific sandbox:

```console
$ sbx policy check network --sandbox my-sandbox api.example.com
```

### Resetting

To remove all custom rules and start fresh with a new preset, use
`sbx policy reset`:

```console
$ sbx policy reset
```

This deletes the local policy store, restarts the daemon, and prompts you to
choose a new preset. Running sandboxes stop when the daemon shuts down. Pass
`--force` to skip the confirmation prompt:

```console
$ sbx policy reset --force
```

## Troubleshooting

### Local allow rules have no effect

If rules you add with `sbx policy allow` don't change sandbox behavior, your
organization likely has governance enabled. Run `sbx policy ls` to check: if
the output starts with a `Governance:` status line showing `Managed by <org>`,
org governance is active. When it's active, local allow rules are inactive.
You can't use them to loosen restrictions the org policy imposes.

Inactive allow rules are hidden from `sbx policy ls` by default; run
`sbx policy ls --include-inactive` to see them with an `inactive` status in
the `STATUS` column.

When organization governance is active, only organization allow rules can grant
access. Ask your admin to update the organization policy if you need access to
an additional resource. Local deny rules remain active, so you can use
`sbx policy deny` to restrict access further.

### A domain is still blocked after adding an allow rule

If a domain remains blocked after you add a local allow rule, your organization
likely enforces governance, which makes local allow rules inactive. Run `sbx
policy ls` to check whether org governance is active; if the output starts with
a `Governance:` status line showing `Managed by <org>`, it is. Add
`--include-inactive` to confirm your rule shows an `inactive` status. If so,
the block can only be lifted by updating the org policy in Docker Home or via
the [API](/reference/api/ai-governance/).


---

# MCP access policies

*Sección: Ai*

MCP access policies let organization administrators control which Model
Context Protocol (MCP) servers developers can register and what agents can do
through Docker's MCP gateway. Use these policies to approve trusted servers,
withdraw access to a server, require approval for tool calls, and restrict
host-run servers. To register MCP servers and connect them to sandboxes, see
[MCP gateway](../../mcp-gateway.md).

MCP access policies apply only to server registration and requests handled by
Docker's MCP gateway. They don't govern an MCP server that an agent or MCP
client configures and connects to directly from inside the sandbox. A direct
connection to a remote MCP server is outbound sandbox traffic, so
[network access policy](network.md) determines whether the sandbox can reach
the server. To prevent access through both paths, block the server in MCP
access policy and block its network destination in network access policy.

Unlike [network access policies](network.md) and
[filesystem access policies](filesystem.md), MCP policies are organization
policies written in Cedar. Docker defines the `MCP` namespace, including the
actions, resource types, attributes, and approval behavior that policies can
match. This page focuses on representative access patterns. For Docker's exact
policy surface, see the [MCP policy reference](../reference/mcp-policy.md). For
Cedar syntax and language semantics, see the
[Cedar documentation](https://docs.cedarpolicy.com/).

## Govern the server lifecycle

MCP policy applies at two points in a server's lifecycle. A rule for one point
doesn't automatically govern the other.

| Admin decision                             | Evaluation point                            | Match with                                                                 |
| ------------------------------------------ | ------------------------------------------- | -------------------------------------------------------------------------- |
| Whether a server can be registered         | When a developer runs `sbx mcp add`         | The registered name and resolved server attributes, such as `identityURL`  |
| What agents can do through the MCP gateway | When the gateway handles a governed request | The registered server name, tool annotations, resource URI, or prompt name |

Registration rules affect future registrations. They don't remove a saved
registration or prevent an existing registration from being loaded with
`sbx mcp load`. Use-time rules govern tool calls, resource reads, and prompt
retrieval from servers that are already registered or loaded.

Server names are chosen during registration. Registration rules can match the
chosen name and resolved server identity together. At use time, tools,
resources, and prompts are associated with the registered name, so rules for an
existing server must match every name under which it was registered.

Built-in gateway tools, such as `mcp-add`, `code-mode`, and OAuth authorization
helpers, are also governed at use time. They are `MCP::Primordial` resources
rather than tools associated with a registered server. For details, see
[Built-in gateway tools](../../mcp-gateway.md#built-in-gateway-tools).

Use-time policy doesn't hide or remove existing registrations. Tool and
resource listings can also include entries that policy denies when an agent
tries to use them.

## Choose an access posture

When MCP policy enforcement is active for a user, registration and governed MCP
requests are denied unless a matching `permit` allows them. A matching `forbid`
overrides any `permit`, including a permit with `@requireApproval`.

Use permits for an allowlist policy. For a blocklist policy that grants MCP
activity except for explicit restrictions, start with an actionless permit:

```plaintext
permit (principal, action, resource);
```

This statement permits every MCP action that reaches Cedar evaluation. Add
`forbid` statements for the restrictions the policy must enforce.

Policy scope supplies the principal. Use organization or team scope instead of
matching users, teams, tenants, or roles in Cedar. If MCP policy enforcement
isn't active for a user, the gateway doesn't evaluate Cedar policy and permits
MCP activity. MCP doesn't have a local preset equivalent to network policy.

## Approve a server

For an allowlist, approve both the server registration and its use-time
capabilities. The following policy approves a remote server only when it is
registered as `example` with the expected identity URL. It permits read-only
tool calls, resource reads, and prompt retrieval from that registered server:

```plaintext
// Permit registration with the expected name and identity URL.
permit (principal, action == MCP::Action::"register", resource)
when {
  resource in MCP::Server::"example" &&
  resource.identityURL == "https://mcp.example.com/mcp"
};

// Permit read-only tool calls.
permit (principal, action == MCP::Action::"invokeTool", resource)
when {
  resource in MCP::Server::"example" &&
  resource.readOnly == true
};

// Permit resource reads.
permit (principal, action == MCP::Action::"readResource", resource)
when { resource in MCP::Server::"example" };

// Permit prompt retrieval.
permit (principal, action == MCP::Action::"getPrompt", resource)
when { resource in MCP::Server::"example" };
```

Matching both the name and identity URL establishes a canonical registration.
It prevents a developer from registering another endpoint under the approved
name or registering the approved endpoint under another name. Remove the
resource or prompt permit if users don't need that capability.

## Require confirmation with MCP elicitation

Use `@requireApproval` to require per-request confirmation through MCP. When a
request matches the annotated `permit`, the gateway sends an
`elicitation/create` request to the same MCP client session that made the
governed request. In a human-driven client, the person operating the agent sees
the prompt and decides whether to proceed.

The following policy requires confirmation for non-read-only tools on a server
registered as `example`. Use it alongside any permits needed to register the
server or use its other capabilities. The annotation string becomes the reason
shown in the elicitation:

```plaintext
@requireApproval("non-read-only tool call")
permit (principal, action == MCP::Action::"invokeTool", resource)
when {
  resource in MCP::Server::"example" &&
  resource.readOnly == false
};
```

Tool annotations are supplied by the server and are advisory. `readOnly`
defaults to `false` for tools that don't declare it, so this pattern requires
confirmation for unannotated tools.

The gateway handles a matching request as follows:

```mermaid
flowchart TD
  request["Agent sends a governed MCP request"] --> evaluate["Gateway evaluates MCP policy"]
  evaluate -->|"Normal permit"| forward["Forward request"]
  evaluate -->|"No permit or matching forbid"| deny["Deny request"]
  evaluate -->|"Permit with @requireApproval"| elicit["Send MCP elicitation to connected client"]
  elicit --> confirm{"Client returns explicit confirmation?"}
  confirm -->|"No, unsupported, or error"| deny
  confirm -->|"Yes"| reevaluate["Re-evaluate with approval digest"]
  reevaluate -->|"Allowed"| forward
  reevaluate -->|"Denied or changed"| deny
```

The prompt identifies the server or gateway tool and includes the annotation
reason. It doesn't include raw tool arguments. Each matching request requires a
new confirmation. After confirmation, the gateway re-evaluates the request with
a digest that binds the response to the evaluated authorization request.

Use this mechanism as a confirmation guardrail for human-driven clients. It
doesn't create administrator approval or separation of duties. An autonomous
MCP client can respond to an in-protocol elicitation programmatically. Use
`forbid` for operations that must never run.

The request is denied if the originating client session can't handle MCP
elicitation, the user declines, the elicitation fails, or re-evaluation doesn't
allow the request. `sbx mcp add` can't present an elicitation, so a registration
permit with `@requireApproval` results in a denial. Tool calls made from an
execution context that can't relay an elicitation, including calls from inside
`code-mode`, are also denied.

## Withdraw server access

To withdraw access from a server that broader rules permit, block it at
registration and at use time. Registration policy controls future `sbx mcp add`
operations, while use-time policy controls requests from servers that are
already registered or loaded.

Prevent future registrations of the server by matching its identity URL:

```plaintext
forbid (principal, action == MCP::Action::"register", resource)
when { resource.identityURL == "https://mcp.example.com/mcp" };
```

Deny use-time requests for each registered name that refers to the server:

```plaintext
forbid (principal, action == MCP::Action::"invokeTool", resource)
when { resource in MCP::Server::"example" };

forbid (principal, action == MCP::Action::"readResource", resource)
when { resource in MCP::Server::"example" };

forbid (principal, action == MCP::Action::"getPrompt", resource)
when { resource in MCP::Server::"example" };
```

The registration remains saved and can still be listed or loaded. These rules
prevent another registration for the identity URL and deny governed use under
the registered name. If the server was registered under other names, add
use-time rules for those names as well.

An OAuth authorization helper is a built-in gateway tool, not a child of the
registered server. To prevent agents from starting authorization for the
server, govern the helper separately:

```plaintext
forbid (principal, action == MCP::Action::"invokePrimordial", resource)
when { resource in MCP::Primordial::"example-authorize" };
```

## Restrict host-run servers

Local stdio servers run on the host, outside the sandbox VM. This includes
explicit host commands and OCI-packaged stdio servers started with host Docker.
For details about this boundary, see
[Docker Engine isolation](../../security/isolation.md#docker-engine-isolation).

In a blocklist policy that otherwise permits registration, deny the host-run
server type:

```plaintext
forbid (principal, action == MCP::Action::"register", resource)
when { resource.type == "local-stdio" };
```

`local-stdio` covers explicit commands, including commands that start a Docker
container, and OCI-packaged stdio servers resolved from registry or manifest
metadata with `--local`.

## Related information

- [MCP policy concepts](../concepts.md#mcp-policies): policy model and rule
  evaluation.
- [MCP policy reference](../reference/mcp-policy.md): exact action, resource,
  attribute, context, and approval behavior.
- [Organization policies](organization.md): policy creation and scope.
- [MCP policy audit logs](../audit/): policy decision
  records.


---

# Network access policies

*Sección: Ai*

Network access policies control outbound connections from sandboxes. Each
policy contains one or more rules that allow the domains, IP ranges, and ports a
workflow needs, or block destinations that should stay unavailable.

You can configure network access in two places:

- [Local policy](local.md), which applies to sandboxes on one developer machine
  when organization governance is not active.
- [Organization policies](organization.md), which apply centrally across an
  organization or to selected teams.

When organization governance is active, only organization allow rules grant
network access. Local allow rules are inactive until organization governance no
longer applies, while local deny rules still apply on top of the organization
policy. See [Precedence](../concepts.md#precedence).

## Rule syntax

Network rules use the action `connect:tcp`. Resources are hostnames, CIDR
ranges, ports, or hostnames with ports. The governance policy schema also
accepts `connect:udp`, but Docker Sandboxes always blocks direct external UDP
and ICMP. `connect:udp` rules have no effect.

Examples:

- `api.example.com`
- `*.example.com`
- `**.example.com`
- `example.com:443`
- `10.0.0.0/8`

For exact wildcard behavior and CIDR support, see
[Network rules](../concepts.md#network-rules).

## Local network rules

Use `sbx policy allow network` and `sbx policy deny network` to manage local
network rules:

```console
$ sbx policy allow network api.example.com
$ sbx policy deny network ads.example.com
```

For presets, sandbox-scoped rules, testing, and troubleshooting, see
[Local policy](local.md).

## Organization network rules

Organization network rules belong to policies that can apply to the whole
organization or to selected teams. For setup steps and team scoping, see
[Organization policies](organization.md).

Use [Monitoring policies](../monitor-and-enforce/monitoring.md) to inspect
which network rules are active on a developer machine.

> [!NOTE]
> To manage Model Context Protocol (MCP) server registration and requests
> through Docker's MCP gateway, use [MCP access policies](mcp.md). These
> policies apply only to the gateway. Direct MCP connections from a sandbox
> don't use the gateway, but you can control access to remote MCP servers with
> network policy.


---

# Organization policies

*Sección: Ai*

[Local policies](local.md) give individual developers control over what their
sandboxes can access. Organization policy moves that control to the admin level:
organization policies apply to sandboxes across the organization, either to
every member or to specific teams. When organization governance is active, only
organization allow rules grant access: local `sbx policy` allow rules are no
longer evaluated and can't expand what the organization permits. Local network
deny rules remain active, so developers can restrict access further but never
loosen it.

Admins can manage organization policies through the Docker Home UI. For
programmatic management of network and filesystem policies, use the
[Governance API](/reference/api/ai-governance/).

By default, only organization
[owners](../../../../security/roles-and-permissions/core-roles.md) can
view and manage AI Governance policies. To let someone other than an owner
manage policies, create a
[custom role](../../../../security/roles-and-permissions/custom-roles/index.md)
with the **Governance** permissions and assign it to a user or team.

> [!NOTE]
> Sandbox organization governance is available on a separate paid
> subscription.
> [Contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
> to request access.

## Create a policy

Manage policies from the **AI Platform** section in the left-hand navigation
of [Docker Home](https://app.docker.com).

To create a policy:

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization.
1. In the left-hand navigation, expand **AI Platform** and select
   **Network access**, **Filesystem access**, or **MCP access**.
1. Select **Create policy**.
1. Enter a **Policy name**.
1. Set the **Scope** to **Organization** or **Teams**. If you select **Teams**,
   choose the teams the policy applies to. See
   [Scope policies to teams](#scope-policies-to-teams).
1. Define the policy rules. For network and filesystem policies, select
   **Add rule** for each rule. For MCP policies, enter Cedar statements in the
   policy editor. For syntax and examples, use the relevant access-control page
   in [Choose a policy type](#choose-a-policy-type).

Existing policies are listed with their name, scope, rule count, and last
update. Use the action menu (⋮) to edit or delete a policy.

## Configure a support message

Admins can add an optional support message that appears after the policy denial
details when a sandbox action is blocked by organization governance. Use it to
point members to an internal support channel, ticket queue, or security contact.

To set the message:

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization.
1. In the left-hand navigation, expand **AI Platform** and select **Manage**.
1. In **Support message**, enter up to 500 characters.
1. Select **Save changes**.

Docker shows the message only for denials caused by organization governance
policy. If you leave it blank, Docker shows the policy denial without additional
contact text.

## Choose a policy type

Organization policies are managed by access surface. Use the access-control
pages for syntax, examples, and enforcement details:

- [Network access policies](network.md): control outbound network access from
  sandboxes.
- [Filesystem access policies](filesystem.md): control which host paths
  sandboxes can mount as workspaces.
- [MCP access policies](mcp.md): control MCP server registration, tool calls,
  resources, prompts, and approval gates with Cedar policy.

When organization governance is active, local and kit-defined allow rules are
not evaluated, while deny rules from those sources still apply. See
[Precedence](../concepts.md#precedence). To see which rules are active on a
developer machine, use
[Monitoring policies](../monitor-and-enforce/monitoring.md).

## Scope policies to teams

An organization can have more than one policy, and each policy applies either
to the whole organization or to specific teams. Scoping lets you apply different
rules to different parts of the organization.

A policy's [**Scope**](#create-a-policy) controls who it applies to. Set it to
**Organization** to apply the policy to every member, or to **Teams** to apply
it only to members of the teams you select.

### Before you start

Team scoping targets your organization's existing
[teams](../../../../accounts/organization/manage/manage-a-team.md), so a team must
exist before you can scope a policy to it. Create teams and manage their members
in one of two ways:

- Manually, in Docker Home.
- Automatically, by using
  [group mapping](../../../../security/provisioning/scim/group-mapping.md)
  to synchronize your identity provider's groups with the teams in your
  organization. Group mapping creates teams that don't already exist and keeps
  their membership in step with your IdP groups.

Because policies apply by team, a user's policies update automatically as their
team membership changes, including changes synced from your IdP.

### How scoped policies combine

A user is governed by all of their
[effective policies](../concepts.md#policy-scope): every org-wide policy, plus
the team-scoped policies for the teams they belong to. Use org-wide policies
for guardrails that must apply everywhere, and team-scoped policies for access
that only some teams need.

For precedence between local and organization policies, and for how allow and
deny rules combine, see [Policy concepts](../concepts.md).

## Troubleshooting

### Policy changes not taking effect

After updating organization policies, changes take up to 5 minutes to
propagate to developer machines. To apply changes immediately, users can run
`sbx policy reset`, which stops the daemon and forces it to pull the latest
organization policies on the next `sbx` command.

> [!WARNING]
> `sbx policy reset` deletes all locally configured policy rules. The command
> prompts for confirmation before proceeding.

#### Enforcement timing by policy type

Policy types differ in when a change takes effect after it reaches the
developer machine:

- Network policy is evaluated on every outbound request. Once a policy
  change has synced to the developer's machine (up to 5 minutes), it applies
  immediately to subsequent requests.

- Filesystem policy is only checked when a workspace is mounted — that
  is, when a sandbox is created. Once a sandbox is running, changing the
  filesystem policy has no effect on that sandbox. The sandbox continues to
  access the previously allowed path until it is removed and a new one is
  created.

- MCP registration policy is evaluated when a server is registered with
  `sbx mcp add`. Changing registration rules doesn't remove existing
  registrations or stop an already-loaded server by itself.

- MCP use-time policy is evaluated by the MCP gateway when a sandbox makes a
  governed MCP request, such as a tool call, resource read, prompt retrieval,
  or built-in gateway tool call. Once a policy change has synced, use-time
  rules apply to subsequent governed MCP requests through the gateway.

To apply a filesystem policy change immediately, remove the running sandbox
and create a new one. To prevent use of an MCP server that is already registered
or loaded, add use-time rules for the registered server name. For examples, see
[Withdraw server access](mcp.md#withdraw-server-access).


---

# AI Governance Audit Logs

*Sección: Ai*

{{< summary-bar feature_name="AI Governance Audit Logs" >}}

AI Governance Audit Logs record Docker AI Governance activity for your
organization. Each record captures the principal, action, target, decision, and
time for a governance event. Records contain metadata only. They don't contain
prompt content, agent output, or parameter values.

Audit logs are exposed when AI Governance is enabled for your organization.
Docker Sandboxes send audit records only for signed-in users who have an AI
Governance license and are governed by an enforced centralized [organization
policy](../access-controls/organization.md). Docker Sandboxes users without both
don't send audit data to audit logs.

> [!NOTE]
> AI Governance Audit Logs are part of Docker AI Governance and require a
> separate paid subscription.
> [Contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
> to request access.

## Requirements

To use AI Governance Audit Logs, your organization needs:

- A Docker [AI Governance plan](../../../../subscription-billing/plans/ai-governance.md)
- An enforced organization governance policy
- A Docker organization account
- An organization owner, or a user with a [custom role](../../../../security/roles-and-permissions/custom-roles/index.md) that includes AI Governance audit permissions, to configure delivery and view hosted events

> [!NOTE]
> Other Docker subscriptions are not sufficient on their own to use AI Governance
> Audit Logs. Users without an AI Governance license and an enforced organization
> policy will not generate audit data and will not appear in audit events or SIEM
> forwarding output. Personal accounts are not supported.

## Coverage

AI Governance Audit Logs cover Docker Sandboxes policy decisions and sandbox
session events. Other Docker AI sources can emit records through the same schema
as they become available.

## Delivery modes

Docker supports two delivery modes for audit records:

- **Local disk**: the sandbox daemon writes JSON Lines (`.jsonl`)
  files on each host. Use this mode for host-local retention, air-gapped
  collection, or collection through your own log shipper.
- **Docker Cloud**: Docker stores audit records in Docker Cloud. Cloud
  delivery powers the hosted audit log view, CSV export, and SIEM streaming from
  app.docker.com. Cloud delivery is on by default when AI Governance is enabled.
  Organization owners can disable it in [audit delivery settings](configure.md).

Organization owners and users with a [custom role](../../../../security/roles-and-permissions/custom-roles/index.md) that includes AI Governance audit permissions can configure local disk, Docker Cloud, or both.

The hosted audit log view, CSV export, and SIEM forwarding all require Docker Cloud delivery to be enabled. Local delivery alone does not power these features.

Organizations that used local audit logging before hosted audit logs were
available start with cloud delivery off until an owner opts in from
[audit delivery settings](configure.md).

## Data handling

When Docker Cloud delivery is enabled, Docker stores audit records in Docker
Cloud for the retention window configured by your organization. For legal and
privacy terms that govern Docker services, see Docker's [Terms of
Service](https://www.docker.com/legal/docker-terms-service/) and [Privacy
Policy](https://www.docker.com/legal/privacy/).

## Learn more

- [Local audit logs](local.md)
- [Configure audit delivery](configure.md)
- [View and export audit events](view-export.md)
- [SIEM forwarding](siem.md)
- [Audit record reference](record-reference.md)


---

# Configure audit delivery

*Sección: Ai*

Organization owners and users with a [custom role](../../../../security/roles-and-permissions/custom-roles/index.md) that includes AI Governance audit permissions can configure where Docker writes audit events.
Two delivery destinations are available and can be used independently or
together:

- **Local disk**: The sandbox daemon writes audit events to the local disk
  on each host.
- **Docker Cloud**: Audit events are sent to Docker's cloud platform, enabling
  the hosted log view, CSV export, and SIEM forwarding.

## Before you begin

Your organization needs:

- A Docker [AI Governance plan](../../../../subscription-billing/plans/ai-governance.md)
- An enforced organization governance policy
- Organization owner access, or a [custom role](../../../../security/roles-and-permissions/custom-roles/index.md) with AI Governance audit permissions

Only users who have an AI Governance license and are governed by the enforced
organization policy send Docker Sandboxes audit data.

## Configure delivery

To configure audit delivery:

1. Sign in to [Docker Home](https://app.docker.com/).
2. Open your organization.
3. Go to **AI Platform** > **Audit logs**.
4. Open **Audit Delivery**.
5. Choose one or both delivery modes:
   - **Local disk** writes audit records to JSON Lines files on each host.
   - **Docker Cloud** stores audit records in Docker Cloud for hosted search,
     CSV export, and SIEM forwarding.
6. Save your changes.

Cloud delivery is on by default when AI Governance is enabled. To keep records
local to your hosts, turn off **Docker Cloud** and keep **Local disk** on.

Organizations that used local audit logging before hosted audit logs were
available start with cloud delivery off until an owner opts in.

## Configure retention

When **Docker Cloud** is selected, you can also configure how long cloud-stored
events are retained:

| Field                          | Description                                                        | Default |
| ------------------------------ | ------------------------------------------------------------------ | ------- |
| Searchable retention (days)    | How long events stay searchable in the hosted audit log view.      | 90 days |
| Archive retention (days)       | How long events are kept in long-term archive storage.             | 90 days |

Archive retention must be greater than or equal to searchable retention.

Retention reductions apply going forward. They don't delete records that were
already retained under a longer retention window.

## Audit delivery change history

Docker keeps a record of every change made to your organization's audit delivery
settings. Each entry captures the timestamp, the user who made the change, and
the delivery configuration that was set. Use this history to audit configuration
changes and verify when delivery modes or retention windows were modified.

Open **History** to review delivery and retention changes for your organization.
History entries show who made the change, when it happened, and the before and
after values.


---

# Local audit logs

*Sección: Ai*

The sandbox daemon writes local audit records as JSON Lines (`.jsonl`) files.
Local audit logs stay on the host that produced them and can be collected by
your own log shipper. Local delivery is independent of
[cloud delivery](configure.md), so you can use local files with cloud delivery
on or off.

The sandbox daemon writes local audit records only for signed-in users who have
an AI Governance license and are governed by an enforced centralized
[organization policy](../access-controls/organization.md). Docker Sandboxes
users without both do not send audit data to audit logs. To confirm governance
is active, run `sbx policy ls`. The output includes a `Governance: Managed by
<org>` line when an organization policy is in effect.

## What gets recorded

The daemon writes two categories of local record:

- Evaluation records capture each policy decision: the resource, the action,
  the verdict, and the reason for a denial.
- Session lifecycle records mark the start and end of each daemon run.
  Evaluation records share the run's `audit_session_id`, so you can correlate
  every decision back to a daemon session.

Records contain metadata only. They don't contain prompt content, agent output,
or parameter values. For field details, see
[Audit record reference](record-reference.md).

A network evaluation record looks like this:

```json
{
  "audit_event_id": "95e7257f-93c9-4f29-bde7-88830e2dae80",
  "timestamp": "2026-05-28T19:15:00.728933Z",
  "schema_version": "1.82.0",
  "category": "AUDIT_CATEGORY_EVALUATION",
  "decision": "AUDIT_DECISION_DENY",
  "username": "jordandoe",
  "user_email": "jordandoe@example.com",
  "org_id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
  "org_name": "Acme Inc",
  "audit_session_id": "8a3bc076-79d0-4502-baf3-cc6ad35fb578",
  "resource_id": "example.com:443",
  "os": "macos",
  "app_version": "v0.31.0",
  "client_name": "sbx",
  "hostname": "host-machine",
  "deny_reason": [
    "no applicable policies for op(action=net:connect:tcp, resource=net:domain:example.com:443)"
  ],
  "action_type": "network_egress",
  "network_egress": { "protocol": "tcp" },
  "agent": "claude"
}
```

## Where records are stored

The daemon writes audit records, not the CLI. Running a command such as
`sbx create` sends a request to the daemon, and the daemon emits the resulting
record to its own audit directory.

The default location depends on your operating system:

| OS      | Default path                                                      |
| ------- | ----------------------------------------------------------------- |
| macOS   | `~/Library/Logs/com.docker.sandboxes/sandboxes/auditkit/`         |
| Linux   | `${XDG_STATE_HOME:-~/.local/state}/sandboxes/sandboxes/auditkit/` |
| Windows | `%LOCALAPPDATA%\DockerSandboxes\sandboxes\logs\auditkit\`         |

The directory layout differs by platform because each operating system places
application logs in its own conventional location.

Files are named `audit-<utc-timestamp>-<process-uuid>-<seq>.jsonl`.

The daemon writes in-progress records to a temporary `.tmp` file and
finalizes it into a `.jsonl` file by atomic rename. Finalization happens at a
rotation threshold: by default, 5 minutes, 1000 events, or 50 MiB, whichever
comes first. Finalization also happens when the daemon shuts down cleanly. Only
`.jsonl` files are complete. Treat `.tmp` files as incomplete and don't collect
them.

Sandboxes never delete `.jsonl` files. Retention and cleanup are the
responsibility of your log shipper or your own housekeeping.

## Collect records with a SIEM

Point your log shipper at the audit directory and configure it to collect
`.jsonl` files only. Tools such as the Splunk Universal Forwarder,
Filebeat, and CrowdStrike Falcon LogScale read the directory and forward each
line as an event. Because in-progress records live in `.tmp` files until they
are finalized, collectors never see partial records.


---

# Audit record reference

*Sección: Ai*

Docker AI Governance audit records use one schema across delivery modes. Local
JSON Lines files and cloud-delivered records contain the same metadata fields.

Records capture metadata only. They don't contain prompt content, agent output,
or parameter values. Parameter keys may appear when they help identify an
action.

## Common fields

| Field              | Description                                                                                                      |
| ------------------ | ---------------------------------------------------------------------------------------------------------------- |
| `audit_event_id`   | Unique ID for the audit event.                                                                                   |
| `timestamp`        | UTC time when Docker recorded the event.                                                                         |
| `schema_version`   | Version of the record schema. Pin SIEM field mappings to this value.                                             |
| `category`         | Event category, such as `AUDIT_CATEGORY_MANAGEMENT`, `AUDIT_CATEGORY_EVALUATION`, or `AUDIT_CATEGORY_EXECUTION`. |
| `decision`         | Governance decision for evaluation records.                                                                      |
| `username`         | The signed-in Docker user's Docker Hub username.                                                                 |
| `user_email`       | The signed-in Docker user's email address.                                                                       |
| `org_id`           | ID of the organization whose governance policy is in effect.                                                     |
| `org_name`         | Display name of the organization whose governance policy is in effect.                                           |
| `audit_session_id` | Identifies the daemon session that produced the record.                                                          |
| `resource_id`      | Target of the evaluation, such as a host and port, file path, or tool.                                           |
| `os`               | Operating system that produced the record.                                                                       |
| `app_version`      | Version of the Docker component that produced the record.                                                        |
| `client_name`      | Source component, such as `sbx` for Docker Sandboxes.                                                            |
| `hostname`         | Hostname of the machine that produced the record.                                                                |
| `deny_reason`      | Why a denied request was blocked. Present on deny decisions.                                                     |
| `action_type`      | Payload discriminator that identifies the action-specific object in the record.                                  |
| `agent`            | AI agent associated with the event, when Docker knows it.                                                        |

## Categories

| Category                    | Description                                                   |
| --------------------------- | ------------------------------------------------------------- |
| `AUDIT_CATEGORY_MANAGEMENT` | Session lifecycle, policy sync, and configuration events.     |
| `AUDIT_CATEGORY_EVALUATION` | Governance policy decisions, such as allow, deny, or consent. |
| `AUDIT_CATEGORY_EXECUTION`  | Outcomes after an evaluated action runs.                      |

## Decisions

| Decision                           | Description                                    |
| ---------------------------------- | ---------------------------------------------- |
| `AUDIT_DECISION_ALLOW`             | Docker allowed the action.                     |
| `AUDIT_DECISION_DENY`              | Docker denied the action.                      |
| `AUDIT_DECISION_APPROVAL_REQUIRED` | Docker required consent before the action ran. |
| `AUDIT_DECISION_APPROVED`          | A consent request was approved.                |
| `AUDIT_DECISION_REJECTED`          | A consent request was rejected.                |

## Action types

The `action_type` field identifies the action-specific payload in the record.

| Action type            | Description                                  |
| ---------------------- | -------------------------------------------- |
| `session`              | Sandbox daemon session lifecycle event.      |
| `network_egress`       | Network access evaluation.                   |
| `filesystem_mount`     | Filesystem mount or path access evaluation.  |
| `tool_invocation`      | Tool invocation evaluation.                  |
| `resource_read`        | Resource read evaluation.                    |
| `server_registration`  | Server registration event.                   |
| `prompt`               | Prompt-related metadata event.               |
| `network_execution`    | Outcome of a network action.                 |
| `filesystem_execution` | Outcome of a filesystem action.              |
| `tool_execution`       | Outcome of a tool invocation.                |
| `resource_execution`   | Outcome of a resource read.                  |
| `policy_sync`          | Policy synchronization event.                |
| `pii_detection`        | Metadata event for a data detection result.  |
| `c_score_report`       | Metadata event for a C-score report.         |
| `policy_action`        | Policy configuration or policy action event. |

## Sample record

```json
{
  "audit_event_id": "95e7257f-93c9-4f29-bde7-88830e2dae80",
  "timestamp": "2026-05-28T19:15:00.728933Z",
  "schema_version": "1.82.0",
  "category": "AUDIT_CATEGORY_EVALUATION",
  "decision": "AUDIT_DECISION_DENY",
  "username": "jordandoe",
  "user_email": "jordandoe@example.com",
  "org_id": "9f8e7d6c-5b4a-3210-fedc-ba9876543210",
  "org_name": "Acme Inc",
  "audit_session_id": "8a3bc076-79d0-4502-baf3-cc6ad35fb578",
  "resource_id": "example.com:443",
  "os": "macos",
  "app_version": "v0.31.0",
  "client_name": "sbx",
  "hostname": "host-machine",
  "deny_reason": [
    "no applicable policies for op(action=net:connect:tcp, resource=net:domain:example.com:443)"
  ],
  "action_type": "network_egress",
  "network_egress": { "protocol": "tcp" },
  "agent": "claude"
}
```


---

# SIEM forwarding

*Sección: Ai*

{{< summary-bar feature_name="AI Governance Audit Logs" >}}

Docker can forward audit events to your security information and event
management (SIEM) system, letting you centralize Docker governance data
alongside other security signals. Docker verifies the endpoint is reachable
with the supplied credential before saving.

## Supported destinations

| Destination                      | Description                                                     |
| -------------------------------- | --------------------------------------------------------------- |
| Splunk Cloud (HEC)               | Hosted Splunk using the HTTP Event Collector                    |
| Dynatrace                        | Dynatrace Log Management using the Log Ingest API               |
| Datadog                          | Datadog Logs using the HTTP log intake API                      |

## Before you begin

SIEM forwarding requires Docker Sandboxes
[0.39.0](../../release-notes.md) or later. Earlier versions
don't deliver audit records to a SIEM destination, even when forwarding is
configured. Update Docker Sandboxes before enabling a new destination.

SIEM forwarding requires Docker Cloud delivery to be enabled for your
organization. If you haven't already, enable it under **AI Platform** >
**Audit logs** > **Audit delivery** before configuring a SIEM destination. See
[Configure audit delivery](configure.md).

Gather credentials from your SIEM before configuring forwarding:

- **Splunk Cloud**: HEC ingest URL and an HEC token. Optionally, a Splunk index
  name. See [Splunk documentation](https://docs.splunk.com/).
- **Dynatrace**: Log Ingest API URL and an API token with the `logs.ingest`
  scope. See [Dynatrace documentation](https://docs.dynatrace.com/).
- **Datadog**: Logs intake URL for your Datadog site and an API key. See
  [Datadog documentation](https://docs.datadoghq.com/).

## Add a SIEM destination

1. Sign in to [Docker Home](https://app.docker.com/).
1. Open your organization.
1. Go to **AI Platform** > **Audit logs**.
1. Open **Export & Connectors**.
1. Select **Add destination**.
1. Select your destination and complete the form.
1. Select **Save**.

If verification fails, check that the URL and credential are correct and that
the endpoint is accessible from the internet.

## Manage destinations

From the **SIEM forwarding** list, select the menu next to a destination to
edit or delete it. The edit form lets you update credentials and toggle
forwarding on or off for that destination. Deleting a destination permanently
removes the endpoint and its stored credential and cannot be undone.


---

# View and export audit events

*Sección: Ai*

Cloud delivery stores AI Governance audit records in Docker Cloud and makes
them available in the hosted audit log UI. Use the hosted view to investigate
policy decisions or export events to CSV.

## View audit events

To view audit events:

1. Sign in to [Docker Home](https://app.docker.com/).
1. Open your organization.
1. Go to **AI Platform** > **Audit logs**.
1. Open **Audit Events**.

The **Audit Events** view includes summary tiles for total events, allowed
events, denied events, and consent-required events. The event table includes:

| Column    | Description                                                   |
| --------- | ------------------------------------------------------------- |
| Time      | When Docker recorded the event.                               |
| Event     | The event type or policy action.                              |
| Principal | The Docker user associated with the event.                    |
| Resource  | The target resource, such as a domain, file path, or tool.    |
| Decision  | The governance decision, such as allow, deny, or consent.     |
| Agent     | The AI agent associated with the event, when Docker knows it. |

## Filter and search events

Use the audit log filters to narrow the event table by decision and time range.
Use search to find events by principal, resource, event type, or agent.

The event table uses cursor pagination for large result sets.

## Export events to CSV

Use CSV export when you need an offline copy of filtered audit events:

1. Open **Audit Events**.
1. Apply the filters and search terms for the events you want to export.
1. Select **Export**.
1. Download the generated CSV file from the link Docker provides.

CSV exports include up to 1 000 000 rows. Download links expire after 24 hours.


---

# Policy concepts

*Sección: Ai*

## Resource model

Docker sandbox governance is built around two resource types: **policies** and
**rules**.

A **policy** is a named collection of rules that controls sandbox access.
Policies exist at two levels:

- **Local**: configured per machine using the `sbx policy` CLI. Applies to
  sandboxes on that machine only.
- **Organization**: configured in Docker Home. Network and filesystem policies
  can also be managed via the
  [Governance API](/reference/api/ai-governance/). Applies to sandboxes across
  the organization. An organization can have several policies, each applying
  either org-wide or to specific teams. See [Policy scope](#policy-scope).

When organization governance is active, only organization allow rules can grant
access. Local and kit-defined deny rules still apply on top. See
[Precedence](#precedence).

A **rule** is the unit of access control within a policy. Each rule has:

- **Name**: a human-readable label
- **Actions**: the type of access the rule controls
- **Resources**: the targets the rule matches against
- **Decision**: `allow` or `deny`

Rules are grouped by domain. Network and filesystem rules in a policy must
share the same domain, either `network` or `filesystem`. MCP policies use Cedar
statements written in the `MCP` namespace instead of the network and filesystem
rule format.

### Limits

Organization policies have the following limits, which help ensure fair usage
and resource availability across organizations:

| Limit                     | Value                                               |
|---------------------------|-----------------------------------------------------|
| Policies per organization | 100                                                 |
| Rules per policy          | 250                                                 |
| Policy size               | 400 KB total, shared across all of a policy's rules |

Typical policies use only a small fraction of the policy size limit. Domain
and file path values have no separate length limit beyond valid format.

If these limits don't fit your organization's needs,
[contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
to discuss options.

## Policy scope

Each organization policy applies either across the whole organization or only
to specific teams:

- Org-wide: with no teams assigned, the policy applies to every member of the
  organization.
- Team-scoped: with one or more teams assigned, the policy applies only to
  members of those teams.

Teams are the same [teams](../../../accounts/organization/manage/manage-a-team.md)
you manage for your organization; Docker matches a policy's teams against each
user's team membership. Because an organization can mix org-wide and team-scoped
policies, a single user is often subject to several at once. The policies that
apply to a given user are their _effective policies_: every org-wide policy,
plus every team-scoped policy for a team they belong to. See
[Rule evaluation](#rule-evaluation) for how a user's effective policies combine.

## Rule syntax

### Network rules

Network rules use the action `connect:tcp`. Resources are hostnames, CIDR
ranges, or ports. The governance policy schema also accepts `connect:udp`, but
Docker Sandboxes always blocks direct external UDP and ICMP. `connect:udp`
rules have no effect.

**Hostname patterns**

| Pattern               | Example           | Matches                                                      |
| --------------------- | ----------------- | ------------------------------------------------------------- |
| Exact hostname        | `example.com`     | `example.com` on any port, not subdomains                     |
| Single-level wildcard | `*.example.com`   | One subdomain level, any port: `api.example.com`              |
| Multi-level wildcard  | `**.example.com`  | Any depth, any port: `api.example.com`, `v2.api.example.com`  |
| Hostname with port    | `example.com:443` | `example.com` on port 443 only                                |

`example.com` and `*.example.com` don't cover each other. Specify both if you
need to match the root domain and its subdomains.

**CIDR ranges**

Both IPv4 and IPv6 notation are supported: `10.0.0.0/8`, `192.168.1.0/24`,
`2001:db8::/32`.

For local and organization policy configuration, see
[Network access policies](access-controls/network.md).

### Filesystem rules

Filesystem rules use the actions `read` and `write`. Resources are host paths
that sandboxes can mount as workspaces.

A workspace mounted with write access must be allowed by both a `read` and a
`write` rule; a read-only workspace needs only `read`. When default deny blocks
a mount, the denial reason names whether read or write access was missing.

`~` expands to the user's home directory on every platform, including Windows,
where it resolves to `%USERPROFILE%`. A single `~/**` rule therefore matches
each user's home tree on macOS, Linux, and Windows. The policy engine expands
only `~`: it does not expand environment variables, so a pattern such as
`%USERPROFILE%\**` or `$HOME/**` matches nothing.

For a path outside the home directory, write it in the format the user's
operating system uses. A rule matches only the format it's written in, so a
location that several platforms share needs a rule for each:

| Operating system | Example path                               |
| ---------------- | ------------------------------------------ |
| macOS, Linux     | `/data/project/**`                         |
| Windows          | `C:\data\project\**`                       |
| WSL              | `\\wsl.localhost\<distro>\data\project\**` |

On Windows, `*:` matches any drive letter, so `*:\data\**` matches the path on
any drive.

Wildcards behave the same way in every path format:

| Pattern            | Example    | Matches                                                    |
| ------------------ | ---------- | ---------------------------------------------------------- |
| Exact path         | `/data`    | `/data` only                                               |
| Segment wildcard   | `/data/*`  | `/data/project`, one path segment only, not subdirectories |
| Recursive wildcard | `/data/**` | `/data/project`, `/data/project/src`, any depth            |

Use `**` to match a directory tree recursively. A single `*` matches within one
path segment and won't cross a path separator. For example, `~/**` matches all
paths under the home directory, while `~/*` matches only its direct children.

For organization policy configuration and enforcement details, see
[Filesystem access policies](access-controls/filesystem.md).

### MCP policies

MCP policies control Model Context Protocol activity made available to a
sandbox through Docker's [MCP gateway](../mcp-gateway.md). They are
organization policies written in Cedar using the `MCP` namespace, rather than
the network and filesystem rule format.

MCP policy applies when a developer registers a server and when an agent uses
the MCP gateway. Registration rules control future `sbx mcp add` operations.
Use-time rules control tool calls, gateway meta-tools, resource reads, and
prompt retrieval from servers that are already registered or loaded.

Governed MCP activity is default deny: a request is blocked unless a matching
`permit` allows it. A matching `forbid` overrides any `permit`, including a
permit that requires approval. Policy scope supplies the principal, so use
organization or team scope instead of matching users, teams, tenants, or roles
in Cedar.

For representative policies, see [MCP access policies](access-controls/mcp.md).
For exact action, resource, context, and approval behavior, see the
[MCP policy reference](reference/mcp-policy.md).

## Rule evaluation

When organization governance is active, the rules from all of a user's
[effective policies](#policy-scope) are combined and evaluated together against
each request, following two principles:

- Deny wins: if any rule matches with `decision: deny`, the request is denied,
  regardless of any matching allow rules.
- Default deny: anything an allow rule doesn't match is blocked. Outbound
  network traffic is blocked unless a network rule allows the destination, and a
  host path can't be mounted unless a filesystem rule allows it. MCP activity is
  blocked unless an MCP `permit` allows it.

Because every effective policy feeds the same evaluation, allows are additive (a
request is allowed if any effective policy allows it) and denies are absolute (a
request is blocked if any effective policy denies it). A deny rule in an
org-wide policy therefore applies to everyone and can't be overridden by a
team-scoped policy, which makes org-wide deny rules useful as guardrails.

Local and kit-defined allow rules take no part in this evaluation. Deny rules
from those sources do still apply. See [Precedence](#precedence).

## Precedence

What applies depends on whether your organization has governance enabled:

- No organization governance: local rules and any
  [kit-defined network rules](../customize/kits.md#control-network-access)
  determine what sandboxes can access.
- Organization governance active: organization policy determines what access can
  be granted. Only organization allow rules grant access, so local and
  kit-defined allow rules are inactive and can't expand what the organization
  permits. Deny rules apply from every source, so a local or kit-defined deny
  can still restrict access further.

Precedence is decided by a rule's decision rather than its source:

| Rule                | Evaluated under organization governance |
| ------------------- | --------------------------------------- |
| Organization allow  | Yes                                     |
| Organization deny   | Yes                                     |
| Local allow         | No                                      |
| Local deny          | Yes                                     |
| Kit-defined allow   | No                                      |
| Kit-defined deny    | Yes                                     |

Local and kit-defined rules cover network access only, so a deny that layers on
top of organization policy is always a network deny. `sbx policy ls` hides
inactive rules by default. See
[Monitoring](monitor-and-enforce/monitoring.md#showing-inactive-rules) for how
to list them.

When organization governance is active, a user's organization policies are
evaluated together, as described in [Rule evaluation](#rule-evaluation).


---

# Monitor and enforce

*Sección: Ai*

After policies are configured, use monitoring, audit records, and sign-in
enforcement to verify how governance behaves across developer machines.

- [Monitoring policies](monitoring.md): inspect active policy rules and monitor
  sandbox network traffic.
- [Audit logs](../audit/): view, configure, export, and collect governance audit
  records.
- [Sign-in enforcement](sign-in-enforcement.md): require users to sign in as
  members of approved Docker organizations.


---

# Monitoring policies

*Sección: Ai*

`sbx policy ls` and `sbx policy log` give you a combined view of all active
policy rules and sandbox network activity, regardless of whether those rules
come from local configuration or organization governance. They're useful both
for verifying rules you've written and for debugging why a request is being
blocked or allowed.

## Listing rules

Use `sbx policy ls` to see all active policies and their current status:

```console
$ sbx policy ls
POLICY                                 SOURCE   APPLIES TO          SUMMARY
local-policy                           local    all                 network: 42 allow, 1 deny; filesystem read: 1 allow; filesystem write: 1 allow
1b2633ea-e604-48bb-a5e6-3ac86ba383fe   kit      sandbox:my-sandbox  network: 3 allow
```

The columns are:

- `POLICY`: the policy name.
- `SOURCE`: where the policy came from. `local` means your local configuration
  — a preset or rules you added with `sbx policy`. `kit` means a
  [kit](../../customize/kits.md#control-network-access). `org` means your
  organization.
- `APPLIES TO`: which sandboxes the policy applies to. `all` means the policy
  is global. `sandbox:<name>` scopes it to a single sandbox; a profile name
  scopes it to sandboxes using that profile.
- `SUMMARY`: a count of rules by type and decision — for example,
  `network: 5 allow, 1 deny`.

To see full rule-level detail including rule IDs and resources, pass `--wide`.
To inspect a single policy or rule, use `sbx policy inspect`:

```console
$ sbx policy inspect Balanced
```

Use `--source` to filter by origin (`local`, `org`, or `kit`) and `--decision`
to filter by outcome (`allow` or `deny`).

A `STATUS` column also appears when you pass `--include-inactive`; see
[Showing inactive rules](#showing-inactive-rules).

When organization governance is active, the output starts with a summary line
showing which organization manages the policy, the sync state, and how many
inactive rules are hidden:

```console
$ sbx policy ls
Governance: Managed by my-org | Sync: OK, last synced 08:21:01 | Hidden: 9 inactive rules. Show with: sbx policy ls --include-inactive

POLICY               SOURCE   APPLIES TO   SUMMARY
default filesystem   org      all          filesystem read: 2 allow; filesystem write: 7 allow, 2 deny
default network      org      all          network: 38 allow, 4 deny
```

`Governance` shows which organization manages the policy, and `Sync` confirms
the daemon has pulled the latest rules. If the sync state shows an error or a
stale timestamp, the daemon may not have the most recent org policy. Run
`sbx policy reset` to force a fresh pull. `Hidden` reports how many inactive
rules are suppressed and how to reveal them.

If Docker can't determine which organization governs your account, policy
output shows `Governance: Unresolved`, and the dashboard shows the same
unresolved state. For example, this happens when your account belongs to
multiple organizations with governance enabled. Policy enforcement fails closed
until the conflict is resolved, so local allow rules can't grant access. Contact
an administrator for the affected organizations to resolve the conflicting
governance configuration.

### Showing inactive rules

When organization governance is active, local and kit-defined allow rules are
not evaluated, so `sbx policy ls` hides them by default. To list them too — for
example, to confirm which allow rules the organization policy overrides — pass
`--include-inactive`. This adds a `STATUS` column:

```console
$ sbx policy ls --include-inactive
Governance: Managed by my-org | Sync: OK, last synced 08:41:06

POLICY                       SOURCE   APPLIES TO   SUMMARY                                                    STATUS
default filesystem           org      all          filesystem read: 2 allow; filesystem write: 7 allow, 2 deny   active
default network              org      all          network: 38 allow, 4 deny                                   active
default-fs-read-allow-all    local    all          filesystem read: 1 allow                                    inactive
default-fs-write-allow-all   local    all          filesystem write: 1 allow                                   inactive
```

Inactive policies show `inactive` in the `STATUS` column. They have no effect
while organization governance is active. Local and kit-defined deny rules stay
active and aren't hidden, because a deny still applies on top of the
organization policy. See [Precedence](../concepts.md#precedence).

Use `--type network` or `--type filesystem` to show only policies of that type.
Without a sandbox argument, `sbx policy ls` shows every policy across all
sandboxes. Pass a sandbox name to filter to global policies and those scoped to
that sandbox:

```console
$ sbx policy ls my-sandbox
```

### Filesystem rules

`sbx policy ls` lists filesystem policies alongside network policies. Filesystem
rules control which host paths a sandbox can mount as a workspace. Pass
`--type filesystem` to show only them:

```console
$ sbx policy ls --type filesystem
POLICY         SOURCE   APPLIES TO   SUMMARY
local-policy   local    all          filesystem read: 1 allow; filesystem write: 1 allow
```

A writable workspace mount must be allowed by both a `filesystem:read` and a
`filesystem:write` rule; a read-only mount needs only `filesystem:read`. The
default local policy allows read and write access to all paths, shown as the
two `default-fs-*` rules above. For the rule syntax and path patterns, see
[Policy concepts](../concepts.md#filesystem-rules).

## Monitoring traffic

Use `sbx policy log` to see which hosts your sandboxes have contacted and
which rules matched:

```console
$ sbx policy log
Blocked requests:
SANDBOX      TYPE     HOST                   PROXY        RULE            REASON         LAST SEEN        COUNT
my-sandbox   network  blocked.example.com    transparent  domain-blocked  default-deny   10:15:25 29-Jan  1

Allowed requests:
SANDBOX      TYPE     HOST                   PROXY          RULE             REASON   LAST SEEN        COUNT
my-sandbox   network  api.anthropic.com      forward        domain-allowed            10:15:23 29-Jan  42
my-sandbox   network  registry.npmjs.org     forward-bypass domain-allowed            10:15:20 29-Jan  18
my-sandbox   network  app.example.com        browser-open                             10:15:10 29-Jan  1
```

The `PROXY` column shows how the request left the sandbox:

| Value            | Description                                                                                                    |
| ---------------- | -------------------------------------------------------------------------------------------------------------- |
| `forward`        | Routed through the forward proxy. Supports [credential injection](../../configuration/credentials.md).              |
| `forward-bypass` | Routed through the forward proxy without credential injection.                                                 |
| `transparent`    | Intercepted by the transparent proxy. Policy is enforced but credential injection is not available.            |
| `network`        | Non-HTTP traffic (raw TCP, UDP, ICMP). TCP can be allowed with a policy rule. UDP and ICMP are always blocked. |
| `browser-open`   | A sandbox process requested opening a URL in the host browser. Policy is enforced before opening the URL.      |

The `RULE` column identifies the policy rule that matched the request. The
`REASON` column includes extra context when the daemon records one.

Filter by sandbox name by passing it as an argument:

```console
$ sbx policy log my-sandbox
```

Use `--limit N` to show only the last `N` entries, `--json` for
machine-readable output, or `--type network` to filter by policy type.
`sbx policy log` records network traffic only; filesystem mount decisions
aren't available in the log yet.


---

# Sign-in enforcement

*Sección: Ai*

Sign-in enforcement restricts Docker Sandboxes to users who are members of
specific Docker organizations. An administrator deploys an enforcement
configuration to managed endpoints, and `sbx login` verifies organization
membership after the user authenticates. If the check fails, credentials are
immediately revoked and the user can't run sandboxes.

Without this enforcement, a developer can sign in with a personal account and
bypass organization [governance policies](../access-controls/organization.md).
Sign-in enforcement closes that gap at the endpoint, where users can't override
it.

> [!NOTE]
> Sign-in enforcement is part of Docker's AI Governance offering.
> [Contact Docker Sales](https://www.docker.com/products/ai-governance/#contact-sales)
> to learn more.

## How it works

1. An administrator deploys an enforcement configuration to managed endpoints
   through MDM, Group Policy, or configuration management, specifying one or
   more allowed Docker organization slugs.
2. When a user runs `sbx login`, they authenticate with Docker. Credentials
   are saved temporarily, then Docker Sandboxes calls the Docker API to
   verify organization membership.
3. If the user belongs to at least one allowed organization, login succeeds and
   the credentials are kept.
4. If not, Docker Sandboxes immediately revokes the saved credentials and the
   user receives an [error message](#error-messages) listing the required
   organizations.

`sbx login` and `sbx logout` always run regardless of organization membership.
Other commands require a valid signed-in session, so they fail after a denied
login until the user signs in with an allowed account.

## Enforcement configuration

All platforms express the same logical schema. The canonical JSON
representation:

```json
{
  "allowedOrgs": ["docker", "acme-corp"],
  "adminEmail": "it-security@acme-corp.com",
  "adminURL": "https://acme-corp.atlassian.net/servicedesk/it",
  "adminName": "ACME IT Security Team"
}
```

| Field         | Type            | Required | Description                                                                                         |
| ------------- | --------------- | -------- | --------------------------------------------------------------------------------------------------- |
| `allowedOrgs` | list of strings | Yes      | Docker organization slugs. The user must be a member of at least one. Matching is case-insensitive. |
| `adminName`   | string          | No       | Administrator or team display name shown in the denial message.                                     |
| `adminEmail`  | string          | No       | Contact email shown in the denial message.                                                          |
| `adminURL`    | string          | No       | Help desk or access-request URL shown in the denial message.                                        |

If `allowedOrgs` is empty or missing, enforcement is inactive and any
authenticated user can use Docker Sandboxes.

The optional `adminName`, `adminEmail`, and `adminURL` fields give denied users
a path to resolution. Include the contact details your organization uses for
access requests.

## Deploy the configuration

Use your existing endpoint management tooling to deploy the configuration. Each
platform reads it from a native location that ordinary users can't modify.

{{< tabs >}}
{{< tab name="macOS" >}}

On macOS, the configuration is a managed preferences domain, `com.docker.sbx`.

Deploy it through any MDM solution, such as Jamf or Intune, as a custom
configuration profile. MDM-deployed profiles take precedence over user-level
preferences and can only be removed by removing the device from MDM management,
so users can't override them.

The following `.mobileconfig` payload sets the allowed organization and admin
contact details:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>PayloadContent</key>
  <array>
    <dict>
      <key>PayloadType</key>
      <string>com.apple.ManagedClient.preferences</string>
      <key>PayloadVersion</key>
      <integer>1</integer>
      <key>PayloadIdentifier</key>
      <string>com.docker.sbx.policy</string>
      <key>PayloadUUID</key>
      <string><!-- generate a UUID --></string>
      <key>PayloadEnabled</key>
      <true/>
      <key>PayloadDisplayName</key>
      <string>Docker Sandboxes Policy</string>
      <key>PayloadContent</key>
      <dict>
        <key>com.docker.sbx</key>
        <dict>
          <key>Forced</key>
          <array>
            <dict>
              <key>mcx_preference_settings</key>
              <dict>
                <key>allowedOrgs</key>
                <array>
                  <string>acme-corp</string>
                </array>
                <key>adminEmail</key>
                <string>it-security@acme-corp.com</string>
                <key>adminURL</key>
                <string>https://acme-corp.atlassian.net/servicedesk/it</string>
                <key>adminName</key>
                <string>ACME IT Security</string>
              </dict>
            </dict>
          </array>
        </dict>
      </dict>
    </dict>
  </array>
</dict>
</plist>
```

To test the configuration locally without MDM, write to the user preferences
domain:

```console
$ defaults write com.docker.sbx allowedOrgs -array "acme-corp"
$ defaults write com.docker.sbx adminEmail "it@acme.com"
```

To remove the test configuration:

```console
$ defaults delete com.docker.sbx
```

`defaults write` uses the user preferences domain, not the managed-preferences
domain. On a managed device, the MDM profile is authoritative and user-level
settings in the same domain are ignored.

{{< /tab >}}
{{< tab name="Windows" >}}

Deploy it through Group Policy, Intune, or any endpoint management tool that can
write registry values.

| Value name    | Type           | Description                                         |
| ------------- | -------------- | --------------------------------------------------- |
| `allowedOrgs` | `REG_MULTI_SZ` | Multi-string list, one organization slug per string |
| `adminName`   | `REG_SZ`       | Administrator or team name (optional)               |
| `adminEmail`  | `REG_SZ`       | Contact email (optional)                            |
| `adminURL`    | `REG_SZ`       | Help desk URL (optional)                            |

To test the configuration locally, run the following in an elevated PowerShell
session. Use `New-ItemProperty` to create values with an explicit type;
`Set-ItemProperty` doesn't create new values.

```powershell
New-Item -Path "HKLM:\SOFTWARE\Policies\Docker\SBX" -Force

New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Docker\SBX" `
  -Name "allowedOrgs" -Value @("acme-corp") -PropertyType MultiString -Force
New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Docker\SBX" `
  -Name "adminEmail" -Value "it@acme.com" -PropertyType String -Force
```

To remove the configuration:

```powershell
Remove-Item -Path "HKLM:\SOFTWARE\Policies\Docker\SBX" -Recurse -Force
```

{{< /tab >}}
{{< tab name="Linux" >}}

On Linux, the configuration is a root-owned JSON file at
`/etc/docker-sbx/config.json`.

Deploy it through configuration management such as Ansible, Puppet, Chef, or
Salt. The file must be owned by root with `644` permissions.

```json
{
  "allowedOrgs": ["acme-corp"],
  "adminEmail": "it-security@acme-corp.com",
  "adminURL": "https://acme-corp.atlassian.net/servicedesk/it",
  "adminName": "ACME IT Security"
}
```

To deploy and set ownership:

```console
$ sudo mkdir -p /etc/docker-sbx
$ sudo tee /etc/docker-sbx/config.json <<'EOF'
{"allowedOrgs": ["acme-corp"], "adminEmail": "it@acme.com"}
EOF
$ sudo chown root:root /etc/docker-sbx/config.json
$ sudo chmod 644 /etc/docker-sbx/config.json
```

To remove the configuration:

```console
$ sudo rm -f /etc/docker-sbx/config.json
```

The Linux loader fails closed if the file is a symlink, isn't a regular file,
isn't owned by root, or is writable by group or other. Any deviation is treated
as a configuration error and `sbx login` is denied with a descriptive message.
Deploying with the commands above passes these checks.

{{< /tab >}}
{{< /tabs >}}

## Error messages

When a user signs in with an account that isn't a member of an allowed
organization, they're signed out and shown a denial message. Only the contact
fields you configure appear: if only `adminEmail` is set, the URL line is
omitted.

When no admin contact details are configured:

```text
Access denied: Your administrator requires you to be logged into an account
that is a member of one of the following Docker organizations:
  - acme-corp

Sign in with an account that belongs to one of these organizations, or
contact your administrator for access.
```

When admin contact details are configured:

```text
Access denied: Your administrator requires you to be logged into an account
that is a member of one of the following Docker organizations:
  - acme-corp

For access, contact ACME IT Security:
  Email: it-security@acme-corp.com
  URL:   https://acme-corp.atlassian.net/servicedesk/it
```

## Related pages

- [Organization policies](../access-controls/organization.md): centrally manage
  sandbox network, filesystem, and MCP access controls from the Docker Admin
  Console
- [Governance overview](../index.md): how local and organization governance fit
  together
- [Enforce sign-in for Docker Desktop](../../../../enterprise/security/enforce-sign-in/index.md):
  the equivalent control for Docker Desktop


---

# Reference

*Sección: Ai*

Use reference material when you need API details or exact policy syntax.

- [Policy concepts](../concepts.md): resource model, rule syntax, policy
  evaluation, and precedence.
- [AI Governance API](/reference/api/ai-governance/): HTTP API reference for
  network and filesystem organization policies.
- [MCP policy reference](mcp-policy.md): Docker MCP policy actions, resources,
  attributes, context fields, and approval behavior.


---

# AI Governance API

*Sección: Ai*




---

# MCP policy reference

*Sección: Ai*

MCP policies are organization policies written in Cedar using Docker's `MCP`
namespace. This reference defines the Docker-specific policy surface for Model
Context Protocol (MCP) activity made available to sandboxes through Docker's
[MCP gateway](../../mcp-gateway.md).

Use this reference with [MCP access policies](../access-controls/mcp.md) for
common policy patterns. For the Cedar language, see the
[Cedar documentation](https://docs.cedarpolicy.com/).

## Evaluation model

Cedar evaluates MCP requests against a principal, action, resource, and context.
For Docker MCP policies, policy scope supplies the principal. Write policies
against the action, resource, and context. Clauses that reference principal
attributes, such as `principal in ...`, `principal.role`, or
`principal.tenant`, don't match.

Governed MCP activity is default deny. A request is blocked unless a matching
`permit` allows it. A matching `forbid` overrides any `permit`, including a
permit annotated with `@requireApproval`.

For details about when Docker Sandboxes evaluates MCP policies for a user, see
[Govern the server lifecycle](../access-controls/mcp.md#govern-the-server-lifecycle).

An actionless `permit` matches every MCP action that reaches Cedar evaluation:

```plaintext
permit (principal, action, resource);
```

## Actions

| Action              | Governs                   | Notes                                                                                                          |
| ------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `register`          | MCP server registration   | Server registration needs an explicit `permit`. Use server attributes to scope registration.                   |
| `invokeTool`        | MCP tool calls            | Most tool access policies target this action.                                                                  |
| `invokePrimordial`  | Gateway meta-tool calls   | Applies to built-in gateway tools such as `mcp-exec`, `mcp-add`, `code-mode`, and OAuth authorization helpers. |
| `readResource`      | MCP resource reads        | Rules match `MCP::Resource` and `resource.uri`.                                                                |
| `getPrompt`         | MCP prompt retrieval      | Rules match `MCP::Prompt` and `resource.name`.                                                                 |
| `listTools`         | MCP tool listing          | Defined in the schema but not Cedar-gated. Tool listings can include tools denied at invocation.               |
| `listResources`     | MCP resource listing      | Defined in the schema but not Cedar-gated. Resource listings can include resources denied by policy.           |
| `subscribeResource` | MCP resource subscription | Defined in the schema but not Cedar-gated.                                                                     |

## Resources

Match resources with the MCP entity type and attributes for the request.

| Entity            | Match with             | Notes                                                                                                                            |
| ----------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `MCP::Server`     | Registered server name | The canonical server identity is the `resource.identityURL` attribute, not the entity ID.                                        |
| `MCP::Tool`       | Bare tool name         | Use `resource.name`. Display prefixes aren't included. A bare-name match applies to every server exposing a tool with that name. |
| `MCP::Resource`   | Resource URI           | Use `resource.uri`.                                                                                                              |
| `MCP::Prompt`     | Prompt name            | Use `resource.name`.                                                                                                             |
| `MCP::Primordial` | Gateway meta-tool name | Match a specific primordial with an entity reference.                                                                            |

Examples:

```plaintext
resource in MCP::Server::"notion"
resource.name == "move_file"
resource.uri like "*/docs/*"
resource in MCP::Primordial::"code-mode"
```

## Resource attributes

Tool annotation attributes come from MCP tool annotations or catalog metadata
and are advisory.

| Attribute                  | Applies to        | Notes                                                                                                                                                 |
| -------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `resource.name`            | Tools and prompts | For tools, this is the bare tool name, not a display-prefixed name.                                                                                   |
| `resource.uri`             | Resources         | Use with string operators such as `like`.                                                                                                             |
| `resource.readOnly`        | Tools             | Defaults to `false` when a tool doesn't declare it.                                                                                                   |
| `resource.destructive`     | Tools             | Defaults to `true` when a tool doesn't declare it.                                                                                                    |
| `resource.idempotent`      | Tools             | Defaults to `false` when a tool doesn't declare it.                                                                                                   |
| `resource.openWorld`       | Tools             | Defaults to `true` when a tool doesn't declare it.                                                                                                    |
| `resource.type`            | Servers           | Use for server registration rules. See [Server type values](#server-type-values).                                                                     |
| `resource.identityURL`     | Servers           | Canonical server identity. The value depends on the registration type. See [Server identity values](#server-identity-values).                         |
| `resource.requiresOAuth`   | Servers           | Use for server registration rules.                                                                                                                    |
| `resource.requiresNetwork` | Servers           | Use for server registration rules.                                                                                                                    |
| `resource.command`         | Servers           | Local stdio server command, such as `npx` or `docker`, when available. Empty for remote servers and registrations that don't include command details. |
| `resource.args`            | Servers           | Local stdio server arguments when available. This is a set, so `.contains()` can match values. Empty when no command details are available.           |

Use `like` for string attributes. In Cedar, `like` uses `*` as its wildcard,
matches the full string, treats `?` as a literal character, and treats `\*` as
a literal asterisk.

Use `.contains()` only on set attributes, such as `resource.args`. On string
attributes, use `like`.

### Server type values

Local gateway registrations use these values:

- `local-stdio`: a host-run stdio server. This includes explicit commands and
  OCI-packaged stdio servers resolved from metadata with `--local`.
- `container-stdio`: an OCI-packaged server resolved from metadata without
  `--local`. This value can appear in `register` decisions, but the local
  gateway can't attach or run this server type.
- `remote-dcr`: a remote endpoint that doesn't require OAuth or supports OAuth
  Dynamic Client Registration.
- `remote-no-dcr`: a remote OAuth endpoint that doesn't support Dynamic Client
  Registration.

### Server identity values

For a remote server, `resource.identityURL` is the endpoint URL. For an explicit
local command, it is the resolved executable path on the host. For a `--local`
metadata registration, it is `local://stdio/<name>`, not the registry or
manifest URL.

## Context fields

| Field                  | Notes                                                                                                                                       |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `context.request_time` | Bound for tool calls, built-in gateway tool calls, resource reads, and prompt retrieval. Registration requests don't include it.            |
| `context.args`         | Arguments for `invokeTool` and `invokePrimordial` requests evaluated by the gateway. Present when arguments are available as a JSON object. |

A registration `permit` conditioned on `context.request_time` doesn't match,
so the registration falls to default deny.

Guard tool-call argument rules with `context has args` and a field check:

```plaintext
permit (principal, action == MCP::Action::"invokeTool", resource)
when {
  resource.name == "approve_expense" &&
  context has args &&
  context.args has amount &&
  context.args.amount <= 500
};
```

A `permit` gated on missing arguments doesn't match, so the request falls to
default deny. A `forbid` gated on missing arguments doesn't match, so it
doesn't block the request.

Only object-shaped tool arguments are represented in `context.args`.
Unsupported or malformed arguments are omitted.

## Approval annotation

Use `@requireApproval("reason")` on a `permit` statement to require in-session
confirmation through MCP elicitation before a matching request runs:

```plaintext
@requireApproval("write tool call")
permit (principal, action == MCP::Action::"invokeTool", resource)
when { resource.readOnly == false };
```

When a request matches the annotated `permit` and no `forbid` overrides it, the
policy engine returns an approval-required outcome. The annotation string is
shown as the elicitation reason. An approval-required outcome takes precedence
over a normal `permit`. A matching `forbid` denies the request without an
elicitation.

For the request flow and trust model, see
[Require confirmation with MCP elicitation](../access-controls/mcp.md#require-confirmation-with-mcp-elicitation).

Approval requires a client session that can present an MCP elicitation request
to the user. If the request can't be presented for approval, the request is
denied. Approval is an in-session confirmation, not an out-of-band approval
workflow. Each confirmation applies to one authorization request. After the
client confirms, the gateway re-evaluates the request with an approval digest.

`sbx mcp add` can't present an elicitation request. A registration permit with
`@requireApproval` therefore results in a denial.

Only the exact annotation name `@requireApproval` applies approval behavior.
Other annotation names, such as `@requireConsent` or `@requireConfirmation`,
don't require approval.

## Limitations

- Tool and resource listing actions aren't Cedar-gated. Listings can include
  entries that a policy denies when the sandbox tries to use them.
- Approval-gated requests are denied when the execution context can't relay an
  MCP elicitation to the originating client. This includes tool calls made from
  inside `code-mode`.
- Registration policy is evaluated when a server is registered. It doesn't
  remove existing registrations or stop an already-loaded server by itself.
  Govern existing registrations with use-time rules such as `invokeTool`,
  `readResource`, and `getPrompt`.
- Server command and argument rules using `resource.command` or `resource.args`
  apply only when the resolved server registration includes local stdio command
  details. Remote servers and metadata-resolved local servers can have empty
  values for those attributes. Use `resource.type == "local-stdio"` to match
  host-run servers independently of command details.
- Principal-based rules don't take effect. Use organization and team policy
  scope to target users.
- Server groups aren't supported in MCP policy. Reference servers individually.


---

# Install Docker Sandboxes

*Sección: Ai*

Install the `sbx` CLI to run AI coding agents in isolated microVMs. You don't
need Docker Desktop or Docker Engine to use `sbx`.

## Prerequisites

### macOS

- macOS Sonoma version 14 or later
- Apple silicon

### Windows

- Windows 11
- A 64-bit Intel or AMD processor
- Windows Hypervisor Platform

To turn on Windows Hypervisor Platform, open an elevated PowerShell prompt and
run:

```powershell
Enable-WindowsOptionalFeature -Online -FeatureName HypervisorPlatform -All
```

### Linux

- Ubuntu 24.04 or later
- A 64-bit Intel or AMD processor, or a 64-bit Arm processor
- KVM hardware virtualization supported and turned on by the CPU
- Your user account in the `kvm` group

If you're running inside a virtual machine or virtual desktop infrastructure
environment, the environment must support nested virtualization.

Verify that KVM is available:

```console
$ lsmod | grep kvm
```

A working setup shows `kvm_intel`, `kvm_amd`, `kvm_arm64`, or `kvm` in the
output. If the output is empty, run `kvm-ok` for diagnostics. `sbx` requires
KVM to start.

Add your user to the `kvm` group:

```console
$ sudo usermod -aG kvm $USER
```

Sign out and back in, or run `newgrp kvm`, for the group change to take effect.

## Install on macOS

Install `sbx` using Homebrew:

```console
$ brew trust docker/tap
$ brew install docker/tap/sbx
```

## Install on Windows

### Install for the current user

Install `sbx` using Windows Package Manager:

```powershell
winget install -h Docker.sbx
```

WinGet installs the per-user `DockerSandboxes.msi` package in
`%LOCALAPPDATA%\DockerSandboxes` and adds its `bin` directory to your user
`PATH`. You can install it without administrator privileges.

### Install for all users

For administrator-managed deployments, download
`DockerSandboxesMachine.msi` from the
[Docker Sandboxes releases](https://github.com/docker/sbx-releases/releases).
From an elevated PowerShell prompt, install the package silently:

```powershell
msiexec.exe /i DockerSandboxesMachine.msi /quiet
```

The machine-wide package installs in `%ProgramFiles%\DockerSandboxes` and adds
its `bin` directory to the system `PATH`.

A machine-wide upgrade might require restarting Windows if an `sbx` daemon in
another user's session is using the installed files.

## Install on Ubuntu

> [!NOTE]
>
> Docker does not test or support Docker Sandboxes on Ubuntu derivatives, such
> as Linux Mint and Pop!_OS. The convenience script can configure an incorrect
> package repository on these distributions.

You can install `sbx` with Docker Engine or install only the `sbx` package.

### Install Docker Engine and SBX

Run Docker's convenience script with `SBX=1` to install Docker Engine and the
`docker-sbx` package together:

```console
$ curl -fsSL https://get.docker.com | sudo SBX=1 sh
```

### Install SBX only

To install `sbx` without Docker Engine on the host, add Docker's `apt`
repository and install the `docker-sbx` package:

```console
$ curl -fsSL https://get.docker.com | sudo REPO_ONLY=1 sh
$ sudo apt install docker-sbx
```

## Install from release artifacts

To install `sbx` from a package or archive, follow the
[manual installation instructions](https://github.com/docker/sbx-releases#manual-install-from-release-artifacts).
The availability of a Linux release artifact does not indicate that Docker
tests or supports the corresponding distribution.

## Sign in

Sign in to Docker:

```console
$ sbx login
```

The command opens a browser for Docker OAuth. See the [FAQ](faq.md) for why
sign-in is required and how Docker handles your data.

After signing in, [run your first sandbox](get-started.md).


---

# Editor and app integrations

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes SSH" >}}

You can connect an external editor or desktop app to a running sandbox over
SSH. This lets you use the tools you already know — VS Code, Cursor, Claude
Desktop, and others — while your code runs, builds, and executes inside the
isolated sandbox instead of on your host.

Each sandbox is reachable at `<name>.sbx`, where `<name>` is the sandbox name.
Once SSH is set up, `<name>.sbx` behaves like any other SSH host, so any tool
that supports remote development over SSH can connect to it.

## Prerequisites

- The `sbx` CLI installed and signed in. See [Get started](../get-started.md).
- An SSH client. macOS and most Linux distributions include OpenSSH. On
  Windows, install the OpenSSH client.
- The editor or app you want to connect, with its remote-over-SSH support
  installed.

## Enable SSH access

Run the SSH setup command once:

```console
$ sbx setup ssh
```

The command starts the Docker Sandboxes daemon if needed and configures your
SSH client. You can re-run it at any time.

## Create or identify a sandbox

SSH connections require an existing sandbox. To create a named shell sandbox
for the current directory:

```console
$ sbx create --name demo shell .
```

To identify an existing sandbox, list your sandboxes:

```console
$ sbx ls
```

## Connect to a sandbox over SSH

Use the sandbox name with the `.sbx` suffix. For example, to connect to a
sandbox named `demo`:

```console
$ ssh demo.sbx
```

## Select the workspace folder

Connecting an app to a sandbox selects the remote environment, but it might not
open the primary workspace automatically. The initial folder depends on the
client. A remote folder picker might open at the sandbox user's home directory,
`/home/agent`, while an interactive `ssh` shell might start in
`/home/agent/workspace`. Select the intended folder explicitly instead of
relying on the initial location.

For a sandbox with a primary workspace, each workspace path appears inside the
sandbox at the same absolute path as on the host. For example, if you pass
`/Users/bob/src/my-project`, select that path in the remote folder picker. For
a mountless sandbox that uses a Docker-provided agent template, select
`/home/agent/workspace`.

## Connect a specific tool

- [VS Code](vscode.md)
- [Cursor](cursor.md)
- [Claude Desktop](claude-desktop.md)
- [ChatGPT](chatgpt.md)
- [T3 Code](t3-code.md)

## How SSH connections work

### Managed SSH configuration

`sbx setup ssh` writes a managed block to your SSH config: `~/.ssh/config` on
macOS and Linux, or `%USERPROFILE%\.ssh\config` on Windows. The block is similar
to the following:

```text
# >>> docker sandboxes (managed) >>>
Host *.sbx
    User _default_user_
    ProxyCommand "sbx" ssh proxy %n
    IdentityAgent none
    IdentityFile /dev/null
    IdentitiesOnly yes
    ControlMaster no
    ControlPath none
    UserKnownHostsFile "~/.ssh/sbx_known_hosts"
    KnownHostsCommand "sbx" ssh known-hosts %H
    StrictHostKeyChecking yes
# <<< docker sandboxes (managed) <<<
```

You don't edit this block by hand. Its key entries work as follows:

- `Host *.sbx` maps sandbox hostnames to the sandbox daemon. Application host
  pickers don't discover individual sandbox names from this wildcard, so enter
  the hostname, such as `demo.sbx`, manually when you configure an integration.
- `User _default_user_` tells the daemon to use the sandbox image's default
  user, so your host username is never sent.

### Connection and authentication

Connections don't use a network port or an SSH key:

- A `ProxyCommand` relays the SSH stream to the daemon over its local socket
  (a Unix domain socket on macOS and Linux, a named pipe on Windows).
- The daemon accepts the connection only while you have an active Docker login.
  Authentication is tied to your login, not to a stored key.
- The host key is verified on every connection, so a rotated daemon key never
  triggers a host-key mismatch.

Because SSH terminates at the daemon, no SSH server runs inside the sandbox.
The sandbox must already be created. If it is stopped, connecting to
`<name>.sbx` starts it automatically.

### Environment variables

SSH connections don't forward client environment variables into the sandbox.
The daemon acknowledges SSH environment requests for compatibility but ignores
their names and values.

### Port forwarding

SSH clients can use local port forwarding to make a service listening on the
sandbox's loopback interface available on the host. For example, a remote
development client can map `127.0.0.1:4321` in the sandbox to
`127.0.0.1:55565` on the host, choosing an available host port automatically.
Traffic passes through the SSH connection instead of a published Docker port.

The sandbox daemon accepts forwarded connections only to loopback addresses in
the sandbox, including `localhost`, `127.0.0.0/8`, and `::1`. The SSH client
chooses the bind address for the listener on the host. A listener bound to
`127.0.0.1` or `::1` is reachable only from the host. A client configured to
bind to a non-loopback address can make the forwarded service reachable from
other machines, subject to the host's network and firewall configuration.


---

# Connect ChatGPT to a sandbox

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes SSH" >}}

Connect the ChatGPT desktop app to a sandbox over SSH so Codex works inside the
isolated environment instead of on your host.

> [!NOTE]
> This page covers running Codex in the ChatGPT desktop app connected to a
> sandbox over SSH. To run the Codex CLI inside a sandbox directly, see
> [Codex](../agents/codex.md).

## Prerequisites

- SSH access set up. See [Editor and app integrations](index.md#enable-ssh-access).
- The ChatGPT desktop app installed.

ChatGPT's remote server requires the `codex` command in the sandbox. The Codex
sandbox template used in the following section includes this command.

## Connect

Create a named Codex sandbox for the current directory if you don't already
have one:

```console
$ sbx create --name demo codex .
```

Confirm that you can connect to the sandbox from a terminal:

```console
$ ssh demo.sbx
```

In the ChatGPT desktop app, open **Settings > Connections** and add an SSH
connection manually. Enter the sandbox hostname, such as `demo.sbx`, as the
host, then use the remote folder picker to
[select the mounted workspace](index.md#select-the-workspace-folder) as the
remote project.

For more connection options, see the OpenAI instructions to
[connect to an SSH host](https://learn.chatgpt.com/docs/remote-connections#connect-to-an-ssh-host).

## Full access still prompts for approval

ChatGPT controls Codex permissions separately from the Docker Sandbox. To run
commands without Codex approval prompts, select **Full access** from the
permissions menu for the remote chat. Enabling **Full access** under
**Settings > General** only adds the mode to the permissions menu. It doesn't
change an existing chat.

If the chat continues to request approval while showing **Full access**, update
the ChatGPT desktop app, then stop and restart the active task. Approval prompts
that return after reconnecting can indicate a
[Codex remote-permission synchronization issue](https://github.com/openai/codex/issues/29054).

## Related

- [Editor and app integrations](index.md) — how SSH access works and how to
  set it up
- [Codex](../agents/codex.md) — run the Codex CLI inside a sandbox


---

# Connect Claude Desktop to a sandbox

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes SSH" >}}

Claude Desktop can run Claude Code on a remote machine over SSH. Point it at a
sandbox so the agent works inside the isolated environment instead of on your
host.

> [!NOTE]
> This page covers Claude Desktop connecting to a sandbox over SSH. To run the
> Claude Code CLI inside a sandbox directly, see
> [Claude Code](../agents/claude-code.md).

## Prerequisites

- SSH access set up. See [Editor and app integrations](index.md#enable-ssh-access).
- Claude Desktop installed.

Use a sandbox created with the Claude agent type. The Claude sandbox template
configures Anthropic credentials and network access for the remote Claude Code
session.

## Connect

> [!WARNING]
> Connecting Claude Desktop to a sandbox over SSH transmits Anthropic
> credentials into the Claude Code process within the sandbox, reducing
> isolation guarantees.

Create a named Claude sandbox for the current directory if you don't already
have one:

```console
$ sbx create --name demo claude .
```

Confirm that you can connect to the sandbox from a terminal:

```console
$ ssh demo.sbx
```

In Claude Desktop, open the environment drop-down before starting a session and
select **+ Add SSH connection**. Enter a name for the connection and enter the
sandbox hostname, such as `demo.sbx`, in **SSH Host**. Leave **SSH Port** and
**Identity File** empty because the managed SSH config supplies them.

Select the connection from the environment drop-down, then use the remote
folder picker to
[select the mounted workspace](index.md#select-the-workspace-folder). The
picker might initially open at `/home/agent`.

For more connection options, see the Claude Desktop instructions for
[SSH sessions](https://code.claude.com/docs/en/desktop#ssh-sessions).

## Troubleshoot a broken SSH connection after token refresh

The SSH connection drops when the Anthropic token expires and needs to be
refreshed. To work around this, run the sandbox manually from your host:

```console
$ sbx run --name <sandbox-name>
```

## Troubleshoot SSH connection timeouts on Windows

Claude Desktop requires Git on Windows. If an SSH connection times out and the
Claude Desktop logs include `ProxyCommand error: spawn sh ENOENT`, install
[Git for Windows](https://git-scm.com/download/win).

If Git is already installed, verify that `sh.exe` is available on your `PATH`:

```powershell
PS> where.exe sh
```

If the command doesn't find `sh.exe`, add the Git `bin` directory to your user
`Path`. The default directory is `C:\Program Files\Git\bin`. Quit and restart
Claude Desktop after updating `Path`.

## Related

- [Editor and app integrations](index.md) — how SSH access works and how to
  set it up
- [Claude Code](../agents/claude-code.md) — run the Claude Code CLI inside a
  sandbox


---

# Connect Cursor to a sandbox

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes SSH" >}}

Cursor is built on VS Code, so it connects to a sandbox the same way, using
Remote - SSH. Your editor stays on your host while files, terminals, and
extensions run in the isolated sandbox.

> [!NOTE]
> This page covers the Cursor editor connecting to a sandbox over SSH. To run
> the Cursor agent CLI inside a sandbox instead, see
> [Cursor agent](../agents/cursor.md).

## Prerequisites

- SSH access set up. See [Editor and app integrations](index.md#enable-ssh-access).
- Cursor's Remote - SSH support installed.

## Connect

Confirm that you can connect to the sandbox from a terminal:

```console
$ ssh demo.sbx
```

1. Open the Command Palette and run **Remote-SSH: Connect to Host**.
2. Enter the sandbox host manually as `<name>.sbx`.
3. Cursor opens a new window connected to the sandbox. Use the remote folder
   picker to [select the mounted workspace](index.md#select-the-workspace-folder).

## Notes

- The first connection installs the editor server inside the sandbox, so it
  can take a moment. Later connections are faster.

## Related

- [Editor and app integrations](index.md) — how SSH access works and how to
  set it up
- [Cursor agent](../agents/cursor.md) — run the Cursor CLI inside a sandbox


---

# Connect T3 Code to a sandbox

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes SSH" >}}

T3 Code's SSH integration lets the desktop app drive coding agents inside a
sandbox. T3 Code has no dedicated Docker Sandboxes integration — it treats the
sandbox as an ordinary SSH host, connects to it, and starts a T3 server inside
that tunnels back to the app.

## Prerequisites

- SSH access set up. See [Editor and app integrations](index.md#enable-ssh-access).
- T3 Code installed.

The first connection installs the T3 server in the sandbox, which needs a
build toolchain. T3 depends on `node-pty`, which ships prebuilt binaries only
for macOS and Windows. On a Linux sandbox, `node-pty` compiles from source and
the build fails without `make`, `python3`, and a compiler such as `g++`.

The [`t3code` kit](https://github.com/docker/sbx-kits-contrib/tree/main/t3code)
prepares a sandbox for T3 Code: it installs the build toolchain and the `t3`
npm package when the sandbox is created, so the first connection starts a
pre-installed server instead of building `node-pty` from source. Pair it with
any agent whose base image ships Node.js 18 or later, which all standard
agent templates do:

```console
$ sbx run claude --kit docker.io/sbx/t3code-kit:latest
```

For an existing sandbox, install the toolchain manually:

```console
$ sbx exec <sandbox> -- sudo apt-get update
$ sbx exec <sandbox> -- sudo DEBIAN_FRONTEND=noninteractive apt-get install -y g++ make python3
```

Verify the toolchain is in place:

```console
$ sbx exec <sandbox> -- sh -lc 'command -v g++ && command -v make && command -v python3'
```

A manual install lasts only until the sandbox is recreated, and the first
connection still builds `node-pty` from source. For a setup that persists,
recreate the sandbox with the [kit](../customize/kits.md) or a custom
[template](../customize/templates.md).

## Connect

Confirm that you can connect to the sandbox from a terminal:

```console
$ ssh demo.sbx
```

In T3 Code, add an SSH environment and enter the sandbox hostname, such as
`demo.sbx`, as the host. The first connection installs the T3 server inside
the sandbox unless the `t3code` kit pre-installed it, so it can take a
moment. Later connections are faster.

Then add a new project, select the SSH environment from the list, and
[choose the mounted workspace](index.md#select-the-workspace-folder) as the
project directory inside the sandbox.

## Troubleshoot a server that never becomes ready

T3 Code can fail to connect with an error like the following, wrapped here
for readability. It concatenates the connection failure with npm's install
output from inside the sandbox into a single error dialog:

```text
Could not prepare the SSH environment: ... SshCommandError: Connecting to
sandbox "sandboxes"… Remote T3 server did not become ready on
127.0.0.1:3773. npm WARN EBADENGINE Unsupported engine { package:
'ini@7.0.0', required: { node: '^22.22.2 || ^24.15.0 || >=26.0.0' },
current: { node: 'v22.22.1', npm: '9.2.0' } }
```

The `npm WARN EBADENGINE` lines warn about the transitive `ini` dependency
and are separate from the failure: npm enforces engine requirements only
when `engine-strict` is set, which is off by default, so this warning alone
still lets the install proceed.

The most common causes are a missing C++ toolchain and a full disk, and both
produce this identical error. Get npm's actual output to tell them apart:

```console
$ sbx exec <sandbox> -- sh -lc \
  'rm -rf /tmp/t3probe && mkdir -p /tmp/t3probe && cd /tmp/t3probe \
   && npm init -y >/dev/null && npm install t3@latest 2>&1 | tail -40'
```

A missing compiler fails the native `node-pty` build with `Error 127` from
`make`:

```text
npm ERR! make: g++: No such file or directory
npm ERR! make: *** [pty.target.mk:115: Release/obj.target/pty/src/unix/pty.o] Error 127
npm ERR! gyp ERR! build error
npm ERR! gyp ERR! stack Error: `make` failed with exit code: 2
```

Install the build toolchain as described in [Prerequisites](#prerequisites).

A full disk fails with `ENOSPC`, and no gyp output appears at all because npm
fails before the native build starts:

```text
npm ERR! code ENOSPC
npm ERR! nospc ENOSPC: no space left on device
```

Check free disk space:

```console
$ sbx exec <sandbox> -- df -h /
```

A sandbox can have both problems at once. Fixing one still leaves the same
top-level error, so check both the toolchain and disk space before
concluding the sandbox is ready. Free up space or install the toolchain as
needed, then reconnect.

## Troubleshoot `turn/setPermissionMode failed`

If your organization manages Claude Code with a policy file, a local T3 Code
thread can fail to start with `turn/setPermissionMode failed`. T3 Code's
default runtime mode is Full access, which maps to the Claude Agent SDK's
`bypassPermissions` mode. A managed policy that disables that mode rejects
the request.

On macOS, check whether this applies to you:

```console
$ cat "/Library/Application Support/ClaudeCode/managed-settings.json"
```

If `permissions.disableBypassPermissionsMode` is set to `disable`, switch T3
Code to a different runtime mode, such as Supervised, Auto-accept edits, or
Auto, then start a new thread. The permission mode is captured once when a
thread starts, so switching modes in an already-failing thread doesn't
recover it.

This restriction applies to the host running Claude Code, not to a sandbox.
A thread connected to a sandbox isn't subject to the host's managed policy,
so Full access works normally there.

## Related

- [Editor and app integrations](index.md) — how SSH access works and how to
  set it up


---

# Connect VS Code to a sandbox

*Sección: Ai*

{{< summary-bar feature_name="Docker Sandboxes SSH" >}}

Use the Remote - SSH extension to open a VS Code window that runs inside a
sandbox. Your editor stays on your host while files, terminals, and extensions
run in the isolated sandbox.

## Prerequisites

- SSH access set up. See [Editor and app integrations](index.md#enable-ssh-access).
- The [Remote - SSH](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh)
  extension (`ms-vscode-remote.remote-ssh`) installed in VS Code.

## Connect

Confirm that you can connect to the sandbox from a terminal:

```console
$ ssh demo.sbx
```

In VS Code, open the Command Palette and run **Remote-SSH: Connect to Host...**.
Enter the sandbox hostname, such as `demo.sbx`, manually. After VS Code
connects, use the remote folder picker to
[select the mounted workspace](index.md#select-the-workspace-folder).

For more connection options, see the VS Code instructions to
[connect to a remote host](https://code.visualstudio.com/docs/remote/ssh#_connect-to-a-remote-host).

## Notes

- The first connection installs the VS Code server inside the sandbox, so it
  can take a moment. Later connections are faster.

### Reconnect loop on macOS

Affected versions of VS Code can enter an infinite reconnect loop on macOS. If
this happens, set `remote.SSH.useLocalServer` to `false` in your VS Code user
settings:

```json
{
  "remote.SSH.useLocalServer": false
}
```

For details, see
[microsoft/vscode-remote-release#11672](https://github.com/microsoft/vscode-remote-release/issues/11672).

### SSH host key verification fails

VS Code can leave duplicate or malformed `Host *.sbx` blocks in your SSH
config after you add an SSH host. If a VS Code connection reports a
`KnownHostsCommand` error or `Host key verification failed`, remove every SSH
config block marked `docker sandboxes (managed)`, including the marker
comments:

```diff
-# >>> docker sandboxes (managed) >>>
-Host *.sbx
-    User _default_user_
-    ProxyCommand "sbx" ssh proxy %n
-    ...
-    UserKnownHostsFile "~/.ssh/sbx_known_hosts"
-    KnownHostsCommand "sbx" ssh known-hosts %H
-    StrictHostKeyChecking yes
-# <<< docker sandboxes (managed) <<<
```

Then regenerate the managed block:

```console
$ sbx setup ssh
```

Reconnect to the sandbox from VS Code.

## Related

- [Editor and app integrations](index.md) — how SSH access works and how to
  set it up


---

# MCP gateway

*Sección: Ai*

Docker Sandboxes includes an MCP gateway for connecting agents to Model Context
Protocol servers. The gateway gives the agent inside the sandbox one MCP
endpoint, while `sbx` manages the registered servers, OAuth credentials, and
sandbox lifecycle on the host.

This is different from configuring an MCP server directly in an agent such as
Claude Code. Direct MCP setup configures that agent's own MCP client. With
Docker Sandboxes, you register MCP servers once on the host, and the sandbox
gateway exposes them to supported agents inside isolated sandboxes. That
host-managed gateway provides a single path for credentials, explicit server
loading, live updates, and organization governance.

> [!NOTE]
> The Docker Sandboxes MCP gateway is separate from the Docker Desktop MCP
> Toolkit. You don't need the Docker Desktop MCP Toolkit to use `sbx mcp`, and
> MCP Toolkit server settings aren't shared with Docker Sandboxes.

## Prerequisites

- Sign in with `sbx login`.
- Use an agent integration that configures MCP at startup: Claude Code, Codex,
  Devin, Gemini, Kiro, or OpenCode.
- For remote servers that require OAuth without Dynamic Client Registration,
  register an OAuth client with the server provider.
- For `--local --url` registrations that resolve to OCI packages, use a host
  with Docker installed and running. Docker is also required for explicit
  `--command docker ...` registrations.

## Quick start

Start by registering one MCP server on the host:

```console
$ sbx mcp add notion --url https://mcp.notion.com/mcp
```

If the server requires OAuth, `sbx` opens an authorization flow before it stores
the registration. After registration, verify that the server is registered:

```console
$ sbx mcp ls
NAME                 TYPE     URL/COMMAND
notion               remote   https://mcp.notion.com/mcp
```

Then start a sandbox and expose the registered server:

```console
$ sbx run claude --name mcp-demo --static-mcp notion
```

The sandbox starts with an MCP gateway and pre-loads the `notion` server. The
registration remains on the host and can be reused by other sandboxes.

## Register an MCP server

`sbx mcp add` registers an MCP server by name. The registration records the
server definition on the host. It doesn't attach the server to a sandbox by
itself. To expose a registered server to a sandbox, pass it with
[`--static-mcp`](#use-static-mode) when you create the
sandbox, or use [`sbx mcp load`](#add-a-server-to-a-running-sandbox) for a
sandbox that's already running.

Server names can contain letters, numbers, dots, hyphens, and underscores.

The `--url` flag can point to different kinds of input. The execution location
depends on what you register:

- A remote endpoint URL identifies a running MCP server. The server runs
  remotely, and the sandbox gateway connects to it.
- A metadata URL with `--local` returns a registry entry, `server.json`, or
  `server.yaml` that describes an OCI-packaged stdio server. `sbx` resolves the
  image and runs it on the host with Docker.
- An explicit command runs on the host as a stdio MCP server.

Local stdio servers run on the host, not inside the sandbox. The agent inside
the sandbox connects only to the MCP gateway.

If a `--url` hostname resolves to a private, loopback, link-local, or cloud
metadata address, `sbx` registers the server but warns you about the resolved
address. Register only URLs you trust. Fetching a manifest from an untrusted
URL can expose internal services or cloud metadata, and DNS rebinding can
redirect a hostname after it has been checked. For a trusted internal server,
pass `--skip-ssrf-check` to suppress the check and warning.

### Remote endpoint URL

For a remote MCP endpoint, pass the server URL:

```console
$ sbx mcp add notion --url https://mcp.notion.com/mcp
$ sbx mcp add linear --url https://mcp.linear.app/mcp
```

### Local stdio server

Some MCP servers communicate over stdio instead of exposing a remote HTTP
endpoint. Use a local stdio server when `sbx` should launch the MCP server on
the host. You can provide a metadata URL or an explicit command.

#### From registry or manifest metadata

Use `--local --url` when you have an MCP community registry URL or a URL that
returns a `server.json` or `server.yaml` document. The registry entry or
manifest must describe an OCI package that uses stdio transport. `sbx` doesn't
launch non-OCI package types, such as `npm`, from metadata. To use those
servers, register an explicit command.

This path resolves the image from the metadata and starts it on the host with
Docker, so Docker must be installed and running on the host.

```console
$ sbx mcp add fetch --local \
  --url https://registry.modelcontextprotocol.io/v0/servers/fetch-mcp/versions/latest
```

If the entry doesn't publish an OCI stdio package, `sbx` rejects the
registration instead of starting it locally.

A server manifest describes the MCP server package and how to start it. It can
be hosted on a GitHub raw URL, internal HTTP server, or CDN.

```console
$ sbx mcp add opine --local --url https://example.com/mcp/opine/server.yaml
```

#### From an explicit command

Use `--command` when you already know the executable and arguments, or when you
need custom Docker flags. The command can be a package runner such as `npx` or
a Docker container command:

```console
$ sbx mcp add playwright --command npx --args @playwright/mcp@latest
$ sbx mcp add local-image-server --command docker \
  --args "run,-i,--rm,your/image"
```

To set the working directory for the host process, pass `--dir`. This flag is
only valid with `--command`:

```console
$ sbx mcp add local-fs --command node --args server.js --dir /srv/data
```

Use registry or manifest metadata when you have a published server definition
and don't need to customize `docker run`. Use `--command` for local
development, private servers, or custom container flags.

> [!WARNING]
> Local stdio servers run on the host, outside sandbox isolation. If the command
> starts a Docker container, that container uses host Docker isolation, not
> sandbox isolation. The process or container can access host files, host
> network resources, and credentials made available to it. Use trusted commands
> and images, and avoid mounting host paths or passing credentials unless the
> server needs them.

## Authorize OAuth-backed servers

If a registered remote server requires OAuth, `sbx mcp add` starts the
authorization flow by default:

```console
$ sbx mcp add notion --url https://mcp.notion.com/mcp
Resolving MCP server "notion"...
Open this URL to authorize MCP server "notion":
https://api.notion.com/v1/oauth/authorize?...
MCP server "notion" authorized
MCP server "notion" registered (type: remote)
```

OAuth credentials stay on the host. In local gateway mode, `sbx` stores tokens
in the host operating system's credential store.

To register an OAuth-backed server without authorizing it, pass `--skip-auth`:

```console
$ sbx mcp add notion --url https://mcp.notion.com/mcp --skip-auth
```

### Use a pre-registered OAuth client

In local gateway mode, you can register a remote OAuth server that doesn't
support Dynamic Client Registration. If the server publishes OAuth metadata,
pass the client ID that you registered with the server provider:

```console
$ sbx mcp add slack --url https://slack.example.com/mcp \
  --client-id <CLIENT_ID>
```

If the server doesn't publish OAuth metadata, pass
`--oauth-authorization-server` with the client ID. The flag accepts a local
file path or an HTTP or HTTPS URL to an RFC 8414 authorization server metadata
document. The document must define `authorization_endpoint` and
`token_endpoint`:

```console
$ sbx mcp add serverx --url https://mcp.serverx.example/mcp \
  --oauth-authorization-server ./serverx-authorization-server.json \
  --client-id <CLIENT_ID>
```

These flags are only valid with `--url`.

For a confidential OAuth client, store the client secret before registering
the server. There is no `--client-secret` flag:

```console
$ sbx secret set mcp:slack.client_secret
$ sbx mcp add slack --url https://slack.example.com/mcp \
  --client-id <CLIENT_ID>
```

The client secret stays in the encrypted host credential store and isn't
written to the MCP registration. If the server requires a confidential client
and no secret is stored, registration succeeds but authorization is skipped.
Store the secret, then run `sbx mcp auth <server>`.

### Set OAuth scopes

Use the repeatable `--scope` flag to record the default scopes requested during
authorization:

```console
$ sbx mcp add serverx --url https://mcp.serverx.example/mcp \
  --scope read --scope write
```

The `sbx mcp auth` command accepts `--scope` to override the recorded defaults
for one authorization:

```console
$ sbx mcp auth serverx --scope read
```

Unless you pass `--no-scope`, `sbx` requests the first available scope set in
the following order:

1. Scopes passed to `sbx mcp auth --scope`
2. Default scopes recorded by `sbx mcp add --scope`
3. Scopes that the protected resource says it requires

If none of these provide a scope set, `sbx` omits the OAuth `scope` parameter so
the authorization server applies its default grant. The authorization server's
full advertised scope set is never requested automatically.

Pass `--no-scope` to suppress both the recorded defaults and the resource's
required scopes for one authorization:

```console
$ sbx mcp auth serverx --no-scope
```

You can't combine `--no-scope` with `--scope`. If the authorization server
advertises supported scopes, each scope you choose must be in that set. The
authorization server can still refuse an advertised scope for a particular
client. For a local authorization flow, `sbx` lists the requested, advertised,
and refused scopes and suggests a retry command. If the server identifies the
refused scopes, the command removes them. Otherwise, it uses `--no-scope`.
`sbx` never retries automatically.

For each OAuth-backed remote server exposed to a sandbox, the gateway exposes a
helper tool named `<server>-authorize`, such as `notion-authorize`. The agent can
call the tool to authorize or reauthorize the server. If the server isn't
authorized, the helper is the only tool exposed for that server.

You can manage OAuth credentials from the host:

```console
$ sbx mcp auth status notion
$ sbx mcp auth notion
$ sbx mcp auth rm notion
```

Use `--all` to apply `auth`, `auth status`, or `auth rm` to all registered
OAuth-backed servers. The `auth status` output reports the scopes granted by the
authorization server, the defaults recorded with `sbx mcp add --scope`, and the
scopes the server supports. It collapses duplicate scope names and highlights
granted scopes that weren't requested or are no longer in the supported set.
Use `--json` for machine-readable output:

```console
$ sbx mcp auth status notion --json
```

## Choose an MCP mode

Every sandbox starts an MCP gateway. When the sandbox starts, supported agent
integrations read the gateway URL and register it with the agent.

Whether you pass `--static-mcp` when you create the sandbox determines its MCP
mode:

- Static mode pre-loads the specified servers and doesn't expose dynamic
  discovery tools to the agent.
- Dynamic mode pre-loads no servers and lets the agent find and attach
  registered servers.

This choice persists across sandbox restarts.

### Use static mode

Pass `--static-mcp` to pre-load registered MCP servers:

```console
$ sbx mcp add notion --url https://mcp.notion.com/mcp
$ sbx mcp add linear --url https://mcp.linear.app/mcp
$ sbx run claude --name my-session --static-mcp notion,linear
```

You can pass `--static-mcp` as a comma-separated list or repeat the flag:

```console
$ sbx run claude --name my-session \
  --static-mcp notion --static-mcp linear
```

Every name in the static set must already be registered with `sbx mcp add`. The
gateway doesn't expose `mcp-find`, `mcp-add`, or `mcp-config-set` to the agent.

You can't replace the initial set by passing `--static-mcp` when reconnecting to
an existing sandbox. To attach another server from the host, use
[`sbx mcp load`](#add-a-server-to-a-running-sandbox).

### Use dynamic mode

Omit `--static-mcp` to use dynamic mode. The gateway pre-loads no servers and
exposes `mcp-find`, `mcp-add`, and `mcp-config-set` to the agent. The agent can
search the registered server catalog and attach servers during the session.

If you run `sbx mcp add` after a dynamic sandbox starts, its gateway refreshes
the searchable catalog. The agent can then find and attach the new registration
without restarting. The `sbx mcp add` command doesn't attach the server by
itself.

## Add a server to a running sandbox

To attach an already-registered server to a running sandbox, use
`sbx mcp load`. This works in both static and dynamic modes:

```console
$ sbx mcp add linear --url https://mcp.linear.app/mcp
$ sbx mcp load linear --sandbox my-session
MCP server "linear" loaded into sandbox "my-session" (live)
```

Connected agent sessions receive a tool-list update, so the added tools become
visible without reconnecting. The loaded server remains attached across sandbox
restarts.

## Built-in gateway tools

The local MCP gateway exposes a small set of built-in tools. These tools belong
to the gateway itself, not to a registered MCP server. Agents can see and call
them on the same MCP connection as server tools, so they can appear in agent
tool lists, logs, policy decisions, audit logs, or approval prompts.

You don't need to call these tools directly for normal setup. Use `sbx mcp`
commands to register servers and manage credentials from the host. The tools
matter because agents can call them during a session, and admins can govern
them separately from tools provided by registered MCP servers.

| Tool                 | Description                                                                                |
| -------------------- | ------------------------------------------------------------------------------------------ |
| `mcp-exec`           | Executes a tool by name through the gateway.                                               |
| `code-mode`          | Creates an ephemeral JavaScript tool that can call selected tools through the MCP gateway. |
| `mcp-find`           | Searches the registered server catalog without changing sandbox state. Dynamic mode only.  |
| `mcp-add`            | Attaches a registered server to the sandbox. Dynamic mode only.                            |
| `mcp-config-set`     | Sets per-session configuration overrides for an attached server. Dynamic mode only.        |
| `<server>-authorize` | Starts or restarts OAuth authorization for an exposed OAuth-backed remote server.          |

Servers attached with `mcp-add` remain attached across sandbox restarts. The
gateway exposes `<server>-authorize` for OAuth-backed remote servers, even when
they already have a valid token. Local stdio servers don't expose this helper.
If `code-mode` creates a generated tool, the tool is shared by clients connected
to the sandbox's gateway and disappears when the gateway is replaced or stops.

In MCP access policies, built-in gateway tools are `MCP::Primordial` resources
and use the `invokePrimordial` action. Tools from registered MCP servers are
`MCP::Tool` resources and use the `invokeTool` action. For details, see the
[MCP policy reference](governance/reference/mcp-policy.md).

## Manage registrations

List registered servers:

```console
$ sbx mcp ls
```

Inspect a registered server:

```console
$ sbx mcp inspect notion
```

Remove a registered server:

```console
$ sbx mcp rm notion
```

For OAuth-backed servers, `sbx mcp rm` removes the OAuth access token before it
removes the server registration. A client secret for a pre-registered OAuth
client and its identity binding remain in the host credential store so you can
reuse them when you re-add the same client. The command prints the
`sbx secret rm` commands for removing them. To remove only the OAuth access
token, use `sbx mcp auth rm`.

## Governance

Organizations with AI Governance can use
[MCP access policies](governance/access-controls/mcp.md) to control MCP server
registration, tool calls, gateway meta-tools, resources, prompts, and approval
requirements. MCP access policies are organization policies written in Cedar.


---

# Docker Sandboxes release notes

*Sección: Ai*

This page lists changes in recent stable releases of Docker Sandboxes. For
the full release history, including pre-releases and downloads, see the
[Docker Sandboxes releases on GitHub](https://github.com/docker/sbx-releases/releases).

<!-- BEGIN GENERATED RELEASES -->

## 0.42.1

{{< release-date date="2026-09-07" >}}

[GitHub release](https://github.com/docker/sbx-releases/releases/tag/v0.42.1)

### What's New

#### Bug Fixes

- Fix HTTP/2 upstream responses without bodies being incorrectly framed as chunked by the sandbox proxy.

## 0.42.0

{{< release-date date="2026-09-07" >}}

[GitHub release](https://github.com/docker/sbx-releases/releases/tag/v0.42.0)

### Highlights

- BREAKING: `sbx ports --publish` and kit-declared ports now default to `tcp4` instead of dual-stack `tcp`, so a published port no longer listens on `::1` unless you name the protocol explicitly (`--publish 8080:3000/tcp`); this makes `http://localhost:<port>/` reach a sandbox service that listens only on IPv4.
- `sbx run` and `sbx create` now accept sandbox kit references as the agent positional: `sbx run <sandbox-kit-ref>`. The old form `sbx run <sandbox-kit-name> --kit <sandbox-kit-ref>` is deprecated; use the `--kit` flag for mixins.
- Sandboxes can now be created without a workspace bind mount by omitting the path in `sbx create`. Note that this only affects the `create` command; `sbx run` still defaults to mounting the current directory as the primary workspace.

### What's New

#### CLI

- Read-only `sbx` commands including `secret ls`, `version`, `mcp ls`, `skills ls`, `policy inspect` and the `kit` verification commands now accept `--json` for machine-readable output.
- Clipboard commands inside local sandboxes can now copy text to the host clipboard.
- Add, update, list, and remove sandbox skills directly from Git repositories with `sbx skills`.

#### Environment files

- `sbx env` now reads a non-hidden `sbxenv.yaml` from a project directory and no longer falls back to a hidden `.sbxenv.yaml` there; it merges a `.sbxenv.yaml` from your home directory beneath the project file as defaults shared across projects.
- `sbx env` now shows a plan of everything an environment file changes on the host — host `lifecycle:` commands, credentials, bindings, MCP servers, workspaces, kits, ports and the sandbox itself — asks before applying it and asks again for every run of a command on this machine unless `env.rememberHostCommands` is set, binds the environment file read-only into the sandbox it describes, and reads a directory for `sbxenv.yaml` alone with `~/.sbxenv.yaml` as the user-level base beneath it.
- `sbx env`: an environment file that declares no `workspace:` now creates a sandbox with no workspace bind mount instead of mounting the directory holding the file; write `workspace: .` to mount the project directory.
- Environment files can now declare their own arguments in an `args:` block, referenced as `${{ env.args.NAME }}` and supplied with `sbx env --env-arg`; `${VAR}` interpolation in `.sbxenv.yaml` is no longer expanded.
- Relative kit paths in an environment file now resolve against the file's directory instead of the directory `sbx` was run from.
- `sbx env create` now shares imported skills by default and accepts display, GPU, and USB options in `sbxenv.yaml`.

#### Daemon

- Sandboxes now get a 10 GB Docker volume instead of 50 GB, which significantly reduces host disk usage; set `DOCKER_SANDBOXES_DOCKER_SIZE` to change it.

#### Agents

- Added Devin as a built-in agent.

#### Kits

- Kits can now declare their arguments in an `args:` block and receive values with `--kit-arg name=value`, or `--kit-arg kit.name=value` to target a single kit.
- A `kits:` entry in sbxenv.yaml carries the arguments for that kit under `kits[].args`.

#### Bug fixes

- Docker Sandboxes no longer opens the setup wizard automatically; run `sbx setup` to launch it explicitly.
- Fixed a vulnerability where a sandboxed process could get the daemon to open a host D-Bus transport and execute an arbitrary command on the host.
- On macOS, sbx now accepts a workspace path whose casing differs from the spelling on disk instead of failing to create the sandbox.
- Fixed a rare case where a spotty network right after your computer woke
from sleep could cause an unexpected Docker Hub sign-out.
- Agent crashes now identify the terminating signal and provide scoped recovery guidance.
- Fixed a vulnerability where a malicious sandbox could hijack another sandbox's OAuth login by pre-claiming its callback port.
- Removing or pruning a local sandbox now also deletes its sandbox-scoped secrets.
- `sbx secret ls` no longer prints a stored secret unmasked when its value happens to match one of the status labels the listing displays.
- `sbx` now warns when a stored credential is not sent to a sandbox because no binding authorizes it, instead of starting the sandbox and failing later with an authentication error.
- Fixed several MCP-related bugs.
- Standardized error message formatting for `sbx rm`, `sbx stop`, MCP authorization, and `sbx reset`.
- Sandbox and agent not-found errors now use one sentence pattern and quote style across commands: sandbox '<name>' not found.
- Docker Hub template pulls created through the TUI now use your Docker Sandboxes login credentials.
- `sbx ports --publish` now automatically starts stopped local sandboxes before publishing ports.
- Docker volume sizes below 512 MiB are now rejected before sandbox creation.
- Creating a sandbox from a Docker Hardened Image template no longer results in a delay.
- Fixed OAuth authentication for custom agent kits that declare resource hosts without a fallback API key.
- Kits can now set a sandbox's CPU and memory limits through the `sandbox.resources` block in their spec.
- Fixed SSH connections from editors by keeping non-interactive probes quiet and delivering their exit status before closing the channel.
- Deleting a sandbox now reliably reclaims its disk volumes, and creating a new sandbox that reuses a deleted sandbox's name no longer inherits its files, Docker images, or agent session history.
- Running `sbx setup` explicitly no longer causes the setup screen to appear again on the next interactive command.
- Fixed sandbox connections to a server that sends data first — including passive FTP transfers and a serial console relayed to the host — failing with a timeout instead of receiving the server's output.
- `sbx kit push` no longer uploads an empty payload layer for kits that ship no files.
- `sbx kit push` now authenticates from the sbx credential store, so a single `sbx login` or `docker login` is enough for pushing, signing, and attaching provenance.
- Kits using `extends:` now inherit the parent's setup commands, credentials, network allowlist, volumes, and environment variables instead of replacing them when the child declares its own.
- Fixed Docker Hub credential refresh retrying without backoff after a rate limit, and a non-interactive login discarding the stored OAuth refresh token.
- Nightly Homebrew installs no longer fail with checksum mismatches while a nightly publish is in flight: the sbx@nightly cask now downloads from immutable per-build release URLs.

#### Other

- Docker Sandboxes now provides a machine-wide Windows MSI for administrator-managed installations.
- A declined `@requireApproval` prompt on a local MCP server now gets its own audit record, with policy attribution and a context digest, instead of leaving the original approval-required decision as the only trace of the exchange.
- A registry mirror configured with `platform.images.registryMirror` is now also used by Docker running inside a sandbox, when the value is a bare host (no path prefix) that is not a loopback or wildcard address.
- `sbx version --json` now reports a `server.state` of `running` or `unavailable`, so scripts can check whether the backend was reachable without parsing the error text.
- SSH agent forwarding can be explicitly disabled and use either each client's current agent socket or a fixed socket path.
- `sbx` terminal output now adapts colors for light terminal backgrounds and
uses a distinct pink spinner glyph; CJK and combining-mark column widths in
table output are now measured correctly; piped and JSON output is unchanged
for ASCII-only content.
- `sbx mcp add` now accepts `--skip-auth` (the old `--skip_auth` still works), and a `--url` on a private, loopback, or cloud-metadata address is resolved and registered with a warning instead of being rejected.
- On Linux hosts without an available OS keychain, newly stored secrets are now read and written much faster; secrets already on disk keep their previous cost until they are next written.
- Fixed a gateway defect where a remote MCP server's reconnect could silently wipe its tool routing, causing the server's tools to disappear from agents and be denied by organization MCP policy as unrecognized built-in tools until the daemon was restarted.
- Docker Sandboxes can now upload a diagnostics bundle automatically when the daemon hits an error, after you opt in.
- Governance resolution issues are now shown in sbx policy output and the dashboard.
- `sbx mcp auth` now requests only the scopes you chose (or the set the resource itself requires, suppressible with the new `--no-scope` flag) instead of every scope a server advertises, explains which scopes a server refused along with a narrower retry command, and reports the scope sets of an existing grant in `sbx mcp auth status`: what was granted, what was requested, and what the server supports — with scopes sorted, duplicates collapsed, and differences such as unrequested or no-longer-advertised grants called out.
- Sandbox listing and creation output now share one rendering package; on a terminal, `sbx ls` column headers are now styled bold.
- Sandbox agent instruction files no longer include generic language-specific development guidance.
- The sandboxd runtime state directory left behind by versions before v0.25.0 is now migrated to its current name instead of being used in place.

## 0.39.0

{{< release-date date="2026-08-19" >}}

[GitHub release](https://github.com/docker/sbx-releases/releases/tag/v0.39.0)

### Highlights

**Declarative sandbox environments.** Define a complete, reproducible sandbox in a `.sbxenv.yaml` file, including the agent, workspace, kits, environment variables, secrets, registry credentials, ports, and resource limits. Commit the file with your project so contributors can launch the same environment with `sbx env run`. This feature is experimental.

### What's New

#### Sandbox environments

- Use `sbx env run` to provision an environment from `.sbxenv.yaml` and open an interactive session.
- Use `sbx env create`, `sbx env exec`, and `sbx env rm` to manage the environment lifecycle.
- Combine multiple environment files for shared configuration and local overrides.
- Reference host environment variables in environment files for machine-specific paths and credentials.
- See the [sandbox environment files documentation](https://docs.docker.com/ai/sandboxes/sandbox-environments/).

#### CLI

- Add an experimental `--usb` flag to `sbx create` behind the `DOCKER_SANDBOXES_FEATURE_SANDBOX_USB` environment variable to re-attach the specified USB devices. They will be available inside a sandbox via usbfs. Linux x86_64/ARM64 only.
- sbx run --model now selects the Ollama backend via a new `--provider ollama` flag instead of an `ollama/` prefix on the model name.
- Stopped sandboxes can now be cleaned up in bulk with `sbx prune`, which never removes a running sandbox and can filter on how long each has been stopped.
- `sbx run` and `sbx create` now accept `-e`/`--env` and `--env-file` to set environment variables in a sandbox, following `docker run` precedence rules.

#### Secrets

- `sbx secret set` and `sbx secret set-custom` can now configure dynamic secrets that resolve values from a reference or command, with options to control refreshing, verification, and error output.
- On Linux hosts without an available OS keychain, newly stored secrets are now read and written much faster; secrets already on disk keep their previous cost until they are next written.

#### Daemon

- Sandboxes now expose their own identity as `SANDBOX_NAME` and `SANDBOX_ID` environment variables, matching the name and id shown by `sbx ls --json`; the older `SANDBOX_VM_ID` still carries the sandbox name but is deprecated.

#### Networking

- Claude Code's `/remote-control` can now be used inside sandboxes by enabling `claude.remoteControl` setting: `sbx settings set claude.remoteControl true`.

#### Bug Fixes

- sandboxd now removes the sandbox container immediately when container startup fails, so an interrupted `sbx create`/`sbx run` is less likely to leave the sandbox name unusable.
- Agent kits that declare a persistent volume without a size now get a 512 MB volume instead of a 50 GB one, which significantly reduces sandbox disk usage on the host.
- `sbx` now reports a clear error for an unrecognized command, subcommand, or `sbx help` topic instead of printing help and succeeding, and reports a mistyped command without first asking an unauthenticated user to sign in.
- Claude sandboxes now use around 3.9 GB less disk space on the host.
- Claude sandboxes can connect to required Anthropic services when using the locked-down network policy.
- `sbx kit inspect` now describes kits using kit-spec v2 field names and lists any deprecated fields a kit still relies on, and `sbx kit validate` now rejects OAuth credentials missing sentinels, a service, or a credential-file body.
- DNS lookups in a sandbox now succeed for any host that network policy allows on any port, including hosts allowed only on a non-standard port such as `myhost:2222`.
- `sbx template load` now fails with an error when an image import does not complete, instead of reporting success.
- Correct the `sbx create --name` help text and CLI reference, which incorrectly listed plus signs as valid sandbox-name characters and omitted the leading-alphanumeric and two-character-minimum rules.
- `sbx reset` now removes the Docker Sandboxes-managed block from `~/.ssh/config`.
- `sbx` now reports the exit code when a sandbox container dies at startup, and rejects a template image built for a different CPU architecture with a clear message instead of failing after a 30-second wait.
- Signing in to Claude Code with an Anthropic Console API key now succeeds on repeat logins instead of failing with a 401 error.
- Fixed `sbx cp` failing on Windows when the local path has no directory component (e.g. `sbx cp file.txt sandbox:/tmp/`).
- `sbx daemon restart` now starts the daemon again after a stop that reports a failure but leaves no daemon running.

#### Other

- `sbx diagnose` now reports free disk space on the volume holding sandbox data, and diagnostics bundles include host disk totals.
- `sbx diagnose` now detects broken, shadowed, or stale SSH client configuration.
- Add a `platform.images.registryMirror` setting that redirects Docker Hub-resolving sandbox template and kit images to an organization's registry mirror.
- Filesystem policy denials now include the organization's support contact message, matching network denials.
- sbx now reports when the host cannot provide a hypervisor — including a Windows installation running inside a virtual machine without nested virtualization — instead of a generic "failed to run sandbox container" error, and `sbx diagnose` now checks host virtualization support.
- Kits can now be signed and verified with cosign-compatible Sigstore signatures via `sbx kit sign` / `sbx kit verify`, with optional policy enforcement at load time.
- OAuth kits can declare their credential file with the declarative `credentialFile.structure` form, rendered to well-formed JSON, instead of a free-form Go template.
- Ubuntu 25.10 packages are no longer published; Ubuntu 25.10 is end-of-life.

## 0.38.0

{{< release-date date="2026-08-06" >}}

[GitHub release](https://github.com/docker/sbx-releases/releases/tag/v0.38.0)

### Highlights

**Kit spec v2.** A new schema is available for authoring kits, with a clearer structure for setup, permissions, agent instructions, networking, and credentials. Use `schemaVersion: "2"` for new kits; existing v1 kits continue to load through the legacy path. See the [kit spec reference](https://docs.docker.com/ai/sandboxes/customize/kit-reference/#schema-versions) for migration details.

**MCP management is now a first-class feature.** Register remote or local MCP servers once with `sbx mcp`, then reuse them across supported agents and sandboxes through a built-in MCP gateway. OAuth credentials stay on the host, and organizations can govern server registration and tool calls with Cedar policies. See the [MCP gateway documentation](https://docs.docker.com/ai/sandboxes/mcp-gateway/).

### What's new

#### CLI

- `sbx create` and `sbx run` show detailed structured progress during startup, including environment files loaded, resources provisioned, and each kit command's outcome; kit-install progress streams live during `sbx create --kit`.
- Added `sbx daemon restart` to stop and restart the sandboxd daemon in the background.
- `sbx inspect` now displays custom secrets configured for a sandbox.
- `DOCKER_SANDBOXES_CLONED_WORKSPACE_SIZE` configures the size of the cloned workspace volume.
- `sbx setup ssh` warns when `ssh` is missing from PATH, and on Windows when `sh` (required by Claude Desktop's SSH ProxyCommand) is missing.
- Port publishing failures now identify the affected host port and explain when the OS requires extra daemon privileges.

#### MCP

- The `sbx mcp` subcommand is now available for managing MCP servers.
- Includes dynamic MCP tools (`mcp-find`, `mcp-add`, `mcp-config-set`) for attaching registered servers to sandboxes.
- Govern MCP servers and tools for your organization using Cedar policies.

#### Networking & policy

- `--deny-network HOST` on `sbx run` and `sbx create` records per-sandbox network deny rules at creation time, with layer-aware egress messages.
- `sbx policy allow network` reports a clear "managed by your organization" error when org governance overrides the local allow, and failed rule removals now explain what went wrong using a single rule identifier.
- Signing in refreshes organization policies in the running daemon immediately instead of waiting for the next polling interval.
- IP-literal destinations denied by a CIDR rule fail fast with a policy message instead of timing out.
- Blocked HTTPS proxy connections appear in `sbx policy log` even when the client aborts the TLS handshake.

#### Secrets & credentials

- Service and custom secrets are global by default, with `--sandbox` for sandbox scope; legacy positional and `--global` forms are deprecated with warnings.
- Sandbox-scoped GitHub credentials added after creation now work without recreating the sandbox.
- Pressing Ctrl+C while entering a secret cancels the command without saving it.

#### Agents

- Docker Agent and OpenCode sandboxes can authenticate GitHub Copilot requests with proxy-managed GitHub credentials.
- Codex sandboxes created from the TUI prefer stored OpenAI OAuth credentials over API keys; kit environment variables now reach cloud agents, and git no longer hangs Codex startup prompting for credentials.
- Shared agent skills: directory symlinks under the skills folder are resolved and their contents imported.

#### Kits & templates

- Kit specs use the new v2 grammar.
- Kits using `extends` correctly inherit and override the base image or build source of their parent.
- Kit install commands can consume static files from `files/home`, including binary files.

#### Packaging

- Homebrew installs from a stapled `.dmg` artifact rather than a `.tar.gz` archive, improving Gatekeeper compatibility on macOS.
- Windows: the running sandboxd daemon is stopped during a WinGet/MSI upgrade so client and server end up on the same version.

#### Security

- Claude Desktop SSH sessions no longer expose Desktop OAuth access tokens inside sandboxes.
- Fixed a destination-escape flaw in `sbx cp` copy-out (CVE-2026-17106).
- The daemon's loopback egress proxy only serves the daemon's own traffic, preventing other local users on a multi-user host from reaching the configured upstream proxy through it.

#### Bug fixes

- Fixed a hang where sandboxd stopped answering all endpoints and could not be stopped without SIGKILL after a crash; fatal daemon tracebacks are now included in `sbx diagnose --upload` bundles.
- Fixed intermittent sandboxd startup failures when a running daemon was slow to answer its health check.
- Fixed `sbx daemon stop` hanging when an idle SSH session (for example, Claude Desktop) was connected to a sandbox.
- sandboxd automatically repairs a corrupted local image cache by re-pulling the image, and otherwise reports a clear "run `sbx daemon reset`" error.
- Fixed recreate failures ("base image not found") after daemon restarts when swapping a sandbox's container via `sbx kit add`; recreates self-heal by recomposing from the sandbox's template.
- Fixed reverse DNS (PTR) lookups from sandboxes returning NXDOMAIN for container-resolved addresses.
- Fixed a goroutine and network-endpoint leak from hijacked HTTP CONNECT tunnels that could eventually stall sandbox creation after many delete/recreate cycles.
- Fixed an intermittent 500 error when deleting a sandbox while its network endpoints were being torn down.
- The daemon restores saved sandboxes' network proxies in parallel on restart, speeding up startup with several sandboxes and fixing a potential crash during first-run policy application.
- Fixed host `.git/config` corruption when creating a sandbox for repositories using `includeIf` directives in `~/.gitconfig`; the sandbox now writes git identity only to the container's gitconfig.
- `sbx skills` shows a single usage form and clearer help for importing shared agent skills.
- sbx no longer reports that a stored credential was not injected when the daemon injects it.

### Experimental features

#### Enterprise networking

Settings-driven upstream-proxy configuration with separate sandbox and daemon scopes, integrated NTLM/Kerberos proxy authentication on Windows.

- Configure separate proxy settings for sandbox and daemon traffic using `proxy`, `proxy.sandbox`, `proxy.daemon`, and the matching `no_proxy` settings. These default to the host operating system's proxy settings. The daemon's own traffic, including image pulls and telemetry, also uses the configured proxy.
- On Windows, sbx can authenticate to upstream proxies that require integrated NTLM or Kerberos/Negotiate authentication. Enable this behavior with the `proxy.integratedAuth` setting.
- If a TLS-inspecting proxy issues certificates with negative serial numbers, enable compatibility with `sbx settings set tls.allowNegativeSerial true`, then restart the daemon.

#### GPU passthrough

Run a sandbox with NVIDIA VFIO GPU passthrough on Linux using `sbx run --gpu`. Enable this feature with `sbx settings set feature.sandbox-gpu true`.

#### Local models

Run Claude Code against a local GGUF model with `sbx run --model <name> claude`. To use a model from an existing Ollama installation, prefix the model name with `ollama/`. See [Claude Code > Use a local model](https://docs.docker.com/ai/sandboxes/agents/claude-code/#use-a-local-model).

<!-- END GENERATED RELEASES -->

## Earlier releases

For older versions, see the
[Docker Sandboxes releases on GitHub](https://github.com/docker/sbx-releases/releases).


---

# Security model

*Sección: Ai*

Docker Sandboxes run AI agents in microVMs so they can execute code, install
packages, and use tools without accessing host resources beyond those you
share. Multiple isolation layers protect your host system.

## Trust boundaries

The primary trust boundary is the microVM. The agent has full control inside
the VM, including sudo access. The VM boundary prevents the agent from reaching
anything on your host except what is explicitly shared.

What crosses the boundary into the VM:

- **Host workspace directory:** shared when you pass a workspace path or use
  `sbx run`, which defaults to the current directory. A direct mount is
  read-write, so the agent edits your working tree in place. With
  [`--clone`](../usage.md#clone-mode), your repository is mounted read-only and
  the agent works on a private clone. A mountless sandbox doesn't share a host
  workspace.
- **Credentials:** the host-side proxy injects authentication headers into
  outbound HTTP requests. The raw credential values never enter the VM.
- **Network access:** outbound TCP connections to destinations allowed by
  [network policy](defaults/) are proxied through the host.
- **Shared agent skills:** a persistent host-side store is mounted read-write
  at the agent's skills directory unless you opt out when creating the
  sandbox. Supported agents in other sandboxes mount the same store.
- **MCP gateway traffic:** supported agents connect to a host-side MCP gateway
  endpoint. The gateway brokers access to registered MCP servers.

What crosses the boundary back to the host:

- **Workspace file changes:** visible on your host in real time when you use a
  direct mount.
- **Outbound TCP connections:** sent to allowed destinations through the host
  proxy.
- **Shared skill changes:** written to the host-side store and visible to other
  sandboxes that share it.

Outside the workspace and shared skills store, the agent cannot access your
host filesystem. It also cannot access your host Docker daemon, your host
network directly, or any destination not allowed by network policy. Sandboxes
cannot communicate directly over the network. Direct external UDP and ICMP are
blocked at the network layer.

MCP servers are an explicit integration point. Remote MCP servers run outside
Docker Sandboxes, and local stdio MCP servers run on the host, not inside the
sandbox VM. An agent can invoke the tools those servers expose through the MCP
gateway, subject to MCP policies when organization governance is active. Treat
local MCP servers as trusted host integrations.

The following diagram shows a sandbox with a directly mounted workspace:

![Docker Sandbox security model](../images/sbx-security.png)

## Isolation layers

The sandbox security model has five layers. See
[Isolation layers](isolation/) for technical details on each.

- **Hypervisor isolation:** separate kernel per sandbox. No shared memory or
  processes with the host.
- **Network isolation:** outbound TCP traffic is proxied through the host and
  governed by a [deny-by-default policy](defaults/). Direct external UDP and
  ICMP are blocked.
- **Docker Engine isolation:** each sandbox has its own Docker Engine with no
  path to the host daemon.
- **Workspace isolation:** a mountless sandbox has no host workspace mount.
  Clone mode gives the agent a private in-VM clone and mounts your repository
  read-only. Direct mode shares your working tree read-write.
- **Credential isolation:** API keys are injected into HTTP headers by the
  host-side proxy. Credential values never enter the VM.

## What the agent can do inside the sandbox

Inside the VM, the agent has full privileges: sudo access, package installation,
a private Docker Engine, and read-write access to its in-sandbox filesystem and
configured workspace. Installed packages, Docker images, and other VM state
persist across restarts. See
[Default security posture](defaults/) for the full breakdown of what is
permitted and what is blocked.

## Security considerations

The sandbox isolates the agent from your host system, but the agent's actions
can still affect you through explicitly shared resources and allowed network
channels.

In direct mode, workspace changes are live on your host. The agent edits the
same files you see on your host. This includes files that execute implicitly
during normal development: Git hooks, CI configuration, IDE task configs, AI
project configuration and settings, `Makefile`, `package.json` scripts, and
similar build files. Review changes before running any modified code. Note that
Git hooks live inside `.git/` and do not appear in `git diff` output — check
them separately. See
[Workspace isolation](isolation/#workspace-isolation) for the full list and
for the alternative clone-mode boundary.

The default allowed domains include broad wildcards. Some defaults like
`*.googleapis.com` cover many services beyond AI APIs. Run `sbx policy ls` to
see the full list of active rules, and remove entries you don't need. See
[Default security posture](defaults/).

Kits run install commands with root privileges inside the sandbox. To limit
supply-chain risk, `sbx` restricts kit installs to an allowlist of sources
that defaults to Docker Hub only. See
[Restrict kit sources](../customize/kits.md#restrict-kit-sources).

Shared agent skills create a narrow exception to cross-sandbox isolation. The
store is mounted read-write, so one sandbox can modify instructions or scripts
that an agent later uses in another sandbox. This doesn't expose the rest of
the host filesystem or create a direct network path between sandboxes, but it
does put participating sandboxes in the same trust boundary. See
[Share agent skills](../workflows/agent-skills.md) for details and the
per-sandbox opt-out.

Local stdio MCP servers run outside the sandbox VM. If you register a local MCP
server that starts a host process or host Docker container, that process or
container uses host permissions and host isolation, not sandbox isolation. See
[MCP gateway](../mcp-gateway.md).

## Organization-wide control

On a single developer's machine, security and policy are configured locally —
for example, network and filesystem rules set with `sbx policy`. Admins can
move these controls to the organization level so that security, policy, and
access apply consistently across every developer's sandboxes, rather than
depending on local configuration.

See [Governance](../governance/) for the controls available to organization
admins.

## Learn more

- [Isolation layers](isolation/): how hypervisor, network, Docker,
  workspace, and credential isolation work
- [Default security posture](defaults/): what a fresh sandbox permits and
  blocks
- [Manage credentials](../configuration/credentials.md): provide and manage API
  keys while keeping their values outside the sandbox
- [Governance](../governance/): configure network, filesystem, and MCP access
  controls locally or across your organization


---

# Default security posture

*Sección: Ai*

A sandbox created with `sbx run claude` and no additional flags has the
following security posture.

## Network defaults

All outbound TCP traffic, including HTTP, HTTPS, and SSH, is blocked unless an
explicit rule allows the destination. Direct external UDP and ICMP traffic is
blocked at the network layer. DNS queries use the sandbox's internal resolver,
which enforces network policy.

Run `sbx policy ls` to see the active network rules for your installation.
Rules can be customized per machine with the `sbx policy` CLI, or managed
centrally across your organization. Org-level rules take precedence over local
rules. See
[Network access policies](../governance/access-controls/network.md).

## Workspace defaults

`sbx run` mounts the current directory when you don't pass a workspace path.
The agent can read, write, and delete any file within that directory, including
hidden files, configuration files, build scripts, and Git hooks.

When you omit the workspace path from `sbx create`, the sandbox doesn't mount a
host workspace. The agent uses the sandbox template's default working
directory. Docker-provided agent templates use `/home/agent/workspace`. If the
template doesn't define a usable absolute working directory, the daemon uses
that path. Files in this directory persist across stops and restarts and are
deleted when you remove the sandbox. See
[Workspace isolation](isolation.md#workspace-isolation) for the available
workspace modes and what to review after a direct-mount session.

## Shared skills defaults

Sandboxes for supported agents mount a persistent shared skills store
read-write by default. Every sandbox that uses the store can change skills that
other participating sandboxes may load. Use `--no-share-skills` when creating a
sandbox to keep it outside this shared trust boundary. See
[Share agent skills](../workflows/agent-skills.md).

## Credential defaults

No credentials are available to the sandbox unless you provide them using
`sbx secret` or environment variables. When credentials are provided, the
host-side proxy injects them into outbound HTTP headers. The agent cannot
read the raw credential values.

See [Credentials](../configuration/credentials.md) for setup instructions.

## Agent capabilities inside the sandbox

The agent runs with full control inside the sandbox VM:

- `sudo` access (the agent runs as a non-root user with sudo privileges)
- A private Docker Engine for building images and running containers
- Package installation through `apt`, `pip`, `npm`, and other package managers
- Full read and write access to the VM filesystem

Everything the agent installs or creates inside the VM, including packages,
Docker images, mountless workspace files, and configuration changes, persists
across stop and restart cycles. When you remove the sandbox with `sbx rm`, the
VM and its contents are deleted. Direct-mounted workspace files and the shared
skills store remain on the host, as do repositories used as clone sources.

## What is blocked by default

The following are blocked for all sandboxes and cannot be changed through
policy configuration:

- Host filesystem access outside explicitly mounted workspaces and the shared
  skills store
- Host Docker daemon
- Direct network communication between sandboxes
- Direct external UDP and ICMP connections

Outbound TCP to destinations not in the allow list is also blocked by default,
but you can add allow rules with `sbx policy allow`.


---

# Isolation layers

*Sección: Ai*

AI coding agents need to execute code, install packages, and run tools on
your behalf. Docker Sandboxes run each agent in its own microVM. Five
isolation layers protect your host: hypervisor, network, Docker Engine,
workspace, and credential proxy.

## Hypervisor isolation

Every sandbox runs inside a lightweight microVM with its own Linux kernel.
Unlike containers, which share the host kernel, a sandbox VM cannot access host
processes, files, or resources outside its defined boundaries.

- **Process isolation:** separate kernel per sandbox; processes inside the VM
  are invisible to your host and to other sandboxes
- **Filesystem isolation:** a host workspace is shared when you pass a
  workspace path or use `sbx run`, which defaults to the current directory.
  For supported agents that haven't opted out, the dedicated
  [shared skills store](../workflows/agent-skills.md) is also shared with the
  host. The rest of the VM filesystem persists across restarts but is removed
  when you delete the sandbox. Symlinks pointing outside the workspace scope
  are not followed.
- **Full cleanup:** when you remove a sandbox with `sbx rm`, the VM and
  everything inside it is deleted

The agent runs as a non-root user with sudo privileges inside the VM. The
hypervisor boundary is the isolation control, not in-VM privilege separation.

Processes in a local sandbox can write text to your host clipboard, but can't
read existing clipboard text. Host clipboard image reads are a separate,
opt-in feature. After running untrusted code, check clipboard contents before
pasting them on the host.

## Network isolation

Each sandbox has its own isolated network. Sandboxes cannot communicate
directly with each other or share a network with your host. To reach a service
running on the host through a policy-controlled connection, see
[Accessing host services from a sandbox](../workflows/development.md#accessing-host-services-from-a-sandbox).

All outbound TCP traffic passes through a proxy on your host that enforces the
[network access policy](../governance/access-controls/network.md). The sandbox
routes traffic through either a forward proxy or a transparent proxy depending
on the client's configuration. Both enforce the network policy. Only the
forward proxy [injects credentials](../configuration/credentials.md) for AI services.

Direct external UDP and ICMP are blocked at the network layer. DNS queries use
the sandbox's internal resolver, which enforces network policy. TCP connections
are allowed only when a policy rule matches the destination.

For the default set of allowed domains, see
[Default security posture](defaults.md). To forward allowed traffic through a
corporate or upstream proxy, see
[Configure an upstream proxy](../configuration/upstream-proxy.md).

## Docker Engine isolation

Agents often need to build images, run containers, and use Docker Compose.
Mounting your host Docker socket into a container would give the agent full
access to your environment.

Docker Sandboxes avoid this by running a separate [Docker
Engine](../../../engine/index.md) inside the sandbox environment, isolated from
your host. When the agent runs `docker build` or `docker compose up`, those
commands execute against that engine. The agent has no path to your host Docker
daemon.

This Docker Engine boundary applies to processes running inside the sandbox VM.
It doesn't apply to local stdio MCP servers registered through the
[MCP gateway](../mcp-gateway.md). Those servers run on the host, outside the
sandbox VM. If a local MCP server starts a Docker container, it uses Docker on
the host.

Each sandbox VM runs its own Docker Engine. The agent runs inside the VM,
alongside that engine, and drives it to create containers, all within the
VM:

```mermaid
flowchart TB
  subgraph host["Host system"]
    subgraph hostd["Host Docker daemon"]
      hc["Your containers and images"]
    end
    subgraph vm["Sandbox (microVM)"]
      a["Agent"]
      subgraph e["Sandbox Docker engine"]
        c["Containers created by agent"]
      end
      a -->|"docker build / compose up"| e
    end
  end
  style host fill:#3b82f622,stroke:#3b82f6
```

## Workspace isolation

When you create a sandbox, choose how the agent receives a workspace:

- **Mountless** (no path to `sbx create`): the sandbox doesn't receive a host
  workspace. The agent works in the sandbox's own filesystem.
- **Direct mount** (a path such as `.`): the agent has read-write access to
  your working tree. There is no boundary between the agent's edits and your
  host filesystem.
- **Clone mode** (`--clone` and a Git path): your repository is mounted
  read-only into the VM and the agent works on a private clone inside the VM.
  The agent's edits never reach your host until you fetch them.

See [Git workflows](../workflows/git.md) for direct-mount and clone-mode
workflows.

### Mountless

Omit the workspace path from `sbx create` to create a mountless sandbox, then
attach by name:

```console
$ sbx create --name scratch claude
$ sbx run --name scratch
```

The agent uses the sandbox template's default working directory.
Docker-provided agent templates use `/home/agent/workspace`. If the template
doesn't define a usable absolute working directory, the daemon uses that path.
Files there stay within the sandbox, persist across stops and restarts, and are
deleted when you remove the sandbox. A mountless sandbox doesn't expose a host
project directory, but separately configured host resources such as the shared
skills store can still be mounted.

### Direct mount

Pass a workspace path to share it into the VM as a read-write mount. The agent
and the host see the same files, and changes the agent makes appear on your
host as soon as they're written. `sbx run` mounts the current directory when
you don't pass a path:

```console
$ sbx run claude
```

Direct mounts enforce access by path. If a workspace file is a hard link to a
file outside the workspace, the agent can read and modify the underlying file
through the workspace path. Changes affect every hard link to that file,
including links outside the authorized workspace. Filesystem access policies
do not block this access because they evaluate the workspace path rather than
other paths to the same file. [Clone mode](#clone-mode) prevents writes through
the primary workspace by mounting the host repository read-only.

Direct mount gives the agent broad write access to your workspace. The agent
can create, modify, or delete workspace files, including:

- Source code and configuration files
- Build files (`Makefile`, `package.json`, `Cargo.toml`)
- Git hooks (`.git/hooks/`)
- CI configuration (`.github/workflows/`, `.gitlab-ci.yml`)
- IDE configuration (`.vscode/tasks.json`, `.idea/` run configurations)
- AI project configuration and settings (`.claude/`, `.codex/`, `.gemini/`)
- Hidden files, shell scripts, and executables

Some of these files execute code when you trigger normal development
actions — committing, pushing, building, or opening the project in an IDE.
Review them after any agent session before performing those actions:

- Git hooks (`.git/hooks/`) run on commit, push, and other Git actions.
  These are inside `.git/` and don't appear in `git diff` output —
  check them separately with `ls -la .git/hooks/`.
- CI configuration (`.github/workflows/`, `.gitlab-ci.yml`) runs on
  push.
- Build files (`Makefile`, `package.json` scripts, `Cargo.toml`) run
  during build or install steps.
- IDE configuration (`.vscode/tasks.json`, `.idea/`) can run tasks
  when you open the project.
- AI project configuration and settings (`.claude/settings.json`, `.codex/config.toml`,
  `.gemini/settings.json`) can define hooks and startup commands that
  execute automatically.

#### Sandbox environment files

Sandbox environment files can declare lifecycle and credential commands that
run on the host with your privileges. Before running these commands, `sbx`
shows them in an environment plan and asks for approval. Review the plan before
you approve host commands.

For file placement and read-only protection, see
[Sandbox environment files](../configuration/environment-files.md#workspace).

> [!WARNING]
> Treat sandbox-modified workspace files the same way you would treat a pull
> request from an untrusted contributor: review before you trust them on
> your host.

### Clone mode

When you start a sandbox with [`--clone`](../usage.md#clone-mode), the agent
never works directly against your host repository. Even with full root
inside the VM, it cannot modify your `.git` directory, your working tree,
or any tracked file on your host.

> [!IMPORTANT]
> Clone mode protects your host repository from modification, **not from
> inspection**. Your repository is still mounted read-only into the sandbox,
> including untracked files and files excluded by `.gitignore`. Files such as
> `.env` remain readable by the agent. Store secrets outside your working
> directory or use [credential isolation](#credential-isolation) instead.

```mermaid
flowchart LR
  subgraph host["Host repository (untouched)"]
    direction TB
    repo[".git/ + working tree"]
    remote["remote sandbox-&lt;name&gt;"]
  end
  subgraph vm["Sandbox VM"]
    direction TB
    mount["/run/sandbox/source<br/>(read-only bind mount)"]
    clone["private clone (RW)<br/>agent edits here"]
    daemon["git-daemon"]
  end
  repo -->|"read-only bind mount"| mount
  mount -->|"git clone"| clone
  clone --> daemon
  daemon -->|"git fetch"| remote
```

How the boundary is enforced:

- Your repository's Git root is mounted at `/run/sandbox/source` as
  read-only. The mount covers your entire working directory, including
  untracked files and files excluded by `.gitignore`. Nothing the agent
  does inside the VM can write back through that mount, but all files
  under the Git root are readable inside the sandbox. This includes
  credential files not tracked by Git, such as `.env`.
- The agent works on a private clone that lives inside the sandbox. The
  clone has its own index, its own refs, and its own working tree. Writes
  to the clone never reach your host.
- The sandbox publishes the clone over a Git daemon bound to localhost on
  the host. The CLI wires it up as a `sandbox-<sandbox-name>` Git remote on
  your host repository. Fetching from that remote uses the same trust
  model as fetching from any third-party remote — nothing is integrated
  until you explicitly merge or check out the fetched refs.

The practical guarantees:

- The agent cannot modify any tracked file or any byte under `.git/` on
  your host. A compromised or buggy agent cannot drop a
  `.git/hooks/pre-commit`, alter `.github/workflows/`, or sneak changes
  into your working tree.
- Concurrent `git` commands on the host and inside the sandbox cannot
  race on a shared `.git/index` or shared refs — there is no shared
  writable Git state.
- Credentials, signing keys, and any settings in your repository's
  `.git/config` stay on the host. The agent's clone has its own
  independent configuration.

Use clone mode whenever you want a strong boundary between the agent's
Git activity and your host repository — for example when running an
unfamiliar agent, running multiple agents on the same repository at once,
or keeping your working tree clean while the agent works.

## Credential isolation

Most agents need API keys for their model provider. Rather than passing keys
into the sandbox, the host-side proxy intercepts outbound API requests and
injects authentication headers before forwarding each request.

Credential values are never stored inside the VM. They are not available as
environment variables or files inside the sandbox unless you explicitly set
them. This means a compromised sandbox cannot read API keys from the local
environment.

SSH agent forwarding is enabled by default. Private keys stay on the host, but
any process inside the sandbox can ask the forwarded agent to authenticate or
sign data. Docker Sandboxes forwards only sockets it recognizes as SSH agents.
A sandbox receives no SSH agent when forwarding is disabled, the configuration
is unavailable, or the selected socket can't be used.

For how to store and manage credentials, see [Credentials](../configuration/credentials.md).


---

# Troubleshooting

*Sección: Ai*

## Run diagnostics

Before digging into a specific issue, run
[`sbx diagnose`](/reference/cli/sbx/diagnose/) to check for common problems
with your installation, such as a missing CLI binary, daemon reachability
problems, a CLI/daemon version mismatch, missing storage directories, or
broken authentication.

```console
$ sbx diagnose
```

The command prints a summary of checks that passed, warned, or failed, along
with suggested fixes. Use `--output json` to get machine-readable output, or
`--output github-issue` to generate a Markdown snippet suitable for pasting
into a GitHub issue.

## Restart the sandbox daemon

If sandbox commands hang, fail to connect to the daemon, or keep returning
daemon errors, restart the sandbox daemon before resetting sandbox state:

```console
$ sbx daemon restart
```

Then retry the command that failed. Restarting the daemon doesn't delete
sandbox data. If the issue persists or state is corrupted, use
[`sbx reset`](/reference/cli/sbx/reset/).

## Resetting sandboxes

If you hit persistent issues or corrupted state, run
[`sbx reset`](/reference/cli/sbx/reset/) to stop all VMs and delete all sandbox
data. Create fresh sandboxes afterwards.

## Sandbox doesn't contain my project files

Starting with `sbx` version 0.42.0, the workspace path is optional for
`sbx create`. When you omit it, the command creates a mountless sandbox. For
example, these commands create and attach to a sandbox without mounting your
host project files:

```console
$ sbx create --name <sandbox-name> <agent>
$ sbx run --name <sandbox-name>
```

By contrast, `sbx run` mounts the current directory when you don't pass a
workspace path:

```console
$ sbx run <agent>
```

A sandbox's workspace configuration is fixed when the sandbox is created. To
reuse the name of an existing mountless sandbox, first
[copy out any files you want to keep](usage.md#copy-files-between-host-and-sandbox),
then remove and recreate it with a workspace path:

```console
$ sbx rm <sandbox-name>
$ sbx run --name <sandbox-name> <agent>
```

See [Choose a workspace](usage.md#choose-a-workspace) for mountless, direct,
and clone-mode behavior.

## Agent can't install packages or reach an API

Sandboxes use [network access rules](governance/access-controls/network.md) to
control outbound traffic.
If the agent fails to install packages or call an external API, the target
domain is likely not in the allow list. Check which requests are being blocked:

```console
$ sbx policy log
```

Then allow the domains your workflow needs:

```console
$ sbx policy allow network "*.npmjs.org,*.pypi.org,files.pythonhosted.org"
```

To allow all outbound traffic instead:

```console
$ sbx policy allow network "**"
```

If `sbx policy allow` doesn't unblock the request, your organization may
manage sandbox policies centrally and take precedence over local rules. See
[Organization policies](governance/access-controls/organization.md).

## Kit fails to install: source not in allowlist

If loading a kit fails with a message like its source is not in your
allowlist:

```console
$ sbx run claude --kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale"
ERROR: resolve kits: kit "git+https://github.com/docker/sbx-kits-contrib.git#dir=vale" cannot be installed — its source is not in your allowlist.
```

`sbx` restricts kit installs to an allowlist of sources, which defaults to
Docker Hub (`docker.io/`) only. Add the kit's publisher to the
`kit.allowedSources` setting, keeping the entries you want to retain:

```console
$ sbx settings set kit.allowedSources '["docker.io/","github.com/docker/"]'
```

Then run the command again. For details, including how to allow local kits or
any remote source, see [Restrict kit sources](customize/kits.md#restrict-kit-sources).

## SSH and other non-HTTP connections fail

Non-HTTP TCP connections such as SSH can be allowed by adding a policy rule for
the destination. Hostname rules work for these connections because the sandbox
recovers the hostname from its DNS resolver when the protocol doesn't include
one:

```console
$ sbx policy allow network "myhost:22"
```

If the destination is reached by IP address without a DNS lookup, the hostname
can't be recovered. Use an address-based rule in that case:

```console
$ sbx policy allow network "10.1.2.3:22"
```

UDP and ICMP traffic is blocked at the network layer and can't be unblocked
with policy rules.

For Git operations over SSH, you can either add an allow rule for the Git
server's hostname or IP address, or use HTTPS URLs instead:

```console
$ git clone https://github.com/owner/repo.git
```

## Can't reach a service running on the host

If a request to `127.0.0.1` or a local network IP returns "connection refused"
from inside a sandbox, the address is not reachable from within the sandbox VM.
See [Accessing host services from a sandbox](workflows/development.md#accessing-host-services-from-a-sandbox).

## Docker authentication failure

If you see a message like `You are not authenticated to Docker`, your login
session has expired. In an interactive terminal, the CLI prompts you to sign in
again. In non-interactive environments such as scripts or CI, run `sbx login`
to re-authenticate.

## Agent authentication failure

If the agent can't reach its model provider or you see API key errors, the key
is likely invalid, expired, or not configured. Verify it's set in your shell
configuration file and that you sourced it or opened a new terminal.

For agents that use the [credential proxy](configuration/credentials.md), make sure
you haven't set the API key to an invalid value inside the sandbox — the proxy
injects credentials automatically on outbound requests.

If credentials are configured correctly but API calls still fail, check
`sbx policy log` and look at the **PROXY** column. Requests routed through
the `transparent` proxy don't get credential injection. This can happen when a
client inside the sandbox (such as a process in a Docker container) isn't
configured to use the forward proxy. See
[Monitoring network activity](governance/monitor-and-enforce/monitoring.md)
for details.

## API calls fail with a certificate error

If your organization uses a proxy that inspects HTTPS traffic, agent requests
can fail with a certificate error such as
`SSL certificate problem: self-signed certificate in certificate chain`. Install
your organization's internal root CA inside the sandbox so the agent and its
SDKs trust certificates signed by the proxy. Certificate errors can stop a
request before the credential proxy can inject credentials.

For repeatable setup, create a [sandbox kit](customize/kits.md) that installs
the CA when the sandbox is created. See
[Install an internal CA certificate](customize/kit-examples.md#install-an-internal-ca-certificate)
for an example kit.

Use a PEM-encoded certificate with a `.crt` extension. If traffic can be signed
by more than one internal proxy, install each proxy's root CA before running
`update-ca-certificates`.

Create a sandbox with the kit:

```console
$ sbx run claude --kit ./internal-ca/
```

To update an existing sandbox, copy the certificate into the sandbox and update
the trust store:

```console
$ sbx cp ./internal-ca.crt <sandbox-name>:/tmp/internal-ca.crt
$ sbx exec <sandbox-name> -- sudo install -m 0644 /tmp/internal-ca.crt /usr/local/share/ca-certificates/internal-ca.crt
$ sbx exec <sandbox-name> -- sudo update-ca-certificates
```

> [!IMPORTANT]
> Install the CA into the system trust store with `update-ca-certificates`, as
> shown above. Don't override the sandbox's TLS trust variables (such as
> `SSL_CERT_FILE`) to point at only your internal CA. Doing so replaces the
> system bundle
> and breaks the trust the credential proxy depends on, so requests on the
> `forward` egress path fail.

If API calls still fail after installing the CA, run `sbx policy log` and check
the egress path in the **PROXY** column:

- `forward`: the credential proxy terminates TLS and presents its own
  certificate, which the sandbox already trusts. Requests on this path don't
  need the internal CA, and overriding the sandbox's trust variables breaks
  them, as described above.
- `forward-bypass` and `transparent`: the proxy forwards packets to the
  upstream proxy without terminating TLS, so the sandbox sees your
  organization's certificate directly. These paths are where installing the
  internal CA applies. The only difference between them is whether the client
  knows it's talking to a proxy.

## Sandbox runs out of disk space

The sandbox root (`/`) filesystem defaults to 20 GB. To increase it, set
`DOCKER_SANDBOXES_ROOT_SIZE` before creating the sandbox:

```console
$ DOCKER_SANDBOXES_ROOT_SIZE=40g sbx run claude
```

`DOCKER_SANDBOXES_ROOT_SIZE` controls the root filesystem size. The Docker data
disk at `/var/lib/docker` is independent and defaults to 10 GB. To change the
Docker data disk size for a sandbox, set `DOCKER_SANDBOXES_DOCKER_SIZE` when you
create it:

```console
$ DOCKER_SANDBOXES_DOCKER_SIZE=20g sbx run claude
```

The Docker data disk must be at least 512 MiB. The environment variable doesn't
resize existing volumes.

For a [clone-mode sandbox](usage.md#clone-mode), set
`DOCKER_SANDBOXES_CLONED_WORKSPACE_SIZE` before creating the sandbox to
configure the cloned workspace volume capacity. The variable accepts
human-readable size strings such as `100g`:

```console
$ DOCKER_SANDBOXES_CLONED_WORKSPACE_SIZE=100g sbx run --clone claude .
```

## Filesystem operations are slow in large repositories

Filesystem operations such as `git status`, `git log`, or directory scans can
be noticeably slow when you pass a workspace path and use direct mode.
Virtiofs caching speeds up these workloads. Clone-mode sandboxes always enable
it, so this tuning applies only to direct mode.

Virtiofs caching is enabled by default on all operating systems. If you
experience Git index corruption or unexpected file content, disable caching
with the kill switch and recreate the sandbox:

```console
$ DOCKER_SANDBOXES_ENABLE_VIRTIOFS_CACHE=0 sbx run <agent>
```

## Clone mode reports "not in a Git repository" on WSL

On Windows, running [`sbx run --clone`](usage.md#clone-mode) against a
repository on a WSL filesystem (a `\\wsl.localhost\...` path) can fail even
though the directory is a valid Git repository:

```console
> sbx run --clone claude \\wsl.localhost\Ubuntu\home\you\repo
ERROR: --clone requires a Git repository, but \\wsl.localhost\Ubuntu\home\you\repo is not in a Git repository
```

The cause is Git's dubious ownership check. When Git on Windows accesses a
repository owned by a different user across the WSL boundary, it refuses to
operate on it, so the underlying repository detection fails:

```console
> git -C \\wsl.localhost\Ubuntu\home\you\repo rev-parse --show-toplevel
fatal: detected dubious ownership in repository at '//wsl.localhost/Ubuntu/home/you/repo'
```

Add the repository to Git's `safe.directory` list to allow access, then run
the command again:

```console
> git config --global --add safe.directory '%(prefix)///wsl.localhost/Ubuntu/home/you/repo'
> sbx run --clone claude \\wsl.localhost\Ubuntu\home\you\repo
✓ Git repository detected: \\wsl.localhost\Ubuntu\home\you\repo
```

## Sandbox commits aren't signed

Docker Sandboxes can sign Git commits with SSH keys from your host agent.
For setup steps, see [Commit signing](workflows/git.md#commit-signing).

Forwarding is enabled by default. Confirm that it hasn't been disabled and
check whether a fixed socket path is configured:

```console
$ sbx settings get ssh.agentForwardingEnabled
$ sbx settings get ssh.agentSocketPath
```

If you use each client's current `SSH_AUTH_SOCK`, reconnect from a shell where
it points to the intended agent. If `ssh.agentSocketPath` returns a path,
confirm that it points to an active host agent. After changing forwarding or
the socket selection, run `sbx daemon restart`.

If `ssh-add -L` prints `The agent has no identities.`, the sandbox can reach
the forwarded agent, but the host agent doesn't have a loaded key. Load the
signing key into your host SSH agent:

```console
$ ssh-add ~/.ssh/id_ed25519
```

If commit signing works on the host but fails in a sandbox, check whether Git
is configured to sign with a host file path such as
`/Users/me/.ssh/id_ed25519.pub`. The sandbox uses the forwarded SSH agent, not
the host key file path. Use the inline public key form instead:

```console
$ git config --global gpg.format ssh
$ git config --global user.signingkey "key::$(ssh-add -L | head -n 1)"
```

If Git reports that `ssh-keygen` is missing, use a sandbox template that
includes OpenSSH client tools.

If `git log --show-signature` reports that `gpg.ssh.allowedSignersFile` needs
to be configured, Git can't verify the SSH signature locally. This verification
config isn't required to create signed commits. GitHub uses the SSH signing
keys configured in your GitHub account to verify commits.

GPG and S/MIME signing keys aren't available inside the sandbox. If your
repository or organization requires GPG or S/MIME signatures, or if SSH signing
isn't configured, use one of these workarounds:

- Commit outside the sandbox. Let the agent make changes without committing,
  then commit and sign from your host terminal.

- Sign after the fact. Let the agent commit inside the sandbox, then re-sign
  the commits on your host:

  ```console
  $ git rebase --exec 'git commit --amend --no-edit -S' origin/main
  ```

  This replays each commit on the branch and re-signs it with your local
  signing key.

## Daemon fails to start after downgrading

If you downgrade `sbx` to a version older than the one that last managed your
local state, the daemon may fail to start with a database version mismatch:

```text
ERROR: failed to start backend in-process: start backend: creating containerd
server: ... database is at major version 6, but this binary only supports up
to major version 1
```

A newer version of `sbx` upgraded the local database to a schema that older
binaries don't understand. To recover, reset all sandbox state:

```console
$ sbx reset --preserve-secrets
```

This stops all VMs and deletes all sandbox data. You'll need to create new
sandboxes afterwards. The `--preserve-secrets` flag keeps any secrets you've
set so you don't have to reconfigure them.

## Removing all state

As a last resort, if `sbx reset` doesn't resolve your issue, you can remove the
`sbx` state directory entirely. This deletes all sandbox data, configuration, and
cached images. Stop all running sandboxes first with `sbx reset`.

{{< tabs >}}
{{< tab name="macOS" >}}

```console
$ rm -rf ~/Library/Application\ Support/com.docker.sandboxes/
```

{{< /tab >}}
{{< tab name="Windows" >}}

```powershell
> Remove-Item -Recurse -Force "$env:LOCALAPPDATA\DockerSandboxes"
```

{{< /tab >}}
{{< tab name="Linux" >}}

Sandbox state on Linux follows the XDG Base Directory specification and is
spread across three directories:

```console
$ rm -rf ~/.local/state/sandboxes/
$ rm -rf ~/.cache/sandboxes/
$ rm -rf ~/.config/sandboxes/
```

If you have set custom `XDG_STATE_HOME`, `XDG_CACHE_HOME`, or
`XDG_CONFIG_HOME` environment variables, replace `~/.local/state`,
`~/.cache`, and `~/.config` with the corresponding values.

{{< /tab >}}
{{< /tabs >}}

## Enable automatic diagnostics uploads

To opt in to automatic diagnostics uploads after certain daemon errors, run:

```console
$ sbx settings set diagnostics.autoUpload yes
```

Automatic bundles include basic system information and client, daemon, crash,
and MCP logs. Docker Sandboxes redacts recognized identity values and
credential patterns, but collected logs can still contain user content. Failed
uploads remain in a local queue for a later retry.

## Report an issue

If you've exhausted the steps above and the problem persists, file a GitHub
issue at [github.com/docker/sbx-releases/issues](https://github.com/docker/sbx-releases/issues).

To help Docker investigate, generate a diagnostics bundle and share it when
reporting the issue:

```console
$ sbx diagnose --upload
```

The bundle contains daemon logs, diagnostic check results, and basic system
information. When `--upload` is confirmed, the bundle is uploaded to Docker
support and the command prints a diagnostics ID. Include this ID in your
issue so the team can correlate it with the uploaded bundle.


---

# Usage

*Sección: Ai*

Use this page as a command-oriented guide to day-to-day `sbx` operations. For
scenario-based recommendations, see [Workflow patterns](workflows/).

## Sign in

Sign in from a terminal:

```console
$ sbx login
```

For scripts or CI runners where a browser isn't available, see
[CI and headless use](workflows/automation.md).

## Start, stop, and remove

The basic workflow is [`run`](/reference/cli/sbx/run/) to start,
[`ls`](/reference/cli/sbx/ls/) to check status,
[`stop`](/reference/cli/sbx/stop/) to pause, and
[`rm`](/reference/cli/sbx/rm/) to clean up:

```console
$ sbx run claude                    # start an agent in the current directory
$ sbx ls                            # see what's running
$ sbx stop my-sandbox               # pause it
$ sbx rm my-sandbox                 # delete it entirely
```

If the sandbox has an active session — an open attach, SSH connection, or
in-flight SFTP transfer — `sbx rm` refuses unless you pass `--force`:

```console
$ sbx rm --force my-sandbox
```

If you need a clean slate, remove the sandbox and run it again:

```console
$ sbx stop my-sandbox
$ sbx rm my-sandbox
$ sbx run claude
```

To remove all stopped local sandboxes, use `sbx prune`. Running sandboxes are
never removed. Preview the sandboxes that would be removed, or filter out
sandboxes stopped within the last week:

```console
$ sbx prune --dry-run
$ sbx prune --filter since=168h
```

Run `sbx prune` without flags to confirm and remove all stopped sandboxes.

## Choose a workspace

`sbx run` mounts the current directory when you don't pass a workspace path.
Pass a path to mount another directory instead:

```console
$ sbx run claude
$ sbx run claude ~/my-project
```

The first workspace path is the primary workspace. The agent starts there, and
`sbx exec` uses it as the default working directory. The host directory is
mounted at the same absolute path inside the sandbox. When you don't pass a
path to `sbx run`, the current directory is the primary workspace.

Starting with `sbx` version 0.42.0, workspace paths are optional for
`sbx create`. Omit them to create a mountless sandbox without a host workspace
bind mount, then attach to the sandbox by name:

```console
$ sbx create --name scratch claude
$ sbx run --name scratch
```

In a mountless sandbox, the agent starts in the template image's working
directory. Docker-provided templates use `/home/agent/workspace`. Files there
persist across stops and restarts but are deleted when you remove the sandbox.
Assign the sandbox a name so you can reconnect to it, and use
[`sbx cp`](#copy-files-between-host-and-sandbox) to transfer files between the
sandbox and the host.

## Reconnect and name sandboxes

Sandboxes persist after the agent exits. Running the same workspace path again
reconnects to the existing sandbox rather than creating another sandbox:

```console
$ sbx run claude ~/my-project  # creates sandbox
$ sbx run claude ~/my-project  # reconnects to same sandbox
```

Use `--name` to give a sandbox an explicit identity:

```console
$ sbx run --name my-project claude
```

Once a named sandbox exists, reattach from any working directory with
`sbx run --name`. You can omit the agent name when reattaching:

```console
$ sbx run --name my-project        # re-attaches from anywhere
$ sbx run claude --name my-project # same, with agent confirmed
```

To run multiple sandboxes against the same workspace, give each a distinct
name:

```console
$ sbx run claude --name feature ~/my-project
$ sbx run claude --name spike ~/my-project
```

## Create without attaching

[`sbx run`](/reference/cli/sbx/run/) creates the sandbox and attaches you to the
agent. To create a sandbox with the current directory mounted in the background
without attaching:

```console
$ sbx create --name my-project claude .
```

Omit the path to create a mountless sandbox instead. Attach later with
`sbx run --name`:

```console
$ sbx create --name scratch claude
$ sbx run --name scratch
```

## Set environment variables

> [!NOTE]
> The `-e`/`--env` and `--env-file` flags require `sbx` version 0.39.0 or
> later.

Pass `-e` or `--env` to `sbx run` or `sbx create` to set an environment
variable in the sandbox:

```console
$ sbx run -e LOG_LEVEL=debug claude
```

Specify a variable name without a value to copy its value from the host
environment:

```console
$ export API_URL=https://api.example.com
$ sbx run -e API_URL claude
```

To load multiple variables, pass one or more environment files:

```console
$ sbx create --name my-project --env-file .env.sandbox claude .
```

The flags follow `docker run` precedence rules. Values passed with `-e`
override values from environment files. When you pass multiple environment
files, a value in a later file overrides the same variable in an earlier file.

When either command creates a sandbox, the variables are stored with the
sandbox. They are also available to the agent session started by `sbx run`.
When `sbx run` re-attaches to an existing sandbox, the variables apply to that
agent session without changing the sandbox's stored environment. To set
variables for one command instead, use `sbx exec -e` or
`sbx exec --env-file`.

To persist a variable across future sessions of an existing sandbox, append an
export to `/etc/sandbox-persistent.sh`:

```console
$ sbx exec -d <sandbox-name> bash -c "echo 'export INTERNAL_API_URL=https://api.example.com' >> /etc/sandbox-persistent.sh"
```

The `bash -c` wrapper ensures the `>>` redirect runs inside the sandbox instead
of on your host. The file is sourced when Bash starts inside the sandbox,
including for interactive sessions and agents started with `sbx run`. A command
passed directly to `sbx exec` doesn't start a shell. Wrap that command in
`bash -c` if it needs variables from the persistent environment file.

A variable added to the file only takes effect for sessions and agents started
afterward. Restart a running agent, or stop and start the sandbox, to pick up
the new value.

Environment variables are readable by processes inside the sandbox. For API
keys and other credentials, use [`sbx secret set`](configuration/credentials.md#store-a-secret)
for a supported service or the experimental
[`sbx secret set-custom`](configuration/credentials.md#custom-secrets) for a
credential sent to known hosts. The host-side proxy can then inject the real
value without exposing it to the agent.

## Run commands inside a sandbox

To get a shell inside a running sandbox, use [`sbx exec`](/reference/cli/sbx/exec/):

```console
$ sbx exec -it <sandbox-name> bash
```

Without `--workdir`, the command starts in the sandbox's primary workspace. In
a mountless sandbox, it starts in the container image's working directory.

## Interactive mode

Running `sbx` with no subcommands opens an interactive terminal dashboard:

```console
$ sbx
```

The dashboard shows all your sandboxes as cards with live status, CPU, and
memory usage. From here you can:

- **Create** a sandbox (`c`).
- **Start or stop** a sandbox (`s`).
- **Attach** to an agent session (`Enter`), same as `sbx run`.
- **Open a shell** inside the sandbox (`x`), same as `sbx exec`.
- **Remove** a sandbox (`r`).

The dashboard also includes a network governance panel where you can monitor
outbound connections made by your sandboxes and manage network rules. Use `tab`
to switch between the sandboxes panel and the network panel.

From the network panel you can browse connection logs, allow or block specific
hosts, and add custom network rules. Press `?` to see all keyboard shortcuts.

## Git workspace modes

When your primary workspace is a Git repository, choose how the sandbox receives
it when you create the sandbox:

- Direct mode is the default for `sbx run`. It also applies when you pass a
  workspace path to `sbx create`. The agent has read-write access to your
  working tree, and changes appear on your host immediately.
- [Clone mode](#clone-mode) uses `--clone`. The agent edits a separate Git clone
  inside the sandbox. Its changes stay there until you fetch them or the agent
  pushes them. Your host repository is also available at
  `/run/sandbox/source`, but only with read access.

For guidance on branch strategy, fetching work from a sandbox, and parallel
agent workflows, see [Git workflows](workflows/git.md). For the
security model behind each mode, see
[Workspace isolation](security/isolation.md#workspace-isolation).

### Clone mode

To create a clone-mode sandbox, pass `--clone` when you run or create it:

```console
$ sbx run --clone claude .
```

You can also create the sandbox in the background and attach later:

```console
$ sbx create --clone --name my-sandbox claude .
$ sbx run --name my-sandbox
```

Clone mode has a few create-time constraints:

- Clone mode is fixed at create time. To switch an existing sandbox to clone
  mode, remove it and recreate it with `sbx create --clone`.
- The clone follows whichever ref your host repository has checked out at create
  time. No branch is created automatically.
- The primary workspace must be a Git repository. Omit `--clone` for non-Git
  workspaces.
- Clone mode is rejected from inside a Git worktree other than the main one. The
  read-only bind mount can't resolve the worktree's `.git` pointer file. Run
  `sbx create --clone <agent> .` from the main repository checkout instead.
- Removing a clone-mode sandbox drops the in-sandbox clone. Fetch or push any
  commits you want to keep before you remove it.

## Multiple workspaces

You can mount extra directories into a sandbox alongside the main workspace.
The first path is the primary workspace — the agent starts here, and the
sandbox's in-container Git clone is populated from this directory if you
use `--clone`. Extra workspaces are always mounted directly.

Each workspace path appears inside the sandbox at the same absolute path as on
the host. Append `:ro` to mount an extra workspace read-only — useful for
reference material or shared libraries the agent shouldn't modify:

```console
$ sbx run claude ~/project-a ~/shared-libs:ro ~/docs:ro
```

You can also run separate projects side-by-side. Remove unused sandboxes when
you're done to reclaim disk space:

```console
$ sbx run claude ~/project-a
$ sbx run claude ~/project-b
$ sbx rm <sandbox-name>       # when finished
```

## Copy files between host and sandbox

Use [`sbx cp`](/reference/cli/sbx/cp/) to copy files or directories between
your host and a sandbox. This is useful for one-off files that aren't part of a
mounted workspace, such as generated output, logs, or setup files. The sandbox
path must be absolute. `sbx cp` doesn't resolve relative paths such as `.`
against the sandbox's default working directory.

For example, copy files to or from the default working directory used by a
Docker-provided agent template:

```console
$ sbx cp ./config.json my-sandbox:/home/agent/workspace/
$ sbx cp my-sandbox:/home/agent/workspace/output.log ./
$ sbx cp ./src/ my-sandbox:/home/agent/workspace/src
```

One side of the copy must use `SANDBOX:PATH`. Copying directly between two
sandboxes isn't supported.

## Publish ports

Sandboxes are [network-isolated](security/isolation.md) — your browser or local
tools can't reach a server running inside one by default. A port mapping of
`8080:3000` publishes sandbox port 3000 on host port 8080.

If you know which ports you need, publish them when you create the sandbox:

```console
$ sbx run --publish 8080:3000 --name my-sandbox claude
```

For an existing sandbox, use [`sbx ports`](/reference/cli/sbx/ports/) to
forward traffic from your host. Publishing a port on a stopped local sandbox
starts it first:

```console
$ sbx ports my-sandbox --publish 8080:3000
$ open http://localhost:8080
```

To let the OS pick a free host port instead of choosing one yourself, specify
only the sandbox port. Then use `sbx ports` to check which host port was
assigned:

```console
$ sbx ports my-sandbox --publish 3000
$ sbx ports my-sandbox
```

`sbx ls` shows active port mappings alongside each sandbox. `sbx ports` lists
them in detail.

```console
$ sbx ls
SANDBOX         AGENT   STATUS   PORTS                    WORKSPACE
my-sandbox      claude  running  127.0.0.1:8080->3000/tcp4 /home/user/proj
```

To stop forwarding a port:

```console
$ sbx ports my-sandbox --unpublish 8080:3000
```

When `sbx run` re-attaches to an existing sandbox, it ignores `--publish`. Use
`sbx ports` to publish ports on that sandbox. For dev server and host-service
recipes, see
[Local services](workflows/development.md#local-services).

## What persists

While a sandbox exists, installed packages, Docker images, configuration
changes, command history, and mountless workspace files all persist across
stops and restarts. When you remove a sandbox, everything inside is deleted.
Host workspace files, including repositories used as clone sources, and the
[shared agent skills store](workflows/agent-skills.md) remain on your host. To
preserve a configured environment, create a [custom
template](customize/templates.md) or use a [kit](customize/kits.md).


---

# Workflow patterns

*Sección: Ai*

Choose a workflow based on how you want to develop, authenticate tools, or run
sandboxes in automation. For command syntax and lifecycle basics, see
[Usage](../usage.md).

## Choose how code moves

Your workspace strategy determines when an agent's changes appear on the host.
Direct mode edits the host working tree in place. Clone mode keeps changes in a
private clone until you fetch or push them. Host worktrees provide branch
isolation while keeping Git operations on the host. See [Git workflows](git.md)
to choose a strategy for single or parallel tasks.

## Develop in the sandbox

Each sandbox has a private Docker daemon and runtime for building images,
installing dependencies, and running tests. You can publish services from the
sandbox or connect to services on the host. See
[Develop and test locally](development.md).

Tools inside the sandbox can use credentials configured on the host without
copying secret values into the VM. See
[Authenticate command-line tools](authentication.md) for GitHub CLI, registry,
and external secret-provider workflows.

## Reuse and automate workflows

Sandbox environment files work like Compose files for sandboxes: they capture
project configuration in a versioned YAML file. Use `sbxenv.yaml` to define
the agent, workspaces, tools, resources, credentials, and ports so contributors
can start a consistent environment without reproducing CLI flags and setup
steps. See [Sandbox environment files](../configuration/environment-files.md).

You can also add skills from Git repositories or import them from supported
host agents into a persistent store shared with new sandboxes. See
[Share agent skills](agent-skills.md).

For unattended jobs, use headless authentication and manage the sandbox
lifecycle from scripts. See [Run sandboxes in CI](automation.md).


---

# Share agent skills

*Sección: Ai*

Shared agent skills let you install skills from Git repositories or import
skills from supported agents on your host. `sbx` keeps installed skills in a
persistent store that survives sandbox deletion and is shared by default with
new sandboxes that run a supported agent.

> [!NOTE]
> Shared agent skills are experimental.

## Add skills from a repository

Add every skill from a Git repository:

```console
$ sbx skills add anthropics/skills
```

The repository must contain one or more valid `SKILL.md` files. You can use
GitHub `owner/repository` shorthand or a Git URL, including HTTPS and SSH URLs.

To add specific skills, use `--skill` with each name or pass a comma-separated
list:

```console
$ sbx skills add https://github.com/anthropics/skills --skill frontend-design --skill pdf
```

When a skill with the same name is already installed, `sbx` prompts before
replacing it. Use `--force` to replace existing skills without prompts.

## Manage installed skills

List the skills in the shared store:

```console
$ sbx skills ls
```

Update every skill installed from a repository:

```console
$ sbx skills update
```

To update specific skills, pass one or more names:

```console
$ sbx skills update frontend-design pdf
```

`sbx skills update` only refreshes skills installed with `sbx skills add`. To
refresh a skill imported from the host, run `sbx skills import` again. To manage
it with `sbx skills update`, install it from a repository instead.

Remove one or more installed skills:

```console
$ sbx skills rm frontend-design pdf
```

`sbx` asks for confirmation before removing skills that running agents may be
using. Use `--force` to skip confirmation in scripts.

## Import skills from the host

Preview the skills that `sbx` finds without copying them:

```console
$ sbx skills import --dry-run
```

The command scans the following directories in order and copies each skill
subdirectory into the shared store. When the sandbox starts, `sbx` mounts the
store at the path the agent reads inside the sandbox.

| Agent       | Host source         | Sandbox mount target          |
| ----------- | ------------------- | ----------------------------- |
| Claude Code | `~/.claude/skills`  | `/home/agent/.claude/skills`  |
| Codex and Devin | `~/.agents/skills` | `/home/agent/.agents/skills` |
| Copilot     | `~/.copilot/skills` | `/home/agent/.copilot/skills` |
| Cursor      | `~/.cursor/skills`  | `/home/agent/.cursor/skills`  |
| Droid       | `~/.factory/skills` | `/home/agent/.factory/skills` |

All imported skills go into the same store, regardless of their source. If
more than one source contains a skill with the same directory name, the skill
from the first source in the table wins and `sbx` warns about the others.

Import the skills:

```console
$ sbx skills import
```

The final output reports the shared store path. The default locations are:

| Platform | Shared store path                                                           |
| -------- | --------------------------------------------------------------------------- |
| macOS    | `~/Library/Application Support/com.docker.sandboxes/sandboxes/agent-skills` |
| Linux    | `~/.local/state/sandboxes/sandboxes/agent-skills`                           |
| Windows  | `%LOCALAPPDATA%\DockerSandboxes\sandboxes\state\agent-skills`               |

On Linux, `sbx` uses `$XDG_STATE_HOME/sandboxes/sandboxes/agent-skills` when
`XDG_STATE_HOME` is set.

When a skill already exists in the store, `sbx` prompts before replacing it.
Use `--force` to replace existing skills without prompts. Importing replaces
the complete skill directory rather than merging files. Run the import command
again when you want to copy updates from the host. If an import replaces a
repository-installed skill, `sbx` no longer associates that skill with its
repository, so `sbx skills update` won't refresh it.

## Shared store behavior

Running `sbx reset` clears the shared store.

Sandboxes created with `sbx` version 0.37.0 or later for a supported agent are
configured to mount the store read-write by default. These sandboxes mount the
current contents of the store each time they start, so you can install skills
before or after creating them. To create a sandbox without the shared store,
use `--no-share-skills`:

```console
$ sbx run --no-share-skills claude
```

Upgrading `sbx` does not enable shared skills for sandboxes created with an
earlier version. Remove and recreate those sandboxes after upgrading. The
`--no-share-skills` option also only applies when the sandbox is created. To
turn off shared skills for an existing sandbox, remove it and recreate it with
the option.

> [!WARNING]
> The shared skills store is mounted read-write. A sandbox can modify any skill
> in the store, and another sandbox can later load the modified instructions or
> run the modified scripts. The store is dedicated sandbox state, so this does
> not by itself execute the modified skill on your host. It does put every
> sandbox that shares the store in the same trust boundary. Use
> `--no-share-skills` to keep a sandbox outside that boundary.

Some agents scan for skills when a session starts. If installed skills don't
appear in an existing session, start another agent session.


---

# Authenticate command-line tools

*Sección: Ai*

The sandbox proxy handles API credentials for model providers automatically,
but agents often also need credentials for tools like `gh`, `docker`, or a
secrets manager. Configure the credential source on your host, and the proxy
injects the resolved value into matching requests from the sandbox. Dynamic
secret sources can retrieve a value from an authenticated host CLI without
copying the value into the secret store.

> [!NOTE]
> Service secrets are global by default, so all future sandboxes can use them.
> Sandboxes that already exist when you run `sbx secret set` do not
> receive the updated value. To update a running sandbox, scope the secret to
> it directly: `sbx secret set <service> --sandbox <sandbox-name>`.

## GitHub CLI

Store your GitHub token as a sandbox secret. The proxy injects it into
outbound requests, so `gh` works inside the sandbox without any additional
configuration:

```console
$ sbx secret set github --command 'gh auth token'
```

The daemon runs `gh auth token` on the host and caches its output for 55 minutes
by default. After the cache expires, it runs the command again, so token updates
from `gh` don't need to be copied into `sbx` manually. Use `--refresh on-demand`
to run the command for every credential use.

The agent can then create pull requests, open issues, comment on PRs, and
interact with the GitHub API the same way it would from your host:

```console
# Inside the sandbox
$ gh pr create --title "feat: my feature" --body "..."
$ gh issue list
```

The token is never stored in plaintext inside the sandbox. See
[GitHub token](../configuration/credentials.md#github-token) for details.

## Docker registry

When using Docker Hub, authentication is handled automatically; `sbx` reuses
your existing login session. For other registries, you need to configure
credentials for `sbx` so it can pull private [templates](../customize/templates.md)
and kits when creating a sandbox:

```console
$ gh auth token | sbx secret set --all-sandboxes --registry ghcr.io \
    --username <github-username> --password-stdin
$ echo "$ACR_PASSWORD" | sbx secret set --all-sandboxes \
    --registry myregistry.azurecr.io \
    --username myuser --password-stdin
```

Add `-g` or a sandbox name when the agent needs to run authenticated
`docker pull` or `docker push` commands from inside the sandbox. The host-side
proxy handles the registry login without writing the credential into the
sandbox.

Images and containers built inside the sandbox run on the sandbox's private
Docker daemon, not your host's. They're deleted when the sandbox is removed.

For information on how registry credentials differ from other secrets,
per-registry username requirements, and all-sandbox versus per-sandbox scoping, see
[Registry credentials](../configuration/credentials.md#registry-credentials).

## Source credentials from 1Password

Install the 1Password CLI, sign in on the host, and pass an `op://` reference to
`sbx secret set`. The secret store records the reference, and the daemon uses
`op read` on the host when the proxy needs the credential:

```console
$ sbx secret set github --ref 'op://Work/GitHub/token'
$ sbx secret set anthropic --ref 'op://Work/Anthropic/credential'
```

The real value stays on your host, and the sandbox sees the proxy-managed
placeholder. Service secrets are cached for 55 minutes by default. To retrieve
the value from 1Password for every credential use, set the refresh policy:

```console
$ sbx secret set anthropic \
    --ref 'op://Work/Anthropic/credential' \
    --refresh on-demand
```

## Source credentials from AWS Secrets Manager

Install and authenticate the AWS CLI on the host, then register the secret's
ARN. The daemon calls AWS Secrets Manager when the proxy needs the value:

```console
$ sbx secret set anthropic \
    --ref 'arn:aws:secretsmanager:us-west-2:123456789012:secret:anthropic-api-key'
```

See [Use a dynamic secret source](../configuration/credentials.md#use-a-dynamic-secret-source)
for refresh policies, verification options, custom secrets, and provider
account or profile selection.


---

# Run sandboxes in CI

*Sección: Ai*

For CI environments and scripts where a browser isn't available, authenticate
with a Docker Personal Access Token (PAT):

```console
$ echo "$DOCKER_PAT" | sbx login --username <your-docker-id> --password-stdin
```

Generate a PAT from your
[Docker account settings](https://app.docker.com/settings/personal-access-tokens)
with at least **Read** scope.

From there, the rest of the `sbx` workflow is the same as interactive use.
Create the sandbox in the background with `sbx create`, run agent tasks with
`sbx exec`, and clean up with `sbx rm`:

```console
$ sbx create --name ci-task --clone claude .
$ sbx run --name ci-task  # attach and give instructions, or use sbx exec for one-off commands
$ git fetch sandbox-ci-task
$ sbx rm ci-task
```

Agent credentials (API keys, GitHub token) can be preconfigured as global
secrets so they're available to any sandbox the CI runner creates. If the
relevant environment variables are already set in the CI environment (see the
[built-in services table](../configuration/credentials.md#built-in-services) for which
variables each service reads), import them all at once:

```console
$ sbx secret import --all
```

To overwrite an existing stored entry, add `--force`. To pass a value from your
CI provider's secret store, use `-t`. For example, in a GitHub Actions step:

```yaml
- run: sbx secret set anthropic -t "${{ secrets.ANTHROPIC_API_KEY }}"
```


---

# Develop and test locally

*Sección: Ai*

Use a sandbox's private runtime to build images, run tests, and connect local
tools to development services across the sandbox boundary.

## Build and test inside a sandbox

Agents have sudo access inside the sandbox, so they can install packages,
start databases, run test dependencies, and prepare the environment they need.
Installed packages persist for the sandbox's lifetime. For repeated setup, use
[Customize](../customize/) to package the environment as a template or kit.

Agents can also build Docker images, run containers, and use
[Compose](../../../compose/index.md). Everything runs inside the sandbox's
private Docker daemon, so containers started by the agent never appear in your
host's `docker ps`. When you remove the sandbox, all images, containers, and
volumes inside it are deleted with it.

This pattern works well for tasks where the agent needs to run the project's
test suite or inspect a service it started. If you need to reach that service
from your host, publish the port when you create the sandbox, or publish it
later with `sbx ports`.

## Local services

Use this workflow when a sandboxed agent starts a dev server, or when the agent
needs to call a service running on your host.

### Accessing services in the sandbox

Sandboxes are [network-isolated](../security/isolation.md) — your browser or local
tools can't reach a server running inside one by default. A port mapping of
`8080:3000` publishes sandbox port 3000 on host port 8080.

If you know which ports you need, publish them when you create the sandbox:

```console
$ sbx run --publish 8080:3000 --name my-sandbox claude
```

For an existing sandbox, use [`sbx ports`](/reference/cli/sbx/ports/) to
forward traffic from your host. Publishing a port on a stopped local sandbox
starts it first.

The common case: an agent has started a dev server or API, and you want to open
it in your browser or run tests against it.

```console
$ sbx ports my-sandbox --publish 8080:3000
$ open http://localhost:8080
```

To let the OS pick a free host port instead of choosing one yourself, specify
only the sandbox port. Then use `sbx ports` to check which host port was
assigned:

```console
$ sbx ports my-sandbox --publish 3000
$ sbx ports my-sandbox
```

`sbx ls` shows active port mappings alongside each sandbox, and `sbx ports`
lists them in detail:

```console
$ sbx ls
SANDBOX         AGENT   STATUS   PORTS                    WORKSPACE
my-sandbox      claude  running  127.0.0.1:8080->3000/tcp4 /home/user/proj
```

To stop forwarding a port:

```console
$ sbx ports my-sandbox --unpublish 8080:3000
```

For a service to be reachable, it must listen on all interfaces inside the
sandbox, not only `127.0.0.1`. Bind it to `0.0.0.0` for IPv4 or `[::]` for both
IPv4 and IPv6. Most dev servers need a flag like `--host 0.0.0.0` to do this.

On the host, a published port binds IPv4 (`127.0.0.1`) unless you name another
protocol, so `http://localhost:<port>/` reaches a service listening on IPv4
whichever address your resolver picks for `localhost`. Naming an explicit IPv6
host address, such as `--publish [::1]:8080:3000`, defaults the protocol to
`tcp6` instead. To publish on both families use `--publish 8080:3000/tcp`, and
for IPv6 alone `/tcp6`. Both of
those require the sandboxed service to listen on IPv6 as well — bind it to
`[::]` — or a client arriving over `::1` has its connection accepted and then
reset.

Published ports survive restarts: `sbx` re-publishes them when the sandbox or
the daemon restarts. Explicit host ports are reused, while a port published with
an OS-assigned host port, such as `--publish 3000`, gets a different host port
on each start. Check `sbx ports my-sandbox` to find it. If an explicit host port
is already in use at restart, the CLI or the dashboard prompts you to choose
another. Removing the sandbox releases its ports.

When `sbx run` re-attaches to an existing sandbox, it ignores `--publish`. Use
`sbx ports` to publish ports on that sandbox. To stop forwarding,
`--unpublish 8080:3000` removes a single mapping, and `--unpublish 3000`
removes every host port mapped to sandbox port 3000.

### Accessing host services from a sandbox

Services running on your host are reachable from inside a sandbox using the
hostname `host.docker.internal`. Use this instead of `127.0.0.1` or your
machine's local network IP address, which are not reachable from inside the
sandbox.

The sandbox proxy translates `host.docker.internal` to `localhost` before
forwarding the request, so you must add the `localhost` address with the
specific port to your network policy allowlist:

```console
$ sbx policy allow network localhost:11434
```

Then use `host.docker.internal` in any configuration or request that points at
the host service. For example, to verify connectivity from a sandbox shell:

```console
$ curl http://host.docker.internal:11434
```


---

# Use Git with sandboxes

*Sección: Ai*

Sandboxes support three approaches for working with Git repositories. The
right choice depends on whether you want branch isolation and whether you
plan to run tasks in parallel:

|                           | Direct mode      | Clone mode (`--clone`)       | Host worktree                 |
| ------------------------- | ---------------- | ---------------------------- | ----------------------------- |
| Branch management         | You, on the host | Agent, inside the clone      | You, on the host              |
| Changes visible on host   | Immediately      | After fetch or agent push    | Immediately                   |
| Agent can use Git         | Yes              | Yes                          | No                            |
| Parallelism               | No               | Multiple agents, one sandbox | One sandbox per parallel task |
| Mode fixed at create time | No               | Yes                          | —                             |

## Direct mode

The simplest approach. The sandbox mounts your host working tree directly —
the agent edits files in place and changes appear immediately. You manage
branches yourself.

1. Check out the branch you want to work on:

   ```console
   $ git checkout -b feat/my-feature
   ```

2. Start the sandbox. No special flags needed:

   ```console
   $ sbx run claude
   ```

3. The agent edits files in your working tree. Review diffs, stage, and
   commit as you normally would:

   ```console
   $ git diff
   $ git add -p
   $ git commit
   $ git push -u origin feat/my-feature
   ```

Because the sandbox mounts your working tree, switching branches on the host
also changes what the agent sees. This makes direct mode well-suited for
focused, single-branch work where you're collaborating with the agent
turn-by-turn.

## Clone mode

In clone mode, `sbx` creates a separate Git clone inside the sandbox. The agent
edits this clone instead of your host working tree. Its changes stay inside the
sandbox until you fetch a branch or the agent pushes one to a remote. Your host
repository is also available at `/run/sandbox/source`, but only with read
access. The sandbox clone is not a Git worktree linked to your host checkout.

A single clone-mode sandbox can hold multiple branches and worktrees for
parallel tasks. The `--clone` flag creates the clone, but it doesn't separate
one task from another. To keep parallel tasks isolated, instruct your agent tool
to create a separate branch or worktree for each task.

> [!NOTE]
> `--clone` is a create-time flag and cannot be changed on an existing
> sandbox. To change a sandbox from clone mode to direct mode, remove and
> recreate it. To run both modes against the same repository, create separate
> sandboxes with distinct names.

### Sandbox remote behavior

The CLI copies Git remotes from your host repository, such as `origin` and
`upstream`, into the in-sandbox clone. Local-path remotes, such as `file://`
URLs and filesystem paths, aren't copied because they aren't reachable from
inside the sandbox.

The Git daemon that exposes the in-sandbox clone runs as part of the sandbox.
It's only reachable while the sandbox is running:

- `sbx stop` shuts down the daemon. `git fetch sandbox-<name>` fails until the
  sandbox starts again.
- Restarting the sandbox assigns another ephemeral port to the daemon. The CLI
  updates the `sandbox-<name>` remote URL in your host repository's Git config,
  so fetching continues without manual reconfiguration.
- `sbx rm` removes the sandbox, the daemon, the published port, and the
  `sandbox-<name>` remote entry from your host repository.

### Single task

1. Start a clone-mode sandbox:

   ```console
   $ sbx run --clone claude .
   ```

2. Ask the agent to create a branch before it starts editing:

   > Create a branch `feat/my-feature` and make the changes.

3. Fetch the agent's branch when it's done:

   ```console
   $ git fetch sandbox-<name>
   $ git log sandbox-<name>/feat/my-feature
   $ git diff main..sandbox-<name>/feat/my-feature
   ```

4. Pull the branch to the host and push, or ask the agent to push directly:

   ```console
   # Pull to host, then push
   $ git checkout -b feat/my-feature sandbox-<name>/feat/my-feature
   $ git push -u origin feat/my-feature
   $ gh pr create

   # Or ask the agent
   # "Push feat/my-feature to origin and open a PR."
   ```

### Parallel tasks

1. Start a clone-mode sandbox and open the
   [agents view](../agents/claude-code.md#agents-view):

   ```console
   $ sbx run --clone claude .
   ```

2. Dispatch each independent task to a separate background session. Your agent
   tool may use branches or worktrees to keep their changes separate. If it
   doesn't, add a project instruction such as:

   ```markdown
   Always start each task on its own git branch before making changes.
   ```

3. Fetch all branches when the agents are done:

   ```console
   $ git fetch sandbox-<name>
   $ git log sandbox-<name>/feat/task-a
   $ git log sandbox-<name>/feat/task-b
   ```

4. Check out the branches you want to keep and open PRs as normal.

## Host worktree

You can create a Git worktree on your host and point the sandbox at it. The
agent edits files directly in the worktree — but because the sandbox mounts
only the worktree directory (not the parent repository), it can't resolve the
`.git` pointer file and has no Git access. The agent can read and write files,
but can't commit, branch, or check status.

This is useful when you want branch isolation without the create-time
commitment of clone mode, and you're comfortable committing from the host
yourself after reviewing the changes.

1. Create the worktree on the host:

   ```console
   $ git worktree add -b feat/my-feature ../my-feature-work
   ```

2. Start the sandbox with the worktree as the workspace:

   ```console
   $ sbx run claude ../my-feature-work
   ```

3. The agent edits files. When it's done, commit and push from the host:

   ```console
   $ cd ../my-feature-work
   $ git diff
   $ git add -p && git commit
   $ git push -u origin feat/my-feature
   $ gh pr create
   ```

## Commit signing

SSH agent forwarding is enabled by default. When `SSH_AUTH_SOCK` is set,
sandboxes forward your host SSH agent into the sandbox, so the agent can sign
commits with your SSH key without the private key ever leaving your host. If
you turned off forwarding or use a fixed SSH agent socket, see
[SSH agent configuration](../configuration/credentials.md#ssh-agent).

1. Make sure the signing key is loaded in your host SSH agent:

   ```console
   $ ssh-add ~/.ssh/id_ed25519
   $ ssh-add -L  # confirm the key appears
   ```

2. Inside the sandbox, configure Git to sign with SSH. Use the forwarded key
   directly rather than a file path, since host paths don't exist inside the
   sandbox:

   ```console
   $ git config --global gpg.format ssh
   $ git config --global user.signingkey "key::$(ssh-add -L | head -n 1)"
   ```

3. Sign commits as usual:

   ```console
   $ git commit -S -m "feat: my change"
   ```

To apply this configuration automatically to every sandbox, use the
[`git-ssh-sign`](https://github.com/docker/sbx-kits-contrib/tree/main/git-ssh-sign)
community kit, which handles all of the above setup. See [Kits](../customize/kits.md)
if you want to package it alongside other sandbox customizations.

For troubleshooting, see
[Sandbox commits aren't signed](../troubleshooting.md#sandbox-commits-arent-signed).


---

# Docker Build

*Sección: Build*

Docker Build is one of Docker Engine's most used features. Whenever you are
creating an image you are using Docker Build. Build is a key part of your
software development life cycle allowing you to package and bundle your code and
ship it anywhere.

Docker Build is more than a command for building images, and it's not only about
packaging your code. It's a whole ecosystem of tools and features that support
not only common workflow tasks but also provides support for more complex and
advanced scenarios.

{{< grid >}}


---

# Bake

*Sección: Build*

Bake is a feature of Docker Buildx that lets you define your build configuration
using a declarative file, as opposed to specifying a complex CLI expression. It
also lets you run multiple builds concurrently with a single invocation.

A Bake file can be written in HCL or JSON format. Bake can also build directly
from a [Docker Compose file](compose-file.md). Here's an example Bake file in
HCL format:

```hcl {title=docker-bake.hcl}
group "default" {
  targets = ["frontend", "backend"]
}

target "frontend" {
  context = "./frontend"
  dockerfile = "frontend.Dockerfile"
  args = {
    NODE_VERSION = "22"
  }
  tags = ["myapp/frontend:latest"]
}

target "backend" {
  context = "./backend"
  dockerfile = "backend.Dockerfile"
  args = {
    GO_VERSION = "{{% param "example_go_version" %}}"
  }
  tags = ["myapp/backend:latest"]
}
```

The `group` block defines a group of targets that can be built concurrently.
Each `target` block defines a build target with its own configuration, such as
the build context, Dockerfile, and tags.

To invoke a build using the above Bake file, you can run:

```console
$ docker buildx bake
```

This executes the `default` group, which builds the `frontend` and `backend`
targets concurrently.

## Get started

To learn how to get started with Bake, head over to the [Bake introduction](introduction.md).


---

# Building with Bake from a Compose file

*Sección: Build*

Bake supports the [Compose file format](../../reference/compose-file/index.md)
to parse a Compose file and translate each service to a [target](reference.md#target).

```yaml
# compose.yaml
services:
  webapp-dev:
    build: &build-dev
      dockerfile: Dockerfile.webapp
      tags:
        - docker.io/username/webapp:latest
      cache_from:
        - docker.io/username/webapp:cache
      cache_to:
        - docker.io/username/webapp:cache

  webapp-release:
    build:
      <<: *build-dev
      x-bake:
        platforms:
          - linux/amd64
          - linux/arm64

  db:
    image: docker.io/username/db
    build:
      dockerfile: Dockerfile.db
```

```console
$ docker buildx bake --print
```

```json
{
  "group": {
    "default": {
      "targets": ["db", "webapp-dev", "webapp-release"]
    }
  },
  "target": {
    "db": {
      "context": ".",
      "dockerfile": "Dockerfile.db",
      "tags": ["docker.io/username/db"]
    },
    "webapp-dev": {
      "context": ".",
      "dockerfile": "Dockerfile.webapp",
      "tags": ["docker.io/username/webapp:latest"],
      "cache-from": [
        {
          "ref": "docker.io/username/webapp:cache",
          "type": "registry"
        }
      ],
      "cache-to": [
        {
          "ref": "docker.io/username/webapp:cache",
          "type": "registry"
        }
      ]
    },
    "webapp-release": {
      "context": ".",
      "dockerfile": "Dockerfile.webapp",
      "tags": ["docker.io/username/webapp:latest"],
      "cache-from": [
        {
          "ref": "docker.io/username/webapp:cache",
          "type": "registry"
        }
      ],
      "cache-to": [
        {
          "ref": "docker.io/username/webapp:cache",
          "type": "registry"
        }
      ],
      "platforms": ["linux/amd64", "linux/arm64"]
    }
  }
}
```

The compose format has some limitations compared to the HCL format:

- Specifying variables or global scope attributes is not supported
- `inherits` service field is not supported, but you can use [YAML anchors](../../reference/compose-file/fragments.md)
  to reference other services, as demonstrated in the previous example with `&build-dev`.

## `.env` file

You can declare default environment variables in an environment file named
`.env`. This file will be loaded from the current working directory,
where the command is executed and applied to compose definitions passed
with `-f`.

```yaml
# compose.yaml
services:
  webapp:
    image: docker.io/username/webapp:${TAG:-v1.0.0}
    build:
      dockerfile: Dockerfile
```

```sh
# .env
TAG=v1.1.0
```

```console
$ docker buildx bake --print
```

```json
{
  "group": {
    "default": {
      "targets": ["webapp"]
    }
  },
  "target": {
    "webapp": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": ["docker.io/username/webapp:v1.1.0"]
    }
  }
}
```

> [!NOTE]
>
> System environment variables take precedence over environment variables
> in `.env` file.

## Extension field with `x-bake`

Where some fields are not available in the compose specification, you can use
the [special extension](../../reference/compose-file/extension.md) field
`x-bake` in your compose file to evaluate extra fields:

```yaml
# compose.yaml
services:
  addon:
    image: ct-addon:bar
    build:
      context: .
      dockerfile: ./Dockerfile
      args:
        CT_ECR: foo
        CT_TAG: bar
      x-bake:
        tags:
          - ct-addon:foo
          - ct-addon:alp
        platforms:
          - linux/amd64
          - linux/arm64
        cache-from:
          - user/app:cache
          - type=local,src=path/to/cache
        cache-to:
          - type=local,dest=path/to/cache
        pull: true

  aws:
    image: ct-fake-aws:bar
    build:
      dockerfile: ./aws.Dockerfile
      args:
        CT_ECR: foo
        CT_TAG: bar
      x-bake:
        secret:
          - id=mysecret,src=./secret
          - id=mysecret2,src=./secret2
        platforms: linux/arm64
        output: type=docker
        no-cache: true
```

```console
$ docker buildx bake --print
```

```json
{
  "group": {
    "default": {
      "targets": ["addon", "aws"]
    }
  },
  "target": {
    "addon": {
      "context": ".",
      "dockerfile": "./Dockerfile",
      "args": {
        "CT_ECR": "foo",
        "CT_TAG": "bar"
      },
      "tags": ["ct-addon:foo", "ct-addon:alp"],
      "cache-from": [
        {
          "ref": "user/app:cache",
          "type": "registry"
        },
        {
          "src": "path/to/cache",
          "type": "local"
        }
      ],
      "cache-to": [
        {
          "dest": "path/to/cache",
          "type": "local"
        }
      ],
      "platforms": ["linux/amd64", "linux/arm64"],
      "pull": true
    },
    "aws": {
      "context": ".",
      "dockerfile": "./aws.Dockerfile",
      "args": {
        "CT_ECR": "foo",
        "CT_TAG": "bar"
      },
      "tags": ["ct-fake-aws:bar"],
      "secret": [
        {
          "id": "mysecret",
          "src": "./secret"
        },
        {
          "id": "mysecret2",
          "src": "./secret2"
        }
      ],
      "platforms": ["linux/arm64"],
      "output": [
        {
          "type": "docker"
        }
      ],
      "no-cache": true
    }
  }
}
```

Complete list of valid fields for `x-bake`:

- `cache-from`
- `cache-to`
- `contexts`
- `no-cache`
- `no-cache-filter`
- `output`
- `platforms`
- `pull`
- `secret`
- `ssh`
- `tags`


---

# Using Bake with additional contexts

*Sección: Build*

In addition to the main `context` key that defines the build context, each
target can also define additional named contexts with a map defined with key
`contexts`. These values map to the `--build-context` flag in the [build
command](/reference/cli/docker/buildx/build/#build-context).

Inside the Dockerfile these contexts can be used with the `FROM` instruction or
`--from` flag.

Supported context values are:

- Local filesystem directories
- Container images
- Git URLs
- HTTP URLs
- Name of another target in the Bake file

## Pinning alpine image

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
FROM alpine
RUN echo "Hello world"
```

```hcl {title=docker-bake.hcl}
target "app" {
  contexts = {
    alpine = "docker-image://alpine:3.13"
  }
}
```

## Using a secondary source directory

```dockerfile {title=Dockerfile}
FROM golang
COPY --from=src . .
```

```hcl {title=docker-bake.hcl}
# Running `docker buildx bake app` will result in `src` not pointing
# to some previous build stage but to the client filesystem, not part of the context.
target "app" {
  contexts = {
    src = "../path/to/source"
  }
}
```

## Using a target as a build context

To use a result of one target as a build context of another, specify the target
name with `target:` prefix.

```dockerfile {title=baseapp.Dockerfile}
FROM scratch
```

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
FROM baseapp
RUN echo "Hello world"
```

```hcl {title=docker-bake.hcl}
target "base" {
  dockerfile = "baseapp.Dockerfile"
}

target "app" {
  contexts = {
    baseapp = "target:base"
  }
}
```

In most cases you should just use a single multi-stage Dockerfile with multiple
targets for similar behavior. This case is only recommended when you have
multiple Dockerfiles that can't be easily merged into one.


---

# Expression evaluation in Bake

*Sección: Build*

Bake files in the HCL format support expression evaluation, which lets you
perform arithmetic operations, conditionally set values, and more.

## Arithmetic operations

You can perform arithmetic operations in expressions. The following example
shows how to multiply two numbers.

```hcl {title=docker-bake.hcl}
sum = 7*6

target "default" {
  args = {
    answer = sum
  }
}
```

Printing the Bake file with the `--print` flag shows the evaluated value for
the `answer` build argument.

```console
$ docker buildx bake --print
```

```json
{
  "target": {
    "default": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "answer": "42"
      }
    }
  }
}
```

## Ternary operators

You can use ternary operators to conditionally register a value.

The following example adds a tag only when a variable is not empty, using the
built-in `notequal` [function](funcs.md).

```hcl {title=docker-bake.hcl}
variable "TAG" {}

target "default" {
  context="."
  dockerfile="Dockerfile"
  tags = [
    "my-image:latest",
    notequal("",TAG) ? "my-image:${TAG}": ""
  ]
}
```

In this case, `TAG` is an empty string, so the resulting build configuration
only contains the hard-coded `my-image:latest` tag.

```console
$ docker buildx bake --print
```

```json
{
  "target": {
    "default": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": ["my-image:latest"]
    }
  }
}
```

## Expressions with variables

You can use expressions with [variables](variables.md) to conditionally set
values, or to perform arithmetic operations.

The following example uses expressions to set values based on the value of
variables. The `v1` build argument is set to "higher" if the variable `FOO` is
greater than 5, otherwise it is set to "lower". The `v2` build argument is set
to "yes" if the `IS_FOO` variable is true, otherwise it is set to "no".

```hcl {title=docker-bake.hcl}
variable "FOO" {
  default = 3
}

variable "IS_FOO" {
  default = true
}

target "app" {
  args = {
    v1 = FOO > 5 ? "higher" : "lower"
    v2 = IS_FOO ? "yes" : "no"
  }
}
```

Printing the Bake file with the `--print` flag shows the evaluated values for
the `v1` and `v2` build arguments.

```console
$ docker buildx bake --print app
```

```json
{
  "group": {
    "default": {
      "targets": ["app"]
    }
  },
  "target": {
    "app": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "v1": "lower",
        "v2": "yes"
      }
    }
  }
}
```


---

# Functions

*Sección: Build*

HCL functions are great for when you need to manipulate values in your build
configuration in more complex ways than just concatenation or interpolation.

## Standard library

Bake ships with built-in support for the [standard library functions](/manuals/build/bake/stdlib.md).

The following example shows the `add` function:

```hcl {title=docker-bake.hcl}
variable "TAG" {
  default = "latest"
}

group "default" {
  targets = ["webapp"]
}

target "webapp" {
  args = {
    buildno = "${add(123, 1)}"
  }
}
```

```console
$ docker buildx bake --print webapp
```

```json
{
  "group": {
    "default": {
      "targets": ["webapp"]
    }
  },
  "target": {
    "webapp": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "buildno": "124"
      }
    }
  }
}
```

## User-defined functions

You can create [user-defined functions](https://github.com/hashicorp/hcl/tree/main/ext/userfunc)
that do just what you want, if the built-in standard library functions don't
meet your needs.

The following example defines an `increment` function.

```hcl {title=docker-bake.hcl}
function "increment" {
  params = [number]
  result = number + 1
}

group "default" {
  targets = ["webapp"]
}

target "webapp" {
  args = {
    buildno = "${increment(123)}"
  }
}
```

```console
$ docker buildx bake --print webapp
```

```json
{
  "group": {
    "default": {
      "targets": ["webapp"]
    }
  },
  "target": {
    "webapp": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "buildno": "124"
      }
    }
  }
}
```

## Variables in functions

You can make references to [variables](./variables) and standard library
functions inside your functions.

The following example uses a global variable (`REPO`) in a custom function.

```hcl {title=docker-bake.hcl}
# docker-bake.hcl
variable "REPO" {
  default = "user/repo"
}

function "tag" {
  params = [tag]
  result = ["${REPO}:${tag}"]
}

target "webapp" {
  tags = tag("v1")
}
```

Printing the Bake file with the `--print` flag shows that the `tag` function
uses the value of `REPO` to set the prefix of the tag.

```console
$ docker buildx bake --print webapp
```

```json
{
  "group": {
    "default": {
      "targets": ["webapp"]
    }
  },
  "target": {
    "webapp": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": ["user/repo:v1"]
    }
  }
}
```


---

# Inheritance in Bake

*Sección: Build*

Targets can inherit attributes from other targets, using the `inherits`
attribute. For example, imagine that you have a target that builds a Docker
image for a development environment:

```hcl {title=docker-bake.hcl}
target "app-dev" {
  args = {
    GO_VERSION = "{{% param example_go_version %}}"
  }
  tags = ["docker.io/username/myapp:dev"]
  labels = {
    "org.opencontainers.image.source" = "https://github.com/username/myapp"
    "org.opencontainers.image.author" = "moby.whale@example.com"
  }
}
```

You can create a new target that uses the same build configuration, but with
slightly different attributes for a production build. In this example, the
`app-release` target inherits the `app-dev` target, but overrides the `tags`
attribute and adds a new `platforms` attribute:

```hcl {title=docker-bake.hcl}
target "app-release" {
  inherits = ["app-dev"]
  tags = ["docker.io/username/myapp:latest"]
  platforms = ["linux/amd64", "linux/arm64"]
}
```

## Common reusable targets

One common inheritance pattern is to define a common target that contains
shared attributes for all or many of the build targets in the project. For
example, the following `_common` target defines a common set of build
arguments:

```hcl {title=docker-bake.hcl}
target "_common" {
  args = {
    GO_VERSION = "{{% param example_go_version %}}"
    BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
  }
}
```

You can then inherit the `_common` target in other targets to apply the shared
attributes:

```hcl {title=docker-bake.hcl}
target "lint" {
  inherits = ["_common"]
  dockerfile = "./dockerfiles/lint.Dockerfile"
  output = [{ type = "cacheonly" }]
}

target "docs" {
  inherits = ["_common"]
  dockerfile = "./dockerfiles/docs.Dockerfile"
  output = ["./docs/reference"]
}

target "test" {
  inherits = ["_common"]
  target = "test-output"
  output = ["./test"]
}

target "binaries" {
  inherits = ["_common"]
  target = "binaries"
  output = ["./build"]
  platforms = ["local"]
}
```

## Overriding inherited attributes

When a target inherits another target, it can override any of the inherited
attributes. For example, the following target overrides the `args` attribute
from the inherited target:

```hcl {title=docker-bake.hcl}
target "app-dev" {
  inherits = ["_common"]
  args = {
    GO_VERSION = "1.17"
  }
  tags = ["docker.io/username/myapp:dev"]
}
```

The `GO_VERSION` argument in `app-release` is set to `1.17`, overriding the
`GO_VERSION` argument from the `app-dev` target.

For more information about overriding attributes, see the [Overriding
configurations](overrides.md) page.

## Inherit from multiple targets

The `inherits` attribute is a list, meaning you can reuse attributes from
multiple other targets. In the following example, the app-release target reuses
attributes from both the `app-dev` and `_common` targets.

```hcl {title=docker-bake.hcl}
target "_common" {
  args = {
    GO_VERSION = "{{% param example_go_version %}}"
    BUILDKIT_CONTEXT_KEEP_GIT_DIR = 1
  }
}

target "app-dev" {
  inherits = ["_common"]
  args = {
    BUILDKIT_CONTEXT_KEEP_GIT_DIR = 0
  }
  tags = ["docker.io/username/myapp:dev"]
  labels = {
    "org.opencontainers.image.source" = "https://github.com/username/myapp"
    "org.opencontainers.image.author" = "moby.whale@example.com"
  }
}

target "app-release" {
  inherits = ["app-dev", "_common"]
  tags = ["docker.io/username/myapp:latest"]
  platforms = ["linux/amd64", "linux/arm64"]
}
```

When inheriting attributes from multiple targets and there's a conflict, the
target that appears last in the inherits list takes precedence. The previous
example defines the `BUILDKIT_CONTEXT_KEEP_GIT_DIR` in the `_common` target and
overrides it in the `app-dev` target.

The `app-release` target inherits both `app-dev` target and the `_common` target.
The `BUILDKIT_CONTEXT_KEEP_GIT_DIR` argument is set to 0 in the `app-dev` target
and 1 in the `_common` target. The `BUILDKIT_CONTEXT_KEEP_GIT_DIR` argument in
the `app-release` target is set to 1, not 0, because the `_common` target appears
last in the inherits list.

## Reusing single attributes from targets

If you only want to inherit a single attribute from a target, you can reference
an attribute from another target using dot notation. For example, in the
following Bake file, the `bar` target reuses the `tags` attribute from the
`foo` target:

```hcl {title=docker-bake.hcl}
target "foo" {
  dockerfile = "foo.Dockerfile"
  tags       = ["myapp:latest"]
}
target "bar" {
  dockerfile = "bar.Dockerfile"
  tags       = target.foo.tags
}
```


---

# Introduction to Bake

*Sección: Build*

Bake is an abstraction for the `docker build` command that lets you more easily
manage your build configuration (CLI flags, environment variables, etc.) in a
consistent way for everyone on your team.

Bake is a command built into the Buildx CLI, so as long as you have Buildx
installed, you also have access to bake, via the `docker buildx bake` command.

## Building a project with Bake

Here's a simple example of a `docker build` command:

```console
$ docker build -f Dockerfile -t myapp:latest .
```

This command builds the Dockerfile in the current directory and tags the
resulting image as `myapp:latest`.

To express the same build configuration using Bake:

```hcl {title=docker-bake.hcl}
target "myapp" {
  context = "."
  dockerfile = "Dockerfile"
  tags = ["myapp:latest"]
}
```

Bake provides a structured way to manage your build configuration, and it saves
you from having to remember all the CLI flags for `docker build` every time.
With this file, building the image is as simple as running:

```console
$ docker buildx bake myapp
```

For simple builds, the difference between `docker build` and `docker buildx
bake` is minimal. However, as your build configuration grows more complex, Bake
provides a more structured way to manage that complexity, that would be
difficult to manage with CLI flags for the `docker build`. It also provides a
way to share build configurations across your team, so that everyone is
building images in a consistent way, with the same configuration.

## The Bake file format

You can write Bake files in HCL or JSON. Bake can also read
[Docker Compose files](compose-file.md) and translate each service to a build
target. HCL is the most expressive and flexible format, which is why you'll see
it used in most of the examples in this documentation, and in projects that use
Bake.

The properties that can be set for a target closely resemble the CLI flags for
`docker build`. For instance, consider the following `docker build` command:

```console
$ docker build \
  -f Dockerfile \
  -t myapp:latest \
  --build-arg foo=bar \
  --no-cache \
  --platform linux/amd64,linux/arm64 \
  .
```

The Bake equivalent would be:

```hcl {title=docker-bake.hcl}
target "myapp" {
  context = "."
  dockerfile = "Dockerfile"
  tags = ["myapp:latest"]
  args = {
    foo = "bar"
  }
  no-cache = true
  platforms = ["linux/amd64", "linux/arm64"]
}
```

> [!TIP]
>
> Want a better editing experience for Bake files in VS Code?
> Check out the [Docker DX](https://marketplace.visualstudio.com/items?itemName=docker.docker) extension for linting, code navigation, and vulnerability scanning.

## Next steps

To learn more about using Bake, see the following topics:

- Learn how to define and use [targets](targets.md) in Bake
- To see all the properties that can be set for a target, refer to the
  [Bake file reference](/build/bake/reference/).


---

# Matrix targets

*Sección: Build*

A matrix strategy lets you fork a single target into multiple different
variants, based on parameters that you specify. This works in a similar way to
[Matrix strategies for GitHub Actions](https://docs.github.com/en/actions/using-jobs/using-a-matrix-for-your-jobs).
You can use this to reduce duplication in your Bake definition.

The matrix attribute is a map of parameter names to lists of values. Bake
builds each possible combination of values as a separate target.

Each generated target must have a unique name. To specify how target names
should resolve, use the name attribute.

The following example resolves the app target to `app-foo` and `app-bar`. It
also uses the matrix value to define the [target build stage](/build/bake/reference/#targettarget).

```hcl {title=docker-bake.hcl}
target "app" {
  name = "app-${tgt}"
  matrix = {
    tgt = ["foo", "bar"]
  }
  target = tgt
}
```

```console
$ docker buildx bake --print app
[+] Building 0.0s (0/0)
{
  "group": {
    "app": {
      "targets": [
        "app-foo",
        "app-bar"
      ]
    },
    "default": {
      "targets": [
        "app"
      ]
    }
  },
  "target": {
    "app-bar": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "target": "bar"
    },
    "app-foo": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "target": "foo"
    }
  }
}
```

## Multiple axes

You can specify multiple keys in your matrix to fork a target on multiple axes.
When using multiple matrix keys, Bake builds every possible variant.

The following example builds four targets:

- `app-foo-1-0`
- `app-foo-2-0`
- `app-bar-1-0`
- `app-bar-2-0`

```hcl {title=docker-bake.hcl}
target "app" {
  name = "app-${tgt}-${replace(version, ".", "-")}"
  matrix = {
    tgt = ["foo", "bar"]
    version = ["1.0", "2.0"]
  }
  target = tgt
  args = {
    VERSION = version
  }
}
```

## Multiple values per matrix target

If you want to differentiate the matrix on more than just a single value, you
can use maps as matrix values. Bake creates a target for each map, and you can
access the nested values using dot notation.

The following example builds two targets:

- `app-foo-1-0`
- `app-bar-2-0`

```hcl {title=docker-bake.hcl}
target "app" {
  name = "app-${item.tgt}-${replace(item.version, ".", "-")}"
  matrix = {
    item = [
      {
        tgt = "foo"
        version = "1.0"
      },
      {
        tgt = "bar"
        version = "2.0"
      }
    ]
  }
  target = item.tgt
  args = {
    VERSION = item.version
  }
}
```


---

# Overriding configurations

*Sección: Build*

Bake supports loading build definitions from files, but sometimes you need even
more flexibility to configure these definitions. For example, you might want to
override an attribute when building in a particular environment or for a
specific target.

The following list of attributes can be overridden:

- `args`
- `attest`
- `cache-from`
- `cache-to`
- `context`
- `contexts`
- `dockerfile`
- `entitlements`
- `labels`
- `network`
- `no-cache`
- `output`
- `platform`
- `pull`
- `secrets`
- `ssh`
- `tags`
- `target`

To override these attributes, you can use the following methods:

- [File overrides](#file-overrides)
- [CLI overrides](#command-line)
- [Environment variable overrides](#environment-variables)

## File overrides

You can load multiple Bake files that define build configurations for your
targets. This is useful when you want to separate configurations into different
files for better organization, or to conditionally override configurations
based on which files are loaded.

### Default file lookup

You can use the `--file` or `-f` flag to specify which files to load.
If you don't specify any files, Bake will use the following lookup order:

1. `compose.yaml`
2. `compose.yml`
3. `docker-compose.yml`
4. `docker-compose.yaml`
5. `docker-bake.json`
6. `docker-bake.hcl`
7. `docker-bake.override.json`
8. `docker-bake.override.hcl`

If more than one Bake file is found, all files are loaded and merged into a
single definition. Files are merged according to the lookup order.

```console
$ docker buildx bake --print
[+] Building 0.0s (1/1) FINISHED                                                                                                                                                                                            
 => [internal] load local bake definitions                                                                                                                                                                             0.0s
 => => reading compose.yaml 45B / 45B                                                                                                                                                                                  0.0s
 => => reading docker-bake.hcl 113B / 113B                                                                                                                                                                             0.0s
 => => reading docker-bake.override.hcl 65B / 65B
```

If merged files contain duplicate attribute definitions, those definitions are
either merged or overridden by the last occurrence, depending on the attribute.

Bake will attempt to load all of the files in the order they are found. If
multiple files define the same target, attributes are either merged or
overridden. In the case of overrides, the last one loaded takes precedence.

For example, given the following files:

```hcl {title=docker-bake.hcl}
variable "TAG" {
  default = "foo"
}

target "default" {
  tags = ["username/my-app:${TAG}"]
}
```

```hcl {title=docker-bake.override.hcl}
variable "TAG" {
  default = "bar"
}
```

Since `docker-bake.override.hcl` is loaded last in the default lookup order,
the `TAG` variable is overridden with the value `bar`.

```console
$ docker buildx bake --print
{
  "target": {
    "default": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": ["username/my-app:bar"]
    }
  }
}
```

### Manual file overrides

You can use the `--file` flag to explicitly specify which files to load,
and use this as a way to conditionally apply override files.

For example, you can create a file that defines a set of configurations for a
specific environment, and load it only when building for that environment. The
following example shows how to load an `override.hcl` file that sets the `TAG`
variable to `bar`. The `TAG` variable is then used in the `default` target.

```hcl {title=docker-bake.hcl}
variable "TAG" {
  default = "foo"
}

target "default" {
  tags = ["username/my-app:${TAG}"]
}
```

```hcl {title=overrides.hcl}
variable "TAG" {
  default = "bar"
}
```

Printing the build configuration without the `--file` flag shows the `TAG`
variable is set to the default value `foo`.

```console
$ docker buildx bake --print
{
  "target": {
    "default": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": [
        "username/my-app:foo"
      ]
    }
  }
}
```

Using the `--file` flag to load the `overrides.hcl` file overrides the `TAG`
variable with the value `bar`.

```console
$ docker buildx bake -f docker-bake.hcl -f overrides.hcl --print
{
  "target": {
    "default": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": [
        "username/my-app:bar"
      ]
    }
  }
}
```

## Command line

You can also override target configurations from the command line with the
[`--set` flag](/reference/cli/docker/buildx/bake/#set):

```hcl
# docker-bake.hcl
target "app" {
  args = {
    mybuildarg = "foo"
  }
}
```

```console
$ docker buildx bake --set app.args.mybuildarg=bar --set app.platform=linux/arm64 app --print
```

```json
{
  "group": {
    "default": {
      "targets": ["app"]
    }
  },
  "target": {
    "app": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "mybuildarg": "bar"
      },
      "platforms": ["linux/arm64"]
    }
  }
}
```

> [!NOTE]
>
> `--set` is a repeatable flag. For array fields such as `tags`, repeat `--set` to provide multiple values or use the `+=` operator to append without replacing.
> Array literal syntax like `--set target.tags=[a,b]` is not supported.

Pattern matching syntax defined in [https://golang.org/pkg/path/#Match](https://golang.org/pkg/path/#Match)
is also supported:

```console
$ docker buildx bake --set foo*.args.mybuildarg=value  # overrides build arg for all targets starting with "foo"
$ docker buildx bake --set *.platform=linux/arm64      # overrides platform for all targets
$ docker buildx bake --set foo*.no-cache               # bypass caching only for targets starting with "foo"
```

Complete list of attributes that can be overridden with `--set` are:

- `args`
- `attest`
- `cache-from`
- `cache-to`
- `context`
- `contexts`
- `dockerfile`
- `entitlements`
- `labels`
- `network`
- `no-cache`
- `output`
- `platform`
- `pull`
- `secrets`
- `ssh`
- `tags`
- `target`

## Environment variables

You can also use environment variables to override configurations.

Bake lets you use environment variables to override the value of a `variable`
block. Only `variable` blocks can be overridden with environment variables.
This means you need to define the variables in the bake file and then set the
environment variable with the same name to override it.

The following example shows how you can define a `TAG` variable with a default
value in the Bake file, and override it with an environment variable.

```hcl
variable "TAG" {
  default = "latest"
}

target "default" {
  context = "."
  dockerfile = "Dockerfile"
  tags = ["docker.io/username/webapp:${TAG}"]
}
```

```console
$ export TAG=$(git rev-parse --short HEAD)
$ docker buildx bake --print webapp
```

The `TAG` variable is overridden with the value of the environment variable,
which is the short commit hash generated by `git rev-parse --short HEAD`.

```json
{
  "group": {
    "default": {
      "targets": ["webapp"]
    }
  },
  "target": {
    "webapp": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": ["docker.io/username/webapp:985e9e9"]
    }
  }
}
```

### Type coercion

Overriding non-string variables with environment variables is supported. Values
passed as environment variables are coerced into suitable types first.

The following example defines a `PORT` variable. The `backend` target uses the
`PORT` variable as-is, and the `frontend` target uses the value of `PORT`
incremented by one.

```hcl
variable "PORT" {
  default = 3000
}

group "default" {
  targets = ["backend", "frontend"]
}

target "backend" {
  args = {
    PORT = PORT
  }
}

target "frontend" {
  args = {
    PORT = add(PORT, 1)
  }
}
```

Overriding `PORT` using an environment variable will first coerce the value
into the expected type, an integer, before the expression in the `frontend`
target runs.

```console
$ PORT=7070 docker buildx bake --print
```

```json
{
  "group": {
    "default": {
      "targets": [
        "backend",
        "frontend"
      ]
    }
  },
  "target": {
    "backend": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "PORT": "7070"
      }
    },
    "frontend": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "args": {
        "PORT": "7071"
      }
    }
  }
}
```


---

# Remote Bake file definition

*Sección: Build*

You can build Bake files directly from a remote Git repository or HTTPS URL:

```console
$ docker buildx bake "https://github.com/docker/cli.git#v20.10.11" --print
#1 [internal] load git source https://github.com/docker/cli.git#v20.10.11
#1 0.745 e8f1871b077b64bcb4a13334b7146492773769f7       refs/tags/v20.10.11
#1 2.022 From https://github.com/docker/cli
#1 2.022  * [new tag]         v20.10.11  -> v20.10.11
#1 DONE 2.9s
```

This fetches the Bake definition from the specified remote location and
executes the groups or targets defined in that file. If the remote Bake
definition doesn't specify a build context, the context is automatically set to
the Git remote. For example, [this case](https://github.com/docker/cli/blob/2776a6d694f988c0c1df61cad4bfac0f54e481c8/docker-bake.hcl#L17-L26)
uses `https://github.com/docker/cli.git`:

```json
{
  "group": {
    "default": {
      "targets": ["binary"]
    }
  },
  "target": {
    "binary": {
      "context": "https://github.com/docker/cli.git#v20.10.11",
      "dockerfile": "Dockerfile",
      "args": {
        "BASE_VARIANT": "alpine",
        "GO_STRIP": "",
        "VERSION": ""
      },
      "target": "binary",
      "platforms": ["local"],
      "output": ["build"]
    }
  }
}
```

## Use the local context with a remote definition

When building with a remote Bake definition, you may want to consume local
files relative to the directory where the Bake command is executed. You can
define contexts as relative to the command context using a `cwd://` prefix.

```hcl {title="https://github.com/dvdksn/buildx/blob/bake-remote-example/docker-bake.hcl"}
target "default" {
  context = "cwd://"
  dockerfile-inline = <<EOT
FROM alpine
WORKDIR /src
COPY . .
RUN ls -l && stop
EOT
}
```

```console
$ touch foo bar
$ docker buildx bake "https://github.com/dvdksn/buildx.git#bake-remote-example"
```

```text
...
 > [4/4] RUN ls -l && stop:
#8 0.101 total 0
#8 0.102 -rw-r--r--    1 root     root             0 Jul 27 18:47 bar
#8 0.102 -rw-r--r--    1 root     root             0 Jul 27 18:47 foo
#8 0.102 /bin/sh: stop: not found
```

You can append a path to the `cwd://` prefix if you want to use a specific
local directory as a context. Note that if you do specify a path, it must be
within the working directory where the command gets executed. If you use an
absolute path, or a relative path leading outside of the working directory,
Bake will throw an error.

### Local named contexts

You can also use the `cwd://` prefix to define local directories in the Bake
execution context as named contexts.

The following example defines the `docs` context as `./src/docs/content`,
relative to the current working directory where Bake is run as a named context.

```hcl {title=docker-bake.hcl}
target "default" {
  contexts = {
    docs = "cwd://src/docs/content"
  }
  dockerfile = "Dockerfile"
}
```

By contrast, if you omit the `cwd://` prefix, the path would be resolved
relative to the build context.

## Specify the Bake definition to use

When loading a Bake file from a remote Git repository, if the repository
contains more than one Bake file, you can specify which Bake definition to use
with the `--file` or `-f` flag:

```console
docker buildx bake -f bake.hcl "https://github.com/crazy-max/buildx.git#remote-with-local"
```

```text
...
#4 [2/2] RUN echo "hello world"
#4 0.270 hello world
#4 DONE 0.3s
```

## Combine local and remote Bake definitions

You can also combine remote definitions with local ones using the `cwd://`
prefix with `-f`.

Given the following local Bake definition in the current working directory:

```hcl
# local.hcl
target "default" {
  args = {
    HELLO = "foo"
  }
}
```

The following example uses `-f` to specify two Bake definitions:

- `-f bake.hcl`: this definition is loaded relative to the Git URL.
- `-f cwd://local.hcl`: this definition is loaded relative to the current
  working directory where the Bake command is executed.

```console
docker buildx bake -f bake.hcl -f cwd://local.hcl "https://github.com/crazy-max/buildx.git#remote-with-local" --print
```

```json
{
  "target": {
    "default": {
      "context": "https://github.com/crazy-max/buildx.git#remote-with-local",
      "dockerfile": "Dockerfile",
      "args": {
        "HELLO": "foo"
      },
      "target": "build",
      "output": [
        {
          "type": "cacheonly"
        }
      ]
    }
  }
}
```

One case where combining local and remote Bake definitions becomes necessary is
when you're building with a remote Bake definition in GitHub Actions and want
to use the [metadata-action](https://github.com/docker/metadata-action) to
generate tags, annotations, or labels. The metadata action generates a Bake
file available in the runner's local Bake execution context. To use both the
remote definition and the local "metadata-only" Bake file, specify both files
and use the `cwd://` prefix for the metadata Bake file:

```yml
      - name: Build
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        with:
          files: |
            ./docker-bake.hcl
            cwd://${{ steps.meta.outputs.bake-file }}
          targets: build
```

## Remote definition in a private repository

If you want to use a remote definition that lives in a private repository,
you may need to specify credentials for Bake to use when fetching the definition.

If you can authenticate to the private repository using the default `SSH_AUTH_SOCK`,
then you don't need to specify any additional authentication parameters for Bake.
Bake automatically uses your default agent socket.

For authentication using an HTTP token, or custom SSH agents,
use the following environment variables to configure Bake's authentication strategy:

- [`BUILDX_BAKE_GIT_AUTH_TOKEN`](../building/variables.md#buildx_bake_git_auth_token)
- [`BUILDX_BAKE_GIT_AUTH_HEADER`](../building/variables.md#buildx_bake_git_auth_header)
- [`BUILDX_BAKE_GIT_SSH`](../building/variables.md#buildx_bake_git_ssh)


---

# Bake targets

*Sección: Build*

A target in a Bake file represents a build invocation. It holds all the
information you would normally pass to a `docker build` command using flags.

```hcl {title=docker-bake.hcl}
target "webapp" {
  dockerfile = "webapp.Dockerfile"
  tags = ["docker.io/username/webapp:latest"]
  context = "https://github.com/username/webapp"
}
```

To build a target with Bake, pass name of the target to the `bake` command.

```console
$ docker buildx bake webapp
```

You can build multiple targets at once by passing multiple target names to the
`bake` command.

```console
$ docker buildx bake webapp api tests
```

## Default target

If you don't specify a target when running `docker buildx bake`, Bake will
build the target named `default`.

```hcl {title=docker-bake.hcl}
target "default" {
  dockerfile = "webapp.Dockerfile"
  tags = ["docker.io/username/webapp:latest"]
  context = "https://github.com/username/webapp"
}
```

To build this target, run `docker buildx bake` without any arguments:

```console
$ docker buildx bake
```

## Target properties

The properties you can set for a target closely resemble the CLI flags for
`docker build`, with a few additional properties that are specific to Bake.

The `dockerfile` property specifies the path to the Dockerfile for a target.
If you also set a `context`, the `dockerfile` path resolves relative to that
context.

```hcl {title=docker-bake.hcl}
target "default" {
  context = "app"
  # resolves to app/src/www/Dockerfile
  dockerfile = "src/www/Dockerfile"
}
```

For all the properties you can set for a target, see the [Bake reference](/build/bake/reference#target).

## Grouping targets

You can group targets together using the `group` block. This is useful when you
want to build multiple targets at once.

```hcl {title=docker-bake.hcl}
group "all" {
  targets = ["webapp", "api", "tests"]
}

target "webapp" {
  dockerfile = "webapp.Dockerfile"
  tags = ["docker.io/username/webapp:latest"]
  context = "https://github.com/username/webapp"
}

target "api" {
  dockerfile = "api.Dockerfile"
  tags = ["docker.io/username/api:latest"]
  context = "https://github.com/username/api"
}

target "tests" {
  dockerfile = "tests.Dockerfile"
  contexts = {
    webapp = "target:webapp"
    api = "target:api"
  }
  output = ["type=local,dest=build/tests"]
  context = "."
}
```

To build all the targets in a group, pass the name of the group to the `bake`
command.

```console
$ docker buildx bake all
```

## Pattern matching for targets and groups

Bake supports shell-style wildcard patterns when specifying target or grouped targets.
This makes it easier to build multiple targets without listing each one explicitly.

Supported patterns:

- `*` matches any sequence of characters
- `?` matches any single character
- `[abc]` matches any character in brackets

> [!NOTE]
>
> Always wrap wildcard patterns in quotes. Without quotes, your shell will expand the
> wildcard to match files in the current directory, causing errors.

Examples:

```console
# Match all targets starting with 'foo-'
$ docker buildx bake "foo-*"

# Match all targets
$ docker buildx bake "*"

# Matches: foo-baz, foo-caz, foo-daz, etc.
$ docker buildx bake "foo-?az"

# Matches: foo-bar, boo-bar
$ docker buildx bake "[fb]oo-bar"

# Matches: mtx-a-b-d, mtx-a-b-e, mtx-a-b-f
$ docker buildx bake "mtx-a-b-*"
```

You can also combine multiple patterns:

```console
$ docker buildx bake "foo*" "tests"
```

## Additional resources

Refer to the following pages to learn more about Bake's features:

- Learn how to use [variables](variables.md) in Bake to make your build
  configuration more flexible.
- Learn how you can use matrices to build multiple images with different
  configurations in [Matrices](matrices.md).
- Head to the [Bake file reference](/build/bake/reference/) to learn about all
  the properties you can set in a Bake file, and its syntax.


---

# Variables in Bake

*Sección: Build*

You can define and use variables in a Bake file to set attribute values,
interpolate them into other values, and perform arithmetic operations.
Variables can be defined with default values, and can be overridden with
environment variables.

## Using variables as attribute values

Use the `variable` block to define a variable.

```hcl {title=docker-bake.hcl}
variable "TAG" {
  default = "docker.io/username/webapp:latest"
}
```

The following example shows how to use the `TAG` variable in a target.

```hcl {title=docker-bake.hcl}
target "webapp" {
  context = "."
  dockerfile = "Dockerfile"
  tags = [ TAG ]
}
```

## Interpolate variables into values

Bake supports string interpolation of variables into values. You can use the
`${}` syntax to interpolate a variable into a value. The following example
defines a `TAG` variable with a value of `latest`.

```hcl {title=docker-bake.hcl}
variable "TAG" {
  default = "latest"
}
```

To interpolate the `TAG` variable into the value of an attribute, use the
`${TAG}` syntax.

```hcl {title=docker-bake.hcl}
group "default" {
  targets = [ "webapp" ]
}

variable "TAG" {
  default = "latest"
}

target "webapp" {
  context = "."
  dockerfile = "Dockerfile"
  tags = ["docker.io/username/webapp:${TAG}"]
}
```

Printing the Bake file with the `--print` flag shows the interpolated value in
the resolved build configuration.

```console
$ docker buildx bake --print
```

```json
{
  "group": {
    "default": {
      "targets": ["webapp"]
    }
  },
  "target": {
    "webapp": {
      "context": ".",
      "dockerfile": "Dockerfile",
      "tags": ["docker.io/username/webapp:latest"]
    }
  }
}
```

## Validating variables

To verify that the value of a variable conforms to an expected type, value
range, or other condition, you can define custom validation rules using the
`validation` block.

In the following example, validation is used to enforce a numeric constraint on
a variable value; the `PORT` variable must be 1024 or greater.

```hcl {title=docker-bake.hcl}
# Define a variable `PORT` with a default value and a validation rule
variable "PORT" {
  default = 3000  # Default value assigned to `PORT`

  # Validation block to ensure `PORT` is a valid number within the acceptable range
  validation {
    condition = PORT >= 1024  # Ensure `PORT` is at least 1024
    error_message = "The variable 'PORT' must be 1024 or greater."  # Error message for invalid values
  }
}
```

If the `condition` expression evaluates to `false`, the variable value is
considered invalid, whereby the build invocation fails and `error_message` is
emitted. For example, if `PORT=443`, the condition evaluates to `false`, and
the error is raised.

Values are coerced into the expected type before the validation is set. This
ensures that any overrides set with environment variables work as expected.

### Validate multiple conditions

To evaluate more than one condition, define multiple `validation` blocks for
the variable. All conditions must be `true`.

Here’s an example:

```hcl {title=docker-bake.hcl}
# Define a variable `VAR` with multiple validation rules
variable "VAR" {
  # First validation block: Ensure the variable is not empty
  validation {
    condition = VAR != ""
    error_message = "The variable 'VAR' must not be empty."
  }

  # Second validation block: Ensure the value contains only alphanumeric characters
  validation {
    # VAR and the regex match must be identical:
    condition = VAR == regex("[a-zA-Z0-9]+", VAR)
    error_message = "The variable 'VAR' can only contain letters and numbers."
  }
}
```

This example enforces:

- The variable must not be empty.
- The variable must match a specific character set.

For invalid inputs like `VAR="hello@world"`, the validation would fail.

### Validating variable dependencies

You can reference other Bake variables in your condition expression, enabling
validations that enforce dependencies between variables. This ensures that
dependent variables are set correctly before proceeding.

Here’s an example:

```hcl {title=docker-bake.hcl}
# Define a variable `FOO`
variable "FOO" {}

# Define a variable `BAR` with a validation rule that references `FOO`
variable "BAR" {
  # Validation block to ensure `FOO` is set if `BAR` is used
  validation {
    condition = FOO != ""  # Check if `FOO` is not an empty string
    error_message = "The variable 'BAR' requires 'FOO' to be set."
  }
}
```

This configuration ensures that the `BAR` variable can only be used if `FOO`
has been assigned a non-empty value. Attempting to build without setting `FOO`
will trigger the validation error.

## Escape variable interpolation

If you want to bypass variable interpolation when parsing the Bake definition,
use double dollar signs (`$${VARIABLE}`).

```hcl {title=docker-bake.hcl}
target "webapp" {
  dockerfile-inline = <<EOF
  FROM alpine
  ARG TARGETARCH
  RUN echo "Building for $${TARGETARCH/amd64/x64}"
  EOF
  platforms = ["linux/amd64", "linux/arm64"]
}
```

```console
$ docker buildx bake --progress=plain
...
#8 [linux/arm64 2/2] RUN echo "Building for arm64"
#8 0.036 Building for arm64
#8 DONE 0.0s

#9 [linux/amd64 2/2] RUN echo "Building for x64"
#9 0.046 Building for x64
#9 DONE 0.1s
...
```

## Using variables in variables across files

When multiple files are specified, one file can use variables defined in
another file. In the following example, the `vars.hcl` file defines a
`BASE_IMAGE` variable with a default value of `docker.io/library/alpine`.

```hcl {title=vars.hcl}
variable "BASE_IMAGE" {
  default = "docker.io/library/alpine"
}
```

The following `docker-bake.hcl` file defines a `BASE_LATEST` variable that
references the `BASE_IMAGE` variable.

```hcl {title=docker-bake.hcl}
variable "BASE_LATEST" {
  default = "${BASE_IMAGE}:latest"
}

target "webapp" {
  contexts = {
    base = BASE_LATEST
  }
}
```

When you print the resolved build configuration, using the `-f` flag to specify
the `vars.hcl` and `docker-bake.hcl` files, you see that the `BASE_LATEST`
variable is resolved to `docker.io/library/alpine:latest`.

```console
$ docker buildx bake -f vars.hcl -f docker-bake.hcl --print app
```

```json
{
  "target": {
    "webapp": {
      "context": ".",
      "contexts": {
        "base": "docker.io/library/alpine:latest"
      },
      "dockerfile": "Dockerfile"
    }
  }
}
```

## Additional resources

Here are some additional resources that show how you can use variables in Bake:

- You can override `variable` values using environment variables. See
  [Overriding configurations](overrides.md#environment-variables) for more
  information.
- You can refer to and use global variables in functions. See [HCL
  functions](funcs.md#variables-in-functions)
- You can use variable values when evaluating expressions. See [Expression
  evaluation](expressions.md#expressions-with-variables)


---

# Builders

*Sección: Build*

A builder is a BuildKit daemon that you can use to run your builds. BuildKit
is the build engine that solves the build steps in a Dockerfile to produce a
container image or other artifacts.

You can create and manage builders, inspect them, and even connect to builders
running remotely. You interact with builders using the Docker CLI.

## Default builder

Docker Engine automatically creates a builder that becomes the default backend
for your builds. This builder uses the BuildKit library bundled with the
daemon. This builder requires no configuration.

The default builder is directly bound to the Docker daemon and its
[context](../../engine/manage-resources/contexts.md). If you change the
Docker context, your `default` builder refers to the new Docker context.

## Build drivers

Buildx implements a concept of [build drivers](drivers/index.md) to refer to
different builder configurations. The default builder created by the daemon
uses the [`docker` driver](drivers/docker.md).

Buildx supports the following build drivers:

- `docker`: uses the BuildKit library bundled into the Docker daemon.
- `docker-container`: creates a dedicated BuildKit container using Docker.
- `kubernetes`: creates BuildKit pods in a Kubernetes cluster.
- `remote`: connects directly to a manually managed BuildKit daemon.

## Selected builder

Selected builder refers to the builder that's used by default when you run
build commands.

When you run a build, or interact with builders in some way using the CLI,
you can use the optional `--builder` flag, or the `BUILDX_BUILDER`
[environment variable](../building/variables.md#buildx_builder),
to specify a builder by name. If you don't specify a builder,
the selected builder is used.

Use the `docker buildx ls` command to see the available builder instances.
The asterisk (`*`) next to a builder name indicates the selected builder.

```console
$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT      STATUS   BUILDKIT PLATFORMS
default *       docker
  default       default              running  v0.11.6  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
my_builder      docker-container
  my_builder0   default              running  v0.11.6  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
```

### Select a different builder

To switch between builders, use the `docker buildx use <name>` command.

After running this command, the builder you specify is automatically
selected when you invoke builds.

### Difference between `docker build` and `docker buildx build`

Even though `docker build` is an alias for `docker buildx build`, there are
subtle differences between the two commands. With Buildx, the build client and
the daemon (BuildKit) are decoupled. This means you can use multiple
builders from a single client, even remote ones.

The `docker build` command always defaults to using the default builder that
comes bundled with the Docker Engine, to ensure backwards compatibility with
older versions of the Docker CLI. The `docker buildx build` command, on the
other hand, checks whether you've set a different builder as the default
builder before it sends your build to BuildKit.

To use the `docker build` command with a non-default builder, you must either
specify the builder explicitly:

- Using the `--builder` flag:

  ```console
  $ docker build --builder my_builder .
  ```

- Or the `BUILDX_BUILDER` environment variable:

  ```console
  $ BUILDX_BUILDER=my_builder docker build .
  ```

<!-- vale Docker.We = NO -->

In general, we recommend that you use the `docker buildx build` command when
you want to use custom builders. This ensures that your [selected
builder](#selected-builder) configuration is interpreted correctly.

<!-- vale Docker.We = YES -->

## Additional information

- For information about how to interact with and manage builders,
  see [Manage builders](manage.md)
- To learn about different types of builders,
  see [Build drivers](drivers/index.md)


---

# Build drivers

*Sección: Build*

Build drivers are configurations for how and where the BuildKit backend runs.
Driver settings are customizable and allow fine-grained control of the builder.
Buildx supports the following drivers:

- `docker`: uses the BuildKit library bundled into the Docker daemon.
- `docker-container`: creates a dedicated BuildKit container using Docker.
- `cloud`: connects to a managed builder in Docker Build Cloud.
- `kubernetes`: creates BuildKit pods in a Kubernetes cluster.
- `remote`: connects directly to a manually managed BuildKit daemon.

Different drivers support different use cases. The default `docker` driver
prioritizes simplicity and ease of use. It has limited support for advanced
features like caching and output formats, and isn't configurable. Other drivers
provide more flexibility and are better at handling advanced scenarios.

The following table outlines some differences between drivers.

| Feature                      |  `docker`   | `docker-container` |     `cloud`      | `kubernetes` |      `remote`      |
| :--------------------------- | :---------: | :----------------: | :--------------: | :----------: | :----------------: |
| **Automatically load image** |     ✅      |                    |   Conditional    |              |                    |
| **Cache export**             |     ✅\*     |         ✅         |        ✅        |      ✅      |         ✅         |
| **Tarball output**           |             |         ✅         |        ✅        |      ✅      |         ✅         |
| **Multi-arch images**        |             |         ✅         |        ✅        |      ✅      |         ✅         |
| **BuildKit configuration**   |             |         ✅         | Managed by Docker |      ✅      | Managed externally |

\* _The `docker` driver doesn't support all cache export options.
See [Cache storage backends](../../cache/backends/index.md) for more information._

## Loading to local image store

The `docker` driver automatically loads images into the local image store.
With Docker Build Cloud, an untagged result remains in the cloud build cache
when you don't specify an output. Using `--tag` instead automatically loads the
image when the build targets a single platform and runs on one cloud node. With
other drivers, the build result remains in the build cache if you don't specify
an output.

To build an image using a driver that doesn't load results automatically, use
the `--load` flag with the build command:

   ```console
   $ docker buildx build --load -t <image> --builder=container .
   ...
   => exporting to oci image format                                                                                                      7.7s
   => => exporting layers                                                                                                                4.9s
   => => exporting manifest sha256:4e4ca161fa338be2c303445411900ebbc5fc086153a0b846ac12996960b479d3                                      0.0s
   => => exporting config sha256:adf3eec768a14b6e183a1010cb96d91155a82fd722a1091440c88f3747f1f53f                                        0.0s
   => => sending tarball                                                                                                                 2.8s
   => importing to docker
   ```

   With this option, the image is available in the image store after the build finishes:

   ```console
   $ docker image ls
   REPOSITORY                       TAG               IMAGE ID       CREATED             SIZE
   <image>                          latest            adf3eec768a1   2 minutes ago       197MB
   ```

### Load by default

{{< summary-bar feature_name="Load by default" >}}

You can configure the custom build drivers to behave in a similar way to the
default `docker` driver, and load images to the local image store by default.
To do so, set the `default-load` driver option when creating the builder:

```console
$ docker buildx create --driver-opt default-load=true
```

Note that, just like with the `docker` driver, if you specify a different
output format with `--output`, the result will not be loaded to the image store
unless you also explicitly specify `--output type=docker` or use the `--load`
flag.

## What's next

Read about each driver:

- [Docker driver](docker.md)
- [Docker container driver](docker-container.md)
- [Cloud driver](cloud.md)
- [Kubernetes driver](kubernetes.md)
- [Remote driver](remote.md)


---

# Cloud driver

*Sección: Build*

The Buildx cloud driver connects to managed BuildKit instances in Docker Build
Cloud. Docker provisions and maintains the builder infrastructure, shared build
cache, and native `linux/amd64` and `linux/arm64` nodes.

The cloud driver requires Buildx version 0.37.0 or later and access to Docker
Build Cloud.

## Synopsis

Before connecting Buildx, create a cloud builder on the
[Docker Build Cloud Dashboard](https://app.docker.com/build/). Then sign in and
connect to the builder:

```console
$ docker login
$ docker buildx create --driver cloud <ORG>/<BUILDER_NAME>
```

The command adds the cloud builder to your local Buildx configuration. It does
not create a builder in Docker Build Cloud.

For service prerequisites and authentication, see
[Docker Build Cloud setup](../../../build-cloud/setup.md). For build examples,
see [Building with Docker Build Cloud](../../../build-cloud/usage.md).


---

# Docker container driver

*Sección: Build*

The Docker container driver allows creation of a managed and customizable
BuildKit environment in a dedicated Docker container.

Using the Docker container driver has a couple of advantages over the default
Docker driver. For example:

- Specify custom BuildKit versions to use.
- Build multi-arch images, see [QEMU](#qemu)
- Advanced options for [cache import and export](../../cache/backends/index.md)

## Synopsis

Run the following command to create a new builder, named `container`, that uses
the Docker container driver:

```console
$ docker buildx create \
  --name container \
  --driver=docker-container \
  --driver-opt=[key=value,...]
container
```

The following table describes the available driver-specific options that you can
pass to `--driver-opt`:

| Parameter        | Type    | Default          | Description                                                                                                            |
| ---------------- | ------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `image`          | String  |                  | Sets the BuildKit image to use for the container.                                                                      |
| `memory`         | String  |                  | Sets the amount of memory the container can use.                                                                       |
| `memory-swap`    | String  |                  | Sets the memory swap limit for the container.                                                                          |
| `cpu-quota`      | String  |                  | Imposes a CPU CFS quota on the container.                                                                              |
| `cpu-period`     | String  |                  | Sets the CPU CFS scheduler period for the container.                                                                   |
| `cpu-shares`     | String  |                  | Configures CPU shares (relative weight) of the container.                                                              |
| `cpuset-cpus`    | String  |                  | Limits the set of CPU cores the container can use.                                                                     |
| `cpuset-mems`    | String  |                  | Limits the set of CPU memory nodes the container can use.                                                              |
| `default-load`   | Boolean | `false`          | Automatically load images to the Docker Engine image store.                                                            |
| `network`        | String  |                  | Sets the network mode for the container.                                                                               |
| `cgroup-parent`  | String  | `/docker/buildx` | Sets the cgroup parent of the container if Docker is using the "cgroupfs" driver.                                      |
| `restart-policy` | String  | `unless-stopped` | Sets the container's [restart policy](../../../engine/containers/start-containers-automatically.md#use-a-restart-policy).      |
| `env.<key>`      | String  |                  | Sets the environment variable `key` to the specified `value` in the container.                                         |
| `provenance-add-gha`   | Boolean |    `true`       | Automatically writes GitHub Actions context into the builder for provenance.                                                   |

Before you configure the resource limits for the container,
read about [configuring runtime resource constraints for containers](/engine/containers/resource_constraints/).

## Usage

When you run a build, Buildx pulls the specified `image` (by default,
[`moby/buildkit`](https://hub.docker.com/r/moby/buildkit)).
When the container has started, Buildx submits the build submitted to the
containerized build server.

```console
$ docker buildx build -t <image> --builder=container .
WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load
#1 [internal] booting buildkit
#1 pulling image moby/buildkit:buildx-stable-1
#1 pulling image moby/buildkit:buildx-stable-1 1.9s done
#1 creating container buildx_buildkit_container0
#1 creating container buildx_buildkit_container0 0.5s done
#1 DONE 2.4s
...
```

## Cache persistence

The `docker-container` driver supports cache persistence, as it stores all the
BuildKit state and related cache into a dedicated Docker volume.

To persist the `docker-container` driver's cache, even after recreating the
driver using `docker buildx rm` and `docker buildx create`, you can destroy the
builder using the `--keep-state` flag:

For example, to create a builder named `container` and then remove it while
persisting state:

```console
# setup a builder
$ docker buildx create --name=container --driver=docker-container --use --bootstrap
container
$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT              STATUS   BUILDKIT PLATFORMS
container *     docker-container
  container0    desktop-linux                running  v0.10.5  linux/amd64
$ docker volume ls
DRIVER    VOLUME NAME
local     buildx_buildkit_container0_state

# remove the builder while persisting state
$ docker buildx rm --keep-state container
$ docker volume ls
DRIVER    VOLUME NAME
local     buildx_buildkit_container0_state

# the newly created driver with the same name will have all the state of the previous one!
$ docker buildx create --name=container --driver=docker-container --use --bootstrap
container
```

## QEMU

The `docker-container` driver supports using [QEMU](https://www.qemu.org/)
(user mode) to build non-native platforms. Use the `--platform` flag to specify
which architectures that you want to build for.

For example, to build a Linux image for `amd64` and `arm64`:

```console
$ docker buildx build \
  --builder=container \
  --platform=linux/amd64,linux/arm64 \
  -t <registry>/<image> \
  --push .
```

> [!NOTE]
>
> Emulation with QEMU can be much slower than native builds, especially for
> compute-heavy tasks like compilation and compression or decompression.

## Custom network

You can customize the network that the builder container uses. This is useful
if you need to use a specific network for your builds.

For example, let's [create a network](/reference/cli/docker/network/create/)
named `foonet`:

```console
$ docker network create foonet
```

Now create a [`docker-container` builder](/reference/cli/docker/buildx/create/)
that will use this network:

```console
$ docker buildx create --use \
  --name mybuilder \
  --driver docker-container \
  --driver-opt "network=foonet"
```

Boot and [inspect `mybuilder`](/reference/cli/docker/buildx/inspect/):

```console
$ docker buildx inspect --bootstrap
```

[Inspect the builder container](/reference/cli/docker/inspect/)
and see what network is being used:

```console
$ docker inspect buildx_buildkit_mybuilder0 --format={{.NetworkSettings.Networks}}
map[foonet:0xc00018c0c0]
```

## Further reading

For more information on the Docker container driver, see the
[buildx reference](/reference/cli/docker/buildx/create/#driver).


---

# Docker driver

*Sección: Build*

The Buildx Docker driver is the default driver. It uses the BuildKit server
components built directly into the Docker Engine. The Docker driver requires no
configuration.

Unlike the other drivers, builders using the Docker driver can't be manually
created. They're only created automatically from the Docker context.

Images built with the Docker driver are automatically loaded to the local image
store.

## Synopsis

```console
# The Docker driver is used by buildx by default
docker buildx build .
```

It's not possible to configure which BuildKit version to use, or to pass any
additional BuildKit parameters to a builder using the Docker driver. The
BuildKit version and parameters are preset by the Docker Engine internally.

If you need additional configuration and flexibility, consider using the
[Docker container driver](docker-container.md).

## Further reading

For more information on the Docker driver, see the
[buildx reference](/reference/cli/docker/buildx/create/#driver).


---

# Kubernetes driver

*Sección: Build*

The Kubernetes driver lets you connect your local development or CI
environments to builders in a Kubernetes cluster to allow access to more
powerful compute resources, optionally on multiple native architectures.

## Synopsis

Run the following command to create a new builder, named `kube`, that uses the
Kubernetes driver:

```console
$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=[key=value,...]
```

The following table describes the available driver-specific options that you
can pass to `--driver-opt`:

| Parameter                                  | Type         | Default                                 | Description                                                                                                                                                                                                   |
| ------------------------------------------ | ------------ | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `image`                                    | String       |                                         | Sets the image to use for running BuildKit.                                                                                                                                                                   |
| `namespace`                                | String       | Namespace in current Kubernetes context | Sets the Kubernetes namespace.                                                                                                                                                                                |
| `default-load`                             | Boolean      | `false`                                 | Automatically load images to the Docker Engine image store.                                                                                                                                                   |
| `replicas`                                 | Integer      | 1                                       | Sets the number of Pod replicas to create. See [scaling BuildKit][1]                                                                                                                                          |
| `requests.cpu`                             | CPU units    |                                         | Sets the request CPU value specified in units of Kubernetes CPU. For example `requests.cpu=100m` or `requests.cpu=2`                                                                                          |
| `requests.memory`                          | Memory size  |                                         | Sets the request memory value specified in bytes or with a valid suffix. For example `requests.memory=500Mi` or `requests.memory=4G`                                                                          |
| `requests.ephemeral-storage`               | Storage size |                                         | Sets the request ephemeral-storage value specified in bytes or with a valid suffix. For example `requests.ephemeral-storage=2Gi`                                                                              |
| `persistent-volume-claim.requests.storage` | Storage size |                                         | Sets the requested size for a persistent volume claim. When set, Buildx creates a `StatefulSet` and stores the BuildKit build cache in the claim. For example `persistent-volume-claim.requests.storage=20Gi` |
| `limits.cpu`                               | CPU units    |                                         | Sets the limit CPU value specified in units of Kubernetes CPU. For example `requests.cpu=100m` or `requests.cpu=2`                                                                                            |
| `limits.memory`                            | Memory size  |                                         | Sets the limit memory value specified in bytes or with a valid suffix. For example `requests.memory=500Mi` or `requests.memory=4G`                                                                            |
| `limits.ephemeral-storage`                 | Storage size |                                         | Sets the limit ephemeral-storage value specified in bytes or with a valid suffix. For example `requests.ephemeral-storage=100M`                                                                               |
| `buildkit-root-volume-memory`              | Memory size  | Using regular file system               | Mounts `/var/lib/buildkit` on an `emptyDir` memory-backed volume, with `SizeLimit` as the value. For example, `buildkit-root-folder-memory=6G`                                                                |
| `nodeselector`                             | CSV string   |                                         | Sets the pod's `nodeSelector` label(s). See [node assignment][2].                                                                                                                                             |
| `annotations`                              | CSV string   |                                         | Sets additional annotations on the `Deployment` or `StatefulSet` and pods.                                                                                                                                    |
| `labels`                                   | CSV string   |                                         | Sets additional labels on the `Deployment` or `StatefulSet` and pods.                                                                                                                                         |
| `tolerations`                              | CSV string   |                                         | Configures the pod's taint toleration. See [node assignment][2].                                                                                                                                              |
| `serviceaccount`                           | String       |                                         | Sets the pod's `serviceAccountName`.                                                                                                                                                                          |
| `schedulername`                            | String       |                                         | Sets the scheduler responsible for scheduling the pod.                                                                                                                                                        |
| `timeout`                                  | Time         | `120s`                                  | Set the timeout limit that determines how long Buildx will wait for pods to be provisioned before a build.                                                                                                    |
| `rootless`                                 | Boolean      | `false`                                 | Run the container as a non-root user. See [rootless mode][3].                                                                                                                                                 |
| `loadbalance`                              | String       | `sticky`                                | Load-balancing strategy (`sticky` or `random`). If set to `sticky`, the pod is chosen using the hash of the context path.                                                                                     |
| `qemu.install`                             | Boolean      | `false`                                 | Install QEMU emulation for multi platforms support. See [QEMU][4].                                                                                                                                            |
| `qemu.image`                               | String       | `tonistiigi/binfmt:latest`              | Sets the QEMU emulation image. See [QEMU][4].                                                                                                                                                                 |

[1]: #scaling-buildkit
[2]: #node-assignment
[3]: #rootless-mode
[4]: #qemu

## Scaling BuildKit

One of the main advantages of the Kubernetes driver is that you can scale the
number of builder replicas up and down to handle increased build load. Scaling
is configurable using the following driver options:

- `replicas=N`

  This scales the number of BuildKit pods to the desired size. By default, it
  only creates a single pod. Increasing the number of replicas lets you take
  advantage of multiple nodes in your cluster.

- `requests.cpu`, `requests.memory`, `requests.ephemeral-storage`, `limits.cpu`, `limits.memory`, `limits.ephemeral-storage`

  These options allow requesting and limiting the resources available to each
  BuildKit pod [according to the official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).

For example, to create 4 replica BuildKit pods:

```console
$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,replicas=4
```

Listing the pods, you get this:

```console
$ kubectl -n buildkit get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
kube0   4/4     4            4           8s

$ kubectl -n buildkit get pods
NAME                     READY   STATUS    RESTARTS   AGE
kube0-6977cdcb75-48ld2   1/1     Running   0          8s
kube0-6977cdcb75-rkc6b   1/1     Running   0          8s
kube0-6977cdcb75-vb4ks   1/1     Running   0          8s
kube0-6977cdcb75-z4fzs   1/1     Running   0          8s
```

Additionally, you can use the `loadbalance=(sticky|random)` option to control
the load-balancing behavior when there are multiple replicas. `random` selects
random nodes from the node pool, providing an even workload distribution across
replicas. `sticky` (the default) attempts to connect the same build performed
multiple times to the same node each time, ensuring better use of local cache.

For more information on scalability, see the options for
[`docker buildx create`](/reference/cli/docker/buildx/create/#driver-opt).

## Persistent storage

Set the `persistent-volume-claim.requests.storage` driver option to store the
BuildKit build cache in a persistent volume claim instead of the pod
filesystem.
When you set this option, Buildx creates a `StatefulSet` instead of a
`Deployment`.

If you also set `replicas`, each replica gets its own persistent volume claim.
This keeps the build cache local to each pod across restarts.

For example, to create a builder with 20 GiB of persistent storage per replica:

```console
$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,replicas=4,persistent-volume-claim.requests.storage=20Gi
```

## Node assignment

The Kubernetes driver allows you to control the scheduling of BuildKit pods
using the `nodeSelector` and `tolerations` driver options.
You can also set the `schedulername` option if you want to use a custom scheduler altogether.

You can use the `annotations` and `labels` driver options to apply additional
metadata to the `Deployment` or `StatefulSet` and the pods hosting your
builders.

The value of the `nodeSelector` parameter is a comma-separated string of
key-value pairs, where the key is the node label and the value is the label
text. For example: `"nodeselector=kubernetes.io/arch=arm64"`

The `tolerations` parameter is a semicolon-separated list of taints. It accepts
the same values as the Kubernetes manifest. Each `tolerations` entry specifies
a taint key and the value, operator, or effect. For example:
`"tolerations=key=foo,value=bar;key=foo2,operator=exists;key=foo3,effect=NoSchedule"`

These options accept CSV-delimited strings as values. Due to quoting rules for
shell commands, you must wrap the values in single quotes. You can even wrap all
of `--driver-opt` in single quotes, for example:

```console
$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  '--driver-opt="nodeselector=label1=value1,label2=value2","tolerations=key=key1,value=value1"'
```

## Multi-platform builds

The Kubernetes driver has support for creating
[multi-platform images](../../building/multi-platform.md),
either using QEMU or by leveraging the native architecture of nodes.

### QEMU

Like the `docker-container` driver, the Kubernetes driver also supports using
[QEMU](https://www.qemu.org/) (user
mode) to build images for non-native platforms. Include the `--platform` flag
and specify which platforms you want to output to.

For example, to build a Linux image for `amd64` and `arm64`:

```console
$ docker buildx build \
  --builder=kube \
  --platform=linux/amd64,linux/arm64 \
  -t <user>/<image> \
  --push .
```

> [!WARNING]
>
> QEMU performs full-CPU emulation of non-native platforms, which is much
> slower than native builds. Compute-heavy tasks like compilation and
> compression/decompression will likely take a large performance hit.

Using a custom BuildKit image or invoking non-native binaries in builds may
require that you explicitly turn on QEMU using the `qemu.install` option when
creating the builder:

```console
$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,qemu.install=true
```

### Native

If you have access to cluster nodes of different architectures, the Kubernetes
driver can take advantage of these for native builds. To do this, use the
`--append` flag of `docker buildx create`.

First, create your builder with explicit support for a single architecture, for
example `amd64`:

```console
$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --platform=linux/amd64 \
  --node=builder-amd64 \
  --driver-opt=namespace=buildkit,nodeselector="kubernetes.io/arch=amd64"
```

This creates a Buildx builder named `kube`, containing a single builder node
named `builder-amd64`. Assigning a node name using `--node` is optional. Buildx
generates a random node name if you don't provide one.

Note that the Buildx concept of a node isn't the same as the Kubernetes concept
of a node. A Buildx node in this case could connect multiple Kubernetes nodes of
the same architecture together.

With the `kube` builder created, you can now introduce another architecture into
the mix using `--append`. For example, to add `arm64`:

```console
$ docker buildx create \
  --append \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --platform=linux/arm64 \
  --node=builder-arm64 \
  --driver-opt=namespace=buildkit,nodeselector="kubernetes.io/arch=arm64"
```

Listing your builders shows both nodes for the `kube` builder:

```console
$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT                                         STATUS   PLATFORMS
kube            kubernetes
  builder-amd64 kubernetes:///kube?deployment=builder-amd64&kubeconfig= running  linux/amd64*, linux/amd64/v2, linux/amd64/v3, linux/386
  builder-arm64 kubernetes:///kube?deployment=builder-arm64&kubeconfig= running  linux/arm64*
```

You can now build multi-arch `amd64` and `arm64` images, by specifying those
platforms together in your build command:

```console
$ docker buildx build --builder=kube --platform=linux/amd64,linux/arm64 -t <user>/<image> --push .
```

You can repeat the `buildx create --append` command for as many architectures
that you want to support.

## Rootless mode

The Kubernetes driver supports rootless mode. For more information on how
rootless mode works, and its requirements, refer to the
[Rootless Buildkit documentation](https://github.com/moby/buildkit/blob/master/docs/rootless.md).

To turn it on in your cluster, you can use the `rootless=true` driver option:

```console
$ docker buildx create \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,rootless=true
```

This will create your pods without `securityContext.privileged`.

Requires Kubernetes version 1.19 or later. Using Ubuntu as the host kernel is
recommended.

## Example: Creating a Buildx builder in Kubernetes

This guide shows you how to:

- Create a namespace for your Buildx resources
- Create a Kubernetes builder.
- List the available builders
- Build an image using your Kubernetes builders

Prerequisites:

- You have an existing Kubernetes cluster. If you don't already have one, you
  can follow along by installing
  [minikube](https://minikube.sigs.k8s.io/docs/).
- The cluster you want to connect to is accessible via the `kubectl` command,
  with the `KUBECONFIG` environment variable
  [set appropriately](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/#set-the-kubeconfig-environment-variable) if necessary.

1. Create a `buildkit` namespace.

   Creating a separate namespace helps keep your Buildx resources separate from
   other resources in the cluster.

   ```console
   $ kubectl create namespace buildkit
   namespace/buildkit created
   ```

2. Create a new builder with the Kubernetes driver:

   ```console
   $ docker buildx create \
     --bootstrap \
     --name=kube \
     --driver=kubernetes \
     --driver-opt=namespace=buildkit
   ```

   > [!NOTE]
   >
   > Remember to specify the namespace in driver options.

3. List available builders using `docker buildx ls`

   ```console
   $ docker buildx ls
   NAME/NODE                DRIVER/ENDPOINT STATUS  PLATFORMS
   kube                     kubernetes
     kube0-6977cdcb75-k9h9m                 running linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
   default *                docker
     default                default         running linux/amd64, linux/386
   ```

4. Inspect the running pods created by the build driver with `kubectl`.

   ```console
   $ kubectl -n buildkit get deployments
   NAME    READY   UP-TO-DATE   AVAILABLE   AGE
   kube0   1/1     1            1           32s

   $ kubectl -n buildkit get pods
   NAME                     READY   STATUS    RESTARTS   AGE
   kube0-6977cdcb75-k9h9m   1/1     Running   0          32s
   ```

   The build driver creates the necessary resources on your cluster in the
   specified namespace (in this case, `buildkit`), while keeping your driver
   configuration locally.

5. Use your new builder by including the `--builder` flag when running Buildx
   commands. For example: :

   ```console
   # Replace <registry> with your Docker username
   # and <image> with the name of the image you want to build
   docker buildx build \
     --builder=kube \
     -t <registry>/<image> \
     --push .
   ```

That's it: you've now built an image from a Kubernetes pod, using Buildx.

## Further reading

For more information on the Kubernetes driver, see the
[buildx reference](/reference/cli/docker/buildx/create/#driver).


---

# Remote driver

*Sección: Build*

The Buildx remote driver allows for more complex custom build workloads,
allowing you to connect to externally managed BuildKit instances. This is useful
for scenarios that require manual management of the BuildKit daemon, or where a
BuildKit daemon is exposed from another source.

## Synopsis

```console
$ docker buildx create \
  --name remote \
  --driver remote \
  tcp://localhost:1234
```

The following table describes the available driver-specific options that you can
pass to `--driver-opt`:

| Parameter      | Type    | Default            | Description                                                            |
| -------------- | ------- | ------------------ | ---------------------------------------------------------------------- |
| `key`          | String  |                    | Sets the TLS client key.                                               |
| `cert`         | String  |                    | Absolute path to the TLS client certificate to present to `buildkitd`. |
| `cacert`       | String  |                    | Absolute path to the TLS certificate authority used for validation.    |
| `servername`   | String  | Endpoint hostname. | TLS server name used in requests.                                      |
| `default-load` | Boolean | `false`            | Automatically load images to the Docker Engine image store.            |

## Example: Remote BuildKit over Unix sockets

This guide shows you how to create a setup with a BuildKit daemon listening on a
Unix socket, and have Buildx connect through it.

1. Ensure that [BuildKit](https://github.com/moby/buildkit) is installed.

   For example, you can launch an instance of buildkitd with:

   ```console
   $ sudo ./buildkitd --group $(id -gn) --addr unix://$HOME/buildkitd.sock
   ```

   Alternatively, refer to the [Rootless Buildkit documentation](https://github.com/moby/buildkit/blob/master/docs/rootless.md)
   for running buildkitd in rootless mode, or [the BuildKit systemd examples](https://github.com/moby/buildkit/tree/master/examples/systemd)
   for running it as a systemd service.

2. Check that you have a Unix socket that you can connect to.

   ```console
   $ ls -lh /home/user/buildkitd.sock
   srw-rw---- 1 root user 0 May  5 11:04 /home/user/buildkitd.sock
   ```

3. Connect Buildx to it using the remote driver:

   ```console
   $ docker buildx create \
     --name remote-unix \
     --driver remote \
     unix://$HOME/buildkitd.sock
   ```

4. List available builders with `docker buildx ls`. You should then see
   `remote-unix` among them:

   ```console
   $ docker buildx ls
   NAME/NODE           DRIVER/ENDPOINT                        STATUS  PLATFORMS
   remote-unix         remote
     remote-unix0      unix:///home/.../buildkitd.sock        running linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
   default *           docker
     default           default                                running linux/amd64, linux/386
   ```

You can switch to this new builder as the default using
`docker buildx use remote-unix`, or specify it per build using `--builder`:

```console
$ docker buildx build --builder=remote-unix -t test --load .
```

Remember that you need to use the `--load` flag if you want to load the build
result into the Docker daemon.

## Example: Remote BuildKit in Docker container

This guide will show you how to create setup similar to the `docker-container`
driver, by manually booting a BuildKit Docker container and connecting to it
using the Buildx remote driver. This procedure will manually create a container
and access it via it's exposed port. (You'd probably be better of just using the
`docker-container` driver that connects to BuildKit through the Docker daemon,
but this is for illustration purposes.)

1.  Generate certificates for BuildKit.

    You can use this [bake definition](https://github.com/moby/buildkit/blob/master/examples/create-certs)
    as a starting point:

    ```console
    SAN="localhost 127.0.0.1" docker buildx bake "https://github.com/moby/buildkit.git#master:examples/create-certs"
    ```

    Note that while it's possible to expose BuildKit over TCP without using
    TLS, it's not recommended. Doing so allows arbitrary access to BuildKit
    without credentials.

2.  With certificates generated in `.certs/`, startup the container:

    ```console
    $ docker run -d --rm \
      --name=remote-buildkitd \
      --privileged \
      -p 1234:1234 \
      -v $PWD/.certs:/etc/buildkit/certs \
      moby/buildkit:latest \
      --addr tcp://0.0.0.0:1234 \
      --tlscacert /etc/buildkit/certs/daemon/ca.pem \
      --tlscert /etc/buildkit/certs/daemon/cert.pem \
      --tlskey /etc/buildkit/certs/daemon/key.pem
    ```

    This command starts a BuildKit container and exposes the daemon's port 1234
    to localhost.

3.  Connect to this running container using Buildx:

    ```console
    $ docker buildx create \
      --name remote-container \
      --driver remote \
      --driver-opt cacert=${PWD}/.certs/client/ca.pem,cert=${PWD}/.certs/client/cert.pem,key=${PWD}/.certs/client/key.pem,servername=<TLS_SERVER_NAME> \
      tcp://localhost:1234
    ```

    Alternatively, use the `docker-container://` URL scheme to connect to the
    BuildKit container without specifying a port:

    ```console
    $ docker buildx create \
      --name remote-container \
      --driver remote \
      docker-container://remote-container
    ```

## Example: Remote BuildKit in Kubernetes

This guide will show you how to create a setup similar to the `kubernetes`
driver by manually creating a BuildKit `Deployment`. While the `kubernetes`
driver will do this under-the-hood, it might sometimes be desirable to scale
BuildKit manually. Additionally, when executing builds from inside Kubernetes
pods, the Buildx builder will need to be recreated from within each pod or
copied between them.

1. Create a Kubernetes deployment of `buildkitd` by following the instructions
   [in the BuildKit documentation](https://github.com/moby/buildkit/tree/master/examples/kubernetes).

   Create certificates for the BuildKit daemon and client using the
   [create-certs.sh](https://github.com/moby/buildkit/blob/master/examples/kubernetes/create-certs.sh),
   script and create a deployment of BuildKit pods with a service that connects
   to them.

2. Assuming that the service is called `buildkitd`, create a remote builder in
   Buildx, ensuring that the listed certificate files are present:

   ```console
   $ docker buildx create \
     --name remote-kubernetes \
     --driver remote \
     --driver-opt cacert=${PWD}/.certs/client/ca.pem,cert=${PWD}/.certs/client/cert.pem,key=${PWD}/.certs/client/key.pem \
     tcp://buildkitd.default.svc:1234
   ```

Note that this only works internally, within the cluster, since the BuildKit
setup guide only creates a `ClusterIP` service. To access a builder remotely,
you can set up and use an ingress, which is outside the scope of this guide.

### Debug a remote builder in Kubernetes

If you're having trouble accessing a remote builder deployed in Kubernetes, you
can use the `kube-pod://` URL scheme to connect directly to a BuildKit pod
through the Kubernetes API. Note that this method only connects to a single pod
in the deployment.

```console
$ kubectl get pods --selector=app=buildkitd -o json | jq -r '.items[].metadata.name'
buildkitd-XXXXXXXXXX-xxxxx
$ docker buildx create \
  --name remote-container \
  --driver remote \
  kube-pod://buildkitd-XXXXXXXXXX-xxxxx
```

Alternatively, use the port forwarding mechanism of `kubectl`:

```console
$ kubectl port-forward svc/buildkitd 1234:1234
```

Then you can point the remote driver at `tcp://localhost:1234`.


---

# Manage builders

*Sección: Build*

You can create, inspect, and manage builders using `docker buildx` commands,
or [using Docker Desktop](#manage-builders-with-docker-desktop).

## Create a new builder

The default builder uses the [`docker` driver](drivers/docker.md).
You can't manually create new `docker` builders, but you can create builders
that use other drivers, such as the
[`docker-container` driver](drivers/docker-container.md),
which runs the BuildKit daemon in a container.

Use the
[`docker buildx create`](/reference/cli/docker/buildx/create/)
command to create a builder.

```console
$ docker buildx create --name=<builder-name>
```

Buildx uses the `docker-container` driver by default if you omit the `--driver`
flag. For more information about available drivers, see
[Build drivers](drivers/index.md).

## List available builders

Use `docker buildx ls` to see builder instances available on your system, and
the drivers they're using.

```console
$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT      STATUS   BUILDKIT PLATFORMS
default *       docker
  default       default              running  v0.11.6  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
my_builder      docker-container
  my_builder0   default              running  v0.11.6  linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
```

The asterisk (`*`) next to the builder name indicates the
[selected builder](index.md#selected-builder).

## Inspect a builder

To inspect a builder with the CLI, use `docker buildx inspect <name>`.
You can only inspect a builder if the builder is active.
You can add the `--bootstrap` flag to the command to start the builder.

```console
$ docker buildx inspect --bootstrap my_builder
[+] Building 1.7s (1/1) FINISHED                                                                  
 => [internal] booting buildkit                                                              1.7s
 => => pulling image moby/buildkit:buildx-stable-1                                           1.3s
 => => creating container buildx_buildkit_my_builder0                                        0.4s
Name:          my_builder
Driver:        docker-container
Last Activity: 2023-06-21 18:28:37 +0000 UTC

Nodes:
Name:      my_builder0
Endpoint:  unix:///var/run/docker.sock
Status:    running
Buildkit:  v0.11.6
Platforms: linux/arm64, linux/amd64, linux/amd64/v2, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
```

If you want to see how much disk space a builder is using, use the
`docker buildx du` command. By default, this command shows the total disk usage
for all available builders. To see usage for a specific builder, use the
`--builder` flag.

```console
$ docker buildx du --builder my_builder
ID                                        RECLAIMABLE SIZE        LAST ACCESSED
olkri5gq6zsh8q2819i69aq6l                 true        797.2MB     37 seconds ago
6km4kasxgsywxkm6cxybdumbb*                true        438.5MB     36 seconds ago
qh3wwwda7gx2s5u4hsk0kp4w7                 true        213.8MB     37 seconds ago
54qq1egqem8max3lxq6180cj8                 true        200.2MB     37 seconds ago
ndlp969ku0950bmrw9muolw0c*                true        116.7MB     37 seconds ago
u52rcsnfd1brwc0chwsesb3io*                true        116.7MB     37 seconds ago
rzoeay0s4nmss8ub59z6lwj7d                 true        46.25MB     4 minutes ago
itk1iibhmv7awmidiwbef633q                 true        33.33MB     37 seconds ago
4p78yqnbmgt6xhcxqitdieeln                 true        19.46MB     4 minutes ago
dgkjvv4ay0szmr9bl7ynla7fy*                true        19.24MB     36 seconds ago
tuep198kmcw299qc9e4d1a8q2                 true        8.663MB     4 minutes ago
n1wzhauk9rpmt6ib1es7dktvj                 true        20.7kB      4 minutes ago
0a2xfhinvndki99y69157udlm                 true        16.56kB     37 seconds ago
gf0z1ypz54npfererqfeyhinn                 true        16.38kB     37 seconds ago
nz505f12cnsu739dw2pw0q78c                 true        8.192kB     37 seconds ago
hwpcyq5hdfvioltmkxu7fzwhb*                true        8.192kB     37 seconds ago
acekq89snc7j6im1rjdizvsg1*                true        8.192kB     37 seconds ago
Reclaimable:  2.01GB
Total:        2.01GB
```

## Remove a builder

Use the
[`docker buildx remove`](/reference/cli/docker/buildx/create/)
command to remove a builder.

```console
$ docker buildx rm <builder-name>
```

If you remove your currently selected builder,
the default `docker` builder is automatically selected.
You can't remove the default builder.

Local build cache for the builder is also removed.

### Removing remote builders

Removing a remote builder doesn't affect the remote build cache.
It also doesn't stop the remote BuildKit daemon.
It only removes your connection to the builder.

## Manage builders with Docker Desktop

If you have turned on the
[Docker Desktop Builds view](../../desktop/use-desktop/builds.md),
you can inspect builders in [Docker Desktop settings](../../desktop/settings-and-maintenance/settings.md#builders).


---

# Building

*Sección: Build*




---

# Base images

*Sección: Build*

All Dockerfiles start from a base image.
A base is the image that your image extends.
It refers to the contents of the `FROM` instruction in the Dockerfile.

```dockerfile
FROM debian
```

For most cases, you don't need to create your own base image. Docker Hub
contains a vast library of Docker images that are suitable for use as a base
image in your build. [Docker Official
Images](../../docker-hub/image-library/trusted-content.md#docker-official-images)
have clear documentation, promote best practices, and are regularly updated.
There are also [Docker Verified
Publisher](../../docker-hub/image-library/trusted-content.md#verified-publisher-images)
images, created by trusted publishing partners, verified by Docker.

## Create a base image

If you need to completely control the contents of your image, you can create
your own base image from a Linux distribution of your choosing, or use the
special `FROM scratch` base:

```dockerfile
FROM scratch
```

The `scratch` image is typically used to create minimal images containing only
just what an application needs. See [Create a minimal base image using scratch](#create-a-minimal-base-image-using-scratch).

To create a distribution base image, you can use a root filesystem, packaged as
a `tar` file, and import it to Docker with `docker import`. The process for
creating your own base image depends on the Linux distribution you want to
package. See [Create a full image using tar](#create-a-full-image-using-tar).

## Create a minimal base image using scratch

The reserved, minimal `scratch` image serves as a starting point for
building containers. Using the `scratch` image signals to the build process
that you want the next command in the `Dockerfile` to be the first filesystem
layer in your image.

While `scratch` appears in Docker's [repository on Docker Hub](https://hub.docker.com/_/scratch),
you can't pull it, run it, or tag any image with the name `scratch`.
Instead, you can refer to it in your `Dockerfile`.
For example, to create a minimal container using `scratch`:

```dockerfile
# syntax=docker/dockerfile:1
FROM scratch
ADD hello /
CMD ["/hello"]
```

Assuming an executable binary named `hello` exists at the root of the [build context](../concepts/context.md).
You can build this Docker image using the following `docker build` command:

```console
$ docker build --tag hello .
```

To run your new image, use the `docker run` command:

```console
$ docker run --rm hello
```

This example image can only be successfully executed as long as the `hello` binary
doesn't have any runtime dependencies. Computer programs tend to depend on
certain other programs or resources to exist in the runtime environment. For
example:

- Programming language runtimes
- Dynamically linked C libraries
- CA certificates

When building a base image, or any image, this is an important aspect to
consider. And this is why creating a base image using `FROM scratch` can be
difficult, for anything other than small, simple programs. On the other hand,
it's also important to include only the things you need in your image, to
reduce the image size and attack surface.

## Create a full image using tar

In general, start with a working machine that is running
the distribution you'd like to package as a base image, though that is
not required for some tools like Debian's [Debootstrap](https://wiki.debian.org/Debootstrap),
which you can also use to build Ubuntu images.

For example, to create an Ubuntu base image using the `noble` codename for
Ubuntu 24.04, run the following commands. Replace `noble` with the codename
for the Ubuntu release you want to import:

```dockerfile
$ sudo debootstrap noble noble > /dev/null
$ sudo tar -C noble -c . | docker import - noble

sha256:81ec9a55a92a5618161f68ae691d092bf14d700129093158297b3d01593f4ee3

$ docker run noble cat /etc/lsb-release

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=24.04
DISTRIB_CODENAME=noble
DISTRIB_DESCRIPTION="Ubuntu 24.04.2 LTS"
```

There are more example scripts for creating base images in
[the Moby GitHub repository](https://github.com/moby/moby/blob/master/contrib).

## More resources

For more information about building images and writing Dockerfiles, see:

* [Dockerfile reference](../concepts/dockerfile.md)
* [Dockerfile best practices](best-practices.md)
* [Docker Official Images](../../docker-hub/image-library/trusted-content.md#docker-official-images)


---

# Building best practices

*Sección: Build*

## Use multi-stage builds

Multi-stage builds let you reduce the size of your final image, by creating a
cleaner separation between the building of your image and the final output.
Split your Dockerfile instructions into distinct stages to make sure that the
resulting output only contains the files that are needed to run the application.

Using multiple stages can also let you build more efficiently by executing
build steps in parallel.

See [Multi-stage builds](multi-stage.md) for more
information.

### Create reusable stages

If you have multiple images with a lot in common, consider creating a reusable
stage that includes the shared components, and basing your unique stages on
that. Docker only needs to build the common stage once. This means that your derivative images use memory
on the Docker host more efficiently and load more quickly.

It's also easier to maintain a common base stage ("Don't repeat yourself"),
than it is to have multiple different stages doing similar things.

## Choose the right base image

The first step towards achieving a secure image is to choose the right base
image. When choosing an image, ensure it's built from a trusted source and keep
it small.

- [Docker Official Images](https://hub.docker.com/search?badges=official)
  are a curated collection that have clear documentation, promote best
  practices, and are regularly updated. They provide a trusted starting point
  for many applications.

- [Verified Publisher](https://hub.docker.com/search?badges=verified_publisher) images
  are high-quality images published and maintained by the organizations
  partnering with Docker, with Docker verifying the authenticity of the content
  in their repositories.

- [Docker-Sponsored Open Source](https://hub.docker.com/search?badges=open_source)
  are published and maintained by open source projects sponsored by Docker
  through an [open source program](../../docker-hub/image-library/trusted-content.md#docker-sponsored-open-source-software-images).

When you pick your base image, look out for the badges indicating that the
image is part of these programs.

![Docker Hub Official and Verified Publisher images](../images/hub-official-images.webp)

When building your own image from a Dockerfile, ensure you choose a minimal base
image that matches your requirements. A smaller base image not only offers
portability and fast downloads, but also shrinks the size of your image and
minimizes the number of vulnerabilities introduced through the dependencies.

You should also consider using two types of base image: one for building and
unit testing, and another (typically slimmer) image for production. In the
later stages of development, your image may not require build tools such as
compilers, build systems, and debugging tools. A small image with minimal
dependencies can considerably lower the attack surface.

## Rebuild your images often

Docker images are immutable. Building an image is taking a snapshot of
that image at that moment. That includes any base images, libraries, or
other software you use in your build. To keep your images up-to-date and
secure, rebuild your images regularly with updated dependencies.

### Use --pull to get fresh base images

The following Dockerfile uses the `24.04` tag of the `ubuntu` image.
Over time, that tag may resolve to a different underlying version of the
`ubuntu` image, as the publisher rebuilds the image with new security
patches and updated libraries.

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:24.04
RUN apt-get -y update && apt-get install -y --no-install-recommends python3
```

To get the latest version of the base image, use the `--pull` flag:

```console
$ docker build --pull -t my-image:my-tag .
```

The `--pull` flag forces Docker to check for and download a newer
version of the base image, even if you have a version cached locally.

### Use --no-cache for clean builds

The `--no-cache` flag disables the build cache, forcing Docker to
rebuild all layers from scratch:

```console
$ docker build --no-cache -t my-image:my-tag .
```

This gets the latest available versions of dependencies from package
managers like `apt-get` or `npm`. It does not pull a fresh base image —
for that, use `--pull`.

The two flags serve distinct purposes and can be combined. Use both
together to get a fresh base image and re-execute all build steps:

```console
$ docker build --pull --no-cache -t my-image:my-tag .
```

Also consider [pinning base image versions](#pin-base-image-versions).

## Exclude with .dockerignore

To exclude files not relevant to the build, without restructuring your source
repository, use a `.dockerignore` file. This file supports exclusion patterns
similar to `.gitignore` files.

For example, to exclude all files with the `.md` extension:

```plaintext
*.md
```

For information on creating one, see
[Dockerignore file](../concepts/context.md#dockerignore-files).

## Create ephemeral containers

The image defined by your Dockerfile should generate containers that are as
ephemeral as possible. Ephemeral means that the container can be stopped
and destroyed, then rebuilt and replaced with an absolute minimum set up and
configuration.

Refer to [Processes](https://12factor.net/processes) under _The Twelve-factor App_
methodology to get a feel for the motivations of running containers in such a
stateless fashion.

## Don't install unnecessary packages

Avoid installing extra or unnecessary packages just because they might be nice to have. For example, you don’t need to include a text editor in a database image.

When you avoid installing extra or unnecessary packages, your images have reduced complexity, reduced dependencies, reduced file sizes, and reduced build times.

## Decouple applications

Each container should have only one concern. Decoupling applications into
multiple containers makes it easier to scale horizontally and reuse containers.
For instance, a web application stack might consist of three separate
containers, each with its own unique image, to manage the web application,
database, and an in-memory cache in a decoupled manner.

Limiting each container to one process is a good rule of thumb, but it's not a
hard and fast rule. For example, not only can containers be
[spawned with an init process](../../engine/containers/multi-service-container.md),
some programs might spawn additional processes of their own accord. For
instance, [Celery](https://docs.celeryq.dev/) can spawn multiple worker
processes, and [Apache](https://httpd.apache.org/) can create one process per
request.

Use your best judgment to keep containers as clean and modular as possible. If
containers depend on each other, you can use [Docker container networks](../../engine/network/index.md)
to ensure that these containers can communicate.

## Sort multi-line arguments

Whenever possible, sort multi-line arguments alphanumerically to make maintenance easier.
This helps to avoid duplication of packages and make the
list much easier to update. This also makes PRs a lot easier to read and
review. Adding a space before a backslash (`\`) helps as well.

Here’s an example from the [buildpack-deps image](https://github.com/docker-library/buildpack-deps):

```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
  bzr \
  cvs \
  git \
  mercurial \
  subversion \
  && rm -rf /var/lib/apt/lists/*
```

## Leverage build cache

When building an image, Docker steps through the instructions in your
Dockerfile, executing each in the order specified. For each instruction, Docker
checks whether it can reuse the instruction from the build cache.

Understanding how the build cache works, and how cache invalidation occurs,
is critical for ensuring faster builds.
For more information about the Docker build cache and how to optimize your builds,
see [Docker build cache](../cache/index.md).

## Pin base image versions

Image tags are mutable, meaning a publisher can update a tag to point to a new
image. This is useful because it lets publishers update tags to point to
newer versions of an image. And as an image consumer, it means you
automatically get the new version when you re-build your image.

For example, if you specify `FROM alpine:3.21` in your Dockerfile, `3.21`
resolves to the latest patch version for `3.21`.

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine:3.21
```

At one point in time, the `3.21` tag might point to version 3.21.1 of the
image. If you rebuild the image 3 months later, the same tag might point to a
different version, such as 3.21.4. This publishing workflow is best practice,
and most publishers use this tagging strategy, but it isn't enforced.

The downside with this is that you're not guaranteed to get the same for every
build. This could result in breaking changes, and it means you also don't have
an audit trail of the exact image versions that you're using.

To fully secure your supply chain integrity, you can pin the image version to a
specific digest. By pinning your images to a digest, you're guaranteed to
always use the same image version, even if a publisher replaces the tag with a
new image. For example, the following Dockerfile pins the Alpine image to the
same tag as earlier, `3.21`, but this time with a digest reference as well.

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine:3.21@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c
```

With this Dockerfile, even if the publisher updates the `3.21` tag, your builds
would still use the pinned image version:
`a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c`.

While this helps you avoid unexpected changes, it's also more tedious to have
to look up and include the image digest for base image versions manually each
time you want to update it. And you're opting out of automated security fixes,
which is likely something you want to get.

Docker Scout's default [**No outdated base images**
policy](../../scout/policy/index.md#no-outdated-base-images) checks whether the
base image version you're using is in fact the latest version. This policy also
checks if pinned digests in your Dockerfile correspond to the correct version.
If a publisher updates an image that you've pinned, the policy evaluation
returns a non-compliant status, indicating that you should update your image.

To keep your base images up-to-date automatically, use
[GitHub Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates)
with `package-ecosystem: "docker"`. Dependabot raises pull requests to update
your base image tags and digests on a schedule. This is better than using a tag
that changes the version automatically, because you're in control and you have
an audit trail of when and how the change occurred.

You can also review available base image updates from the CLI with
[`docker scout recommendations`](/reference/cli/docker/scout/recommendations/).

## Build and test your images in CI

When you check in a change to source control or create a pull request, use
[GitHub Actions](../ci/github-actions/index.md) or another CI/CD pipeline to
automatically build and tag a Docker image and test it.

## Dockerfile instructions

Follow these recommendations on how to properly use the [Dockerfile instructions](../concepts/dockerfile.md)
to create an efficient and maintainable Dockerfile.

> [!TIP]
>
> To improve linting, code navigation, and vulnerability scanning of your Dockerfiles in Visual Studio Code
> see the [Docker DX](https://marketplace.visualstudio.com/items?itemName=docker.docker) extension.

### FROM

Whenever possible, use current official images as the basis for your
images. Docker recommends the [Alpine image](https://hub.docker.com/_/alpine/) as it
is tightly controlled and small in size (under 6 MB), while still
being a full Linux distribution.

For more information about the `FROM` instruction, see [Dockerfile reference for the FROM instruction](../concepts/dockerfile.md#from).

### LABEL

You can add labels to your image to help organize images by project, record
licensing information, to aid in automation, or for other reasons. For each
label, add a line beginning with `LABEL` with one or more key-value pairs.
The following examples show the different acceptable formats. Explanatory comments are included inline.

Strings with spaces must be quoted or the spaces must be escaped. Inner
quote characters (`"`), must also be escaped. For example:

```dockerfile
# Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor1="ACME Incorporated"
LABEL vendor2=ZENITH\ Incorporated
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""
```

An image can have more than one label. Prior to Docker 1.10, it was recommended
to combine all labels into a single `LABEL` instruction, to prevent extra layers
from being created. This is no longer necessary, but combining labels is still
supported. For example:

```dockerfile
# Set multiple labels on one line
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
```

The above example can also be written as:

```dockerfile
# Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
      com.example.is-beta= \
      com.example.is-production="" \
      com.example.version="0.0.1-beta" \
      com.example.release-date="2015-02-12"
```

See [Understanding object labels](../../engine/manage-resources/labels.md)
for guidelines about acceptable label keys and values. For information about
querying labels, refer to the items related to filtering in
[Managing labels on objects](../../engine/manage-resources/labels.md#manage-labels-on-objects).
See also [LABEL](../concepts/dockerfile.md#label) in the Dockerfile reference.

### RUN

Split long or complex `RUN` statements on multiple lines separated with
backslashes to make your Dockerfile more readable, understandable, and
maintainable.

For example, you can chain commands with the `&&` operator, and use
escape characters to break long commands into multiple lines.

```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo
```

By default, backslash escapes a newline character, but you can change it with
the [`escape` directive](../concepts/dockerfile.md#escape).

You can also use here documents to run multiple commands without chaining them
with a pipeline operator:

```dockerfile
RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo
EOF
```

For more information about `RUN`, see [Dockerfile reference for the RUN instruction](../concepts/dockerfile.md#run).

#### apt-get

One common use case for `RUN` instructions in Debian-based images is to install
software using `apt-get`. Because `apt-get` installs packages, the `RUN
apt-get` command has several counter-intuitive behaviors to look out for.

Always combine `RUN apt-get update` with `apt-get install` in the same `RUN`
statement. For example:

```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo
```

Using `apt-get update` alone in a `RUN` statement causes caching issues and
subsequent `apt-get install` instructions to fail. For example, this issue will occur in the following Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1

FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends curl
```

After building the image, all layers are in the Docker cache. Suppose you later
modify `apt-get install` by adding an extra package as shown in the following Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1

FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends curl nginx
```

Docker sees the initial and modified instructions as identical and reuses the
cache from previous steps. As a result the `apt-get update` isn't executed
because the build uses the cached version. Because the `apt-get update` isn't
run, your build can potentially get an outdated version of the `curl` and
`nginx` packages.

Using `RUN apt-get update && apt-get install -y --no-install-recommends` ensures your Dockerfile
installs the latest package versions with no further coding or manual
intervention. This technique is known as cache busting. You can also achieve
cache busting by specifying a package version. This is known as version pinning.
For example:

```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo=1.3.*
```

Version pinning forces the build to retrieve a particular version regardless of
what’s in the cache. This technique can also reduce failures due to unanticipated changes
in required packages.

Below is a well-formed `RUN` instruction that demonstrates all the `apt-get`
recommendations.

```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends \
    aufs-tools \
    automake \
    build-essential \
    curl \
    dpkg-sig \
    libcap-dev \
    libsqlite3-dev \
    mercurial \
    reprepro \
    ruby1.9.1 \
    ruby1.9.1-dev \
    s3cmd=1.1.* \
    && rm -rf /var/lib/apt/lists/*
```

The `s3cmd` argument specifies a version `1.1.*`. If the image previously
used an older version, specifying the new one causes a cache bust of `apt-get
update` and ensures the installation of the new version. Listing packages on
each line can also prevent mistakes in package duplication.

In addition, when you clean up the apt cache by removing `/var/lib/apt/lists` it
reduces the image size, since the apt cache isn't stored in a layer. Since the
`RUN` statement starts with `apt-get update`, the package cache is always
refreshed prior to `apt-get install`.

Official Debian and Ubuntu images [automatically run `apt-get clean`](https://github.com/debuerreotype/debuerreotype/blob/c9542ab785e72696eb2908a6dbc9220abbabef39/scripts/debuerreotype-minimizing-config#L87-L109), so explicit invocation is not required.

#### Using pipes

Some `RUN` commands depend on the ability to pipe the output of one command into another, using the pipe character (`|`), as in the following example:

```dockerfile
RUN wget -O - https://some.site | wc -l > /number
```

Docker executes these commands using the `/bin/sh -c` interpreter, which only
evaluates the exit code of the last operation in the pipe to determine success.
In the example above, this build step succeeds and produces a new image so long
as the `wc -l` command succeeds, even if the `wget` command fails.

If you want the command to fail due to an error at any stage in the pipe,
prepend `set -o pipefail &&` to ensure that an unexpected error prevents the
build from inadvertently succeeding. For example:

```dockerfile
RUN set -o pipefail && wget -O - https://some.site | wc -l > /number
```

> [!NOTE]
>
> Not all shells support the `-o pipefail` option.
>
> In cases such as the `dash` shell on
> Debian-based images, consider using the _exec_ form of `RUN` to explicitly
> choose a shell that does support the `pipefail` option. For example:
>
> ```dockerfile
> RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]
> ```

### CMD

The `CMD` instruction should be used to run the software contained in your
image, along with any arguments. `CMD` should almost always be used in the form
of `CMD ["executable", "param1", "param2"]`. Thus, if the image is for a
service, such as Apache and Rails, you would run something like `CMD
["apache2","-DFOREGROUND"]`. Indeed, this form of the instruction is recommended
for any service-based image.

In most other cases, `CMD` should be given an interactive shell, such as bash,
Python and perl. For example, `CMD ["perl", "-de0"]`, `CMD ["python"]`, or `CMD
["php", "-a"]`. Using this form means that when you execute something like
`docker run -it python`, you’ll get dropped into a usable shell, ready to go.
`CMD` should rarely be used in the manner of `CMD ["param", "param"]` in
conjunction with [`ENTRYPOINT`](../concepts/dockerfile.md#entrypoint), unless
you and your expected users are already quite familiar with how `ENTRYPOINT`
works.

For more information about `CMD`, see [Dockerfile reference for the CMD instruction](../concepts/dockerfile.md#cmd).

### EXPOSE

The `EXPOSE` instruction indicates the ports on which a container listens
for connections. Consequently, you should use the common, traditional port for
your application. For example, an image containing the Apache web server would
use `EXPOSE 80`, while an image containing MongoDB would use `EXPOSE 27017` and
so on.

For external access, your users can execute `docker run` with a flag indicating
how to map the specified port to the port of their choice.
For container linking, Docker provides environment variables for the path from
the recipient container back to the source (for example, `MYSQL_PORT_3306_TCP`).

For more information about `EXPOSE`, see [Dockerfile reference for the EXPOSE instruction](../concepts/dockerfile.md#expose).

### ENV

To make new software easier to run, you can use `ENV` to update the
`PATH` environment variable for the software your container installs. For
example, `ENV PATH=/usr/local/nginx/bin:$PATH` ensures that `CMD ["nginx"]`
just works.

The `ENV` instruction is also useful for providing the required environment
variables specific to services you want to containerize, such as Postgres’s
`PGDATA`.

Lastly, `ENV` can also be used to set commonly used version numbers so that
version bumps are easier to maintain, as seen in the following example:

```dockerfile
ENV PG_MAJOR=9.3
ENV PG_VERSION=9.3.4
RUN curl -SL https://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgres && …
ENV PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH
```

Similar to having constant variables in a program, as opposed to hard-coding
values, this approach lets you change a single `ENV` instruction to
automatically bump the version of the software in your container.

Each `ENV` line creates a new intermediate layer, just like `RUN` commands. This
means that even if you unset the environment variable in a future layer, it
still persists in this layer and its value can be dumped. You can test this by
creating a Dockerfile like the following, and then building it.

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
ENV ADMIN_USER="mark"
RUN echo $ADMIN_USER > ./mark
RUN unset ADMIN_USER
```

```console
$ docker run --rm test sh -c 'echo $ADMIN_USER'

mark
```

To prevent this and unset the environment variable, use a `RUN` command
with shell commands, to set, use, and unset the variable all in a single layer.
You can separate your commands with `;` or `&&`. If you use the second method,
and one of the commands fails, the `docker build` also fails. This is usually a
good idea. Using `\` as a line continuation character for Linux Dockerfiles
improves readability. You could also put all of the commands into a shell script
and have the `RUN` command just run that shell script.

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN export ADMIN_USER="mark" \
    && echo $ADMIN_USER > ./mark \
    && unset ADMIN_USER
CMD sh
```

```console
$ docker run --rm test sh -c 'echo $ADMIN_USER'

```

For more information about `ENV`, see [Dockerfile reference for the ENV instruction](../concepts/dockerfile.md#env).

### ADD or COPY

`ADD` and `COPY` are functionally similar. `COPY` supports basic copying of
files into the container, from the [build context](../concepts/context.md)
or from a stage in a [multi-stage build](multi-stage.md).
`ADD` supports features for fetching files from remote HTTPS and Git URLs, and
extracting tar files automatically when adding files from the build context.

You'll mostly want to use `COPY` for copying files from one stage to another in
a multi-stage build. If you need to add files from the build context to the
container temporarily to execute a `RUN` instruction, you can often substitute
the `COPY` instruction with a bind mount instead. For example, to temporarily
add a `requirements.txt` file for a `RUN pip install` instruction:

```dockerfile
RUN --mount=type=bind,source=requirements.txt,target=/tmp/requirements.txt \
    pip install --requirement /tmp/requirements.txt
```

Bind mounts are more efficient than `COPY` for including files from the build
context in the container. Note that bind-mounted files are only added
temporarily for a single `RUN` instruction, and don't persist in the final
image. If you need to include files from the build context in the final image,
use `COPY`.

The `ADD` instruction is best for when you need to download a remote artifact
as part of your build. `ADD` is better than manually adding files using
something like `wget` and `tar`, because it ensures a more precise build cache.
`ADD` also has built-in support for checksum validation of the remote
resources, and a protocol for parsing branches, tags, and subdirectories from
[Git URLs](/reference/cli/docker/buildx/build/).

The following example uses `ADD` to download a .NET installer. Combined with
multi-stage builds, only the .NET runtime remains in the final stage, no
intermediate files.

```dockerfile
# syntax=docker/dockerfile:1

FROM scratch AS src
ARG DOTNET_VERSION=8.0.0-preview.6.23329.7
ADD --checksum=sha256:270d731bd08040c6a3228115de1f74b91cf441c584139ff8f8f6503447cebdbb \
    https://dotnetcli.azureedge.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-runtime-$DOTNET_VERSION-linux-arm64.tar.gz /dotnet.tar.gz

FROM mcr.microsoft.com/dotnet/runtime-deps:8.0.0-preview.6-bookworm-slim-arm64v8 AS installer

# Retrieve .NET Runtime
RUN --mount=from=src,target=/src <<EOF
mkdir -p /dotnet
tar -oxzf /src/dotnet.tar.gz -C /dotnet
EOF

FROM mcr.microsoft.com/dotnet/runtime-deps:8.0.0-preview.6-bookworm-slim-arm64v8

COPY --from=installer /dotnet /usr/share/dotnet
RUN ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
```

For more information about `ADD` or `COPY`, see the following:

- [Dockerfile reference for the ADD instruction](../concepts/dockerfile.md#add)
- [Dockerfile reference for the COPY instruction](../concepts/dockerfile.md#copy)

### ENTRYPOINT

The best use for `ENTRYPOINT` is to set the image's main command, allowing that
image to be run as though it was that command, and then use `CMD` as the
default flags.

The following is an example of an image for the command line tool `s3cmd`:

```dockerfile
ENTRYPOINT ["s3cmd"]
CMD ["--help"]
```

You can use the following command to run the image and show the command's help:

```console
$ docker run s3cmd
```

Or, you can use the right parameters to execute a command, like in the following example:

```console
$ docker run s3cmd ls s3://mybucket
```

This is useful because the image name can double as a reference to the binary as
shown in the command above.

The `ENTRYPOINT` instruction can also be used in combination with a helper
script, allowing it to function in a similar way to the command above, even
when starting the tool may require more than one step.

For example, the [Postgres Official Image](https://hub.docker.com/_/postgres/)
uses the following script as its `ENTRYPOINT`:

```bash
#!/bin/sh
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"
```

This script uses [the `exec` builtin](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#exec) so that the final running application becomes the container's PID 1. This allows the application to receive any Unix signals sent to the container. For more information, see the [`ENTRYPOINT` reference](../concepts/dockerfile.md#entrypoint).

In the following example, a helper script is copied into the container and run via `ENTRYPOINT` on
container start:

```dockerfile
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["postgres"]
```

This script lets you interact with Postgres in several ways.

It can simply start Postgres:

```console
$ docker run postgres
```

Or, you can use it to run Postgres and pass parameters to the server:

```console
$ docker run postgres postgres --help
```

Lastly, you can use it to start a totally different tool, such as Bash:

```console
$ docker run --rm -it postgres bash
```

For more information about `ENTRYPOINT`, see [Dockerfile reference for the ENTRYPOINT instruction](../concepts/dockerfile.md#entrypoint).

### VOLUME

You should use the `VOLUME` instruction to expose any database storage area,
configuration storage, or files and folders created by your Docker container. You
are strongly encouraged to use `VOLUME` for any combination of mutable or user-serviceable
parts of your image.

For more information about `VOLUME`, see [Dockerfile reference for the VOLUME instruction](../concepts/dockerfile.md#volume).

### USER

If a service can run without privileges, use `USER` to change to a non-root
user. Start by creating the user and group in the Dockerfile with something
like the following example:

```dockerfile
RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres
```

> [!NOTE]
>
> Consider an explicit UID/GID.
>
> Users and groups in an image are assigned a non-deterministic UID/GID in that
> the "next" UID/GID is assigned regardless of image rebuilds. So, if it’s
> critical, you should assign an explicit UID/GID.

> [!NOTE]
>
> Due to an [unresolved bug](https://github.com/golang/go/issues/13548) in the
> Go archive/tar package's handling of sparse files, attempting to create a user
> with a significantly large UID inside a Docker container can lead to disk
> exhaustion because `/var/log/faillog` in the container layer is filled with
> NULL (\0) characters. A workaround is to pass the `--no-log-init` flag to
> `useradd`. The Debian/Ubuntu `adduser` wrapper does not support this flag.

Avoid installing or using `sudo` as it has unpredictable TTY and
signal-forwarding behavior that can cause problems. If you absolutely need
functionality similar to `sudo`, such as initializing the daemon as `root` but
running it as non-`root`, consider using [“gosu”](https://github.com/tianon/gosu).

Lastly, to reduce layers and complexity, avoid switching `USER` back and forth
frequently.

For more information about `USER`, see [Dockerfile reference for the USER instruction](../concepts/dockerfile.md#user).

### WORKDIR

For clarity and reliability, you should always use absolute paths for your
`WORKDIR`. Also, you should use `WORKDIR` instead of proliferating instructions
like `RUN cd … && do-something`, which are hard to read, troubleshoot, and
maintain.

For more information about `WORKDIR`, see [Dockerfile reference for the `WORKDIR` instruction](../concepts/dockerfile.md#workdir).

### ONBUILD

An `ONBUILD` command executes after the current Dockerfile build completes.
`ONBUILD` executes in any child image derived `FROM` the current image. Think
of the `ONBUILD` command as an instruction that the parent Dockerfile gives
to the child Dockerfile.

A Docker build executes `ONBUILD` commands before any command in a child
Dockerfile.

`ONBUILD` is useful for images that are going to be built `FROM` a given
image. For example, you would use `ONBUILD` for a language stack image that
builds arbitrary user software written in that language within the
Dockerfile, as you can see in [Ruby’s `ONBUILD` variants](https://github.com/docker-library/ruby/blob/c43fef8a60cea31eb9e7d960a076d633cb62ba8d/2.4/jessie/onbuild/Dockerfile).

Images built with `ONBUILD` should get a separate tag. For example,
`ruby:1.9-onbuild` or `ruby:2.0-onbuild`.

Be careful when putting `ADD` or `COPY` in `ONBUILD`. The image
fails catastrophically if the new build's context is missing the resource being
added. Adding a separate tag, as recommended above, helps mitigate this by
allowing the Dockerfile author to make a choice.

For more information about `ONBUILD`, see [Dockerfile reference for the ONBUILD instruction](../concepts/dockerfile.md#onbuild).


---

# Container Device Interface (CDI)

*Sección: Build*

<!-- vale Docker.We = NO -->

The [Container Device Interface (CDI)](https://github.com/cncf-tags/container-device-interface/blob/main/SPEC.md)
is a specification designed to standardize how devices (like GPUs, FPGAs, and
other hardware accelerators) are exposed to and used by containers. The aim is
to provide a more consistent and secure mechanism for using hardware devices in
containerized environments, addressing the challenges associated with
device-specific setups and configurations.

In addition to enabling the container to interact with the device node, CDI also
lets you specify additional configuration for the device, such as environment
variables, host mounts (such as shared objects), and executable hooks.

## Getting started

To get started with CDI, you need to have a compatible environment set up. This
includes having Docker v27+ installed with [CDI configured](/reference/cli/dockerd.md#configure-cdi-devices)
and Buildx v0.22+.

You also need to create the [device specifications using JSON or YAML files](https://github.com/cncf-tags/container-device-interface/blob/main/SPEC.md#cdi-json-specification)
in one of the following locations:

* `/etc/cdi`
* `/var/run/cdi`
* `/etc/buildkit/cdi`

> [!NOTE]
> Location can be changed by setting the `specDirs` option in the `cdi` section
> of the [`buildkitd.toml` configuration file](../buildkit/configure.md) if you
> are using BuildKit directly. If you're building using the Docker Daemon with
> the `docker` driver, see [Configure CDI devices](/reference/cli/dockerd.md#configure-cdi-devices)
> documentation.

> [!NOTE]
> If you are creating a container builder on WSL, you need to ensure that
> [Docker Desktop](../../desktop/index.md) is installed and [WSL 2 GPU Paravirtualization](../../desktop/features/gpu.md#prerequisites)
> is enabled. Buildx v0.27+ is also required to mount the WSL libraries in the
> container.

## Building with a simple CDI specification

Let's start with a simple CDI specification that injects an environment variable
into the build environment and write it to `/etc/cdi/foo.yaml`:

```yaml {title="/etc/cdi/foo.yaml"}
cdiVersion: "0.6.0"
kind: "vendor1.com/device"
devices:
- name: foo
  containerEdits:
    env:
    - FOO=injected
```

Inspect the `default` builder to verify that `vendor1.com/device` is detected
as a device:

```console
$ docker buildx inspect
Name:   default
Driver: docker

Nodes:
Name:             default
Endpoint:         default
Status:           running
BuildKit version: v0.23.2
Platforms:        linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/amd64/v4, linux/386
Labels:
 org.mobyproject.buildkit.worker.moby.host-gateway-ip: 172.17.0.1
Devices:
 Name:                  vendor1.com/device=foo
 Automatically allowed: false
GC Policy rule#0:
 All:            false
 Filters:        type==source.local,type==exec.cachemount,type==source.git.checkout
 Keep Duration:  48h0m0s
 Max Used Space: 658.9MiB
GC Policy rule#1:
 All:            false
 Keep Duration:  1440h0m0s
 Reserved Space: 4.657GiB
 Max Used Space: 953.7MiB
 Min Free Space: 2.794GiB
GC Policy rule#2:
 All:            false
 Reserved Space: 4.657GiB
 Max Used Space: 953.7MiB
 Min Free Space: 2.794GiB
GC Policy rule#3:
 All:            true
 Reserved Space: 4.657GiB
 Max Used Space: 953.7MiB
 Min Free Space: 2.794GiB
```

Now let's create a Dockerfile to use this device:

```dockerfile
# syntax=docker/dockerfile:1-labs
FROM busybox
RUN --device=vendor1.com/device \
  env | grep ^FOO=
```

Here we use the [`RUN --device` command](../concepts/dockerfile.md#run---device)
and set `vendor1.com/device` which requests the first device available in the
specification. In this case it uses `foo`, which is the first device in
`/etc/cdi/foo.yaml`.

> [!NOTE]
> [`RUN --device` command](../concepts/dockerfile.md#run---device) is only
> featured in [`labs` channel](../buildkit/frontend.md#labs-channel) since
> [Dockerfile frontend v1.14.0-labs](https://github.com/moby/buildkit/releases/tag/dockerfile%2F1.14.0-labs)
> and not yet available in stable syntax.

Now let's build this Dockerfile:

```console
$ docker buildx build .
[+] Building 0.4s (5/5) FINISHED                                                                                                        docker:default
 => [internal] load build definition from Dockerfile                                                                                    0.0s 
 => => transferring dockerfile: 155B                                                                                                    0.0s
 => resolve image config for docker-image://docker/dockerfile:1-labs                                                                    0.1s 
 => CACHED docker-image://docker/dockerfile:1-labs@sha256:9187104f31e3a002a8a6a3209ea1f937fb7486c093cbbde1e14b0fa0d7e4f1b5              0.0s
 => [internal] load metadata for docker.io/library/busybox:latest                                                                       0.1s 
 => [internal] load .dockerignore                                                                                                       0.0s
 => => transferring context: 2B                                                                                                         0.0s 
ERROR: failed to build: failed to solve: failed to load LLB: device vendor1.com/device=foo is requested by the build but not allowed
```

It fails because the device `vendor1.com/device=foo` is not automatically
allowed by the build as shown in the `buildx inspect` output above:

```text
Devices:
 Name:                  vendor1.com/device=foo
 Automatically allowed: false
```

To allow the device, you can use the [`--allow` flag](/reference/cli/docker/buildx/build/#allow)
with the `docker buildx build` command:

```console
$ docker buildx build --allow device .
```

Or you can set the `org.mobyproject.buildkit.device.autoallow` annotation in
the CDI specification to automatically allow the device for all builds:

```yaml {title="/etc/cdi/foo.yaml"}
cdiVersion: "0.6.0"
kind: "vendor1.com/device"
devices:
- name: foo
  containerEdits:
    env:
    - FOO=injected
annotations:
  org.mobyproject.buildkit.device.autoallow: true
```

Now running the build again with the `--allow device` flag:

```console
$ docker buildx build --progress=plain --allow device .
#0 building with "default" instance using docker driver

#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 159B done
#1 DONE 0.0s

#2 resolve image config for docker-image://docker/dockerfile:1-labs
#2 DONE 0.1s

#3 docker-image://docker/dockerfile:1-labs@sha256:9187104f31e3a002a8a6a3209ea1f937fb7486c093cbbde1e14b0fa0d7e4f1b5
#3 CACHED

#4 [internal] load metadata for docker.io/library/busybox:latest
#4 DONE 0.1s

#5 [internal] load .dockerignore
#5 transferring context: 2B done
#5 DONE 0.0s

#6 [1/2] FROM docker.io/library/busybox:latest@sha256:f85340bf132ae937d2c2a763b8335c9bab35d6e8293f70f606b9c6178d84f42b
#6 CACHED

#7 [2/2] RUN --device=vendor1.com/device   env | grep ^FOO=
#7 0.155 FOO=injected
#7 DONE 0.2s
```

The build is successful and the output shows that the `FOO` environment variable
was injected into the build environment as specified in the CDI specification.

## Set up a container builder with GPU support

In this section, we will show you how to set up a [container builder](../builders/drivers/docker-container.md)
using NVIDIA GPUs. Since Buildx v0.22, when creating a new container builder, a
GPU request is automatically added to the container builder if the host has GPU
drivers installed in the kernel. This is similar to using [`--gpus=all` with the `docker run`](/reference/cli/docker/container/run/#gpus)
command.

Now let's create a container builder named `gpubuilder` using Buildx:

```console
$ docker buildx create --name gpubuilder --driver-opt "image=moby/buildkit:buildx-stable-1-gpu" --bootstrap
#1 [internal] booting buildkit
#1 pulling image moby/buildkit:buildx-stable-1-gpu
#1 pulling image moby/buildkit:buildx-stable-1-gpu 1.0s done
#1 creating container buildx_buildkit_gpubuilder0
#1 creating container buildx_buildkit_gpubuilder0 8.8s done
#1 DONE 9.8s
gpubuilder
```

> [!NOTE]
> We made a specially crafted BuildKit image because the current BuildKit
> release image is based on Alpine that doesn't support NVIDIA drivers. The
> following image is based on Ubuntu and installs the NVIDIA client libraries
> and generates the CDI specification for your GPU in the container builder if
> a device is requested during a build.

Let's inspect this builder:

```console
$ docker buildx inspect gpubuilder
Name:          gpubuilder
Driver:        docker-container
Last Activity: 2025-07-10 08:18:09 +0000 UTC

Nodes:
Name:                  gpubuilder0
Endpoint:              unix:///var/run/docker.sock
Driver Options:        image="moby/buildkit:buildx-stable-1-gpu"
Status:                running
BuildKit daemon flags: --allow-insecure-entitlement=network.host
BuildKit version:      v0.26.2
Platforms:             linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
Labels:
 org.mobyproject.buildkit.worker.executor:         oci
 org.mobyproject.buildkit.worker.hostname:         d6aa9cbe8462
 org.mobyproject.buildkit.worker.network:          host
 org.mobyproject.buildkit.worker.oci.process-mode: sandbox
 org.mobyproject.buildkit.worker.selinux.enabled:  false
 org.mobyproject.buildkit.worker.snapshotter:      overlayfs
Devices:
 Name:      nvidia.com/gpu
 On-Demand: true
GC Policy rule#0:
 All:            false
 Filters:        type==source.local,type==exec.cachemount,type==source.git.checkout
 Keep Duration:  48h0m0s
 Max Used Space: 488.3MiB
GC Policy rule#1:
 All:            false
 Keep Duration:  1440h0m0s
 Reserved Space: 9.313GiB
 Max Used Space: 93.13GiB
 Min Free Space: 188.1GiB
GC Policy rule#2:
 All:            false
 Reserved Space: 9.313GiB
 Max Used Space: 93.13GiB
 Min Free Space: 188.1GiB
GC Policy rule#3:
 All:            true
 Reserved Space: 9.313GiB
 Max Used Space: 93.13GiB
 Min Free Space: 188.1GiB
```

We can see `nvidia.com/gpu` vendor is detected as a device in the builder which
means that drivers were detected.

Optionally you can check if NVIDIA GPU devices are available in the container
using `nvidia-smi`:

```console
$ docker exec -it buildx_buildkit_gpubuilder0 nvidia-smi -L
GPU 0: Tesla T4 (UUID: GPU-6cf00fa7-59ac-16f2-3e83-d24ccdc56f84)
```

## Building with GPU support

Let's create a simple Dockerfile that will use the GPU device:

```dockerfile
# syntax=docker/dockerfile:1-labs
FROM ubuntu
RUN --device=nvidia.com/gpu nvidia-smi -L
```

Now run the build using the `gpubuilder` builder we created earlier:

```console
$ docker buildx --builder gpubuilder build --progress=plain .
#0 building with "gpubuilder" instance using docker-container driver
...

#7 preparing device nvidia.com/gpu
#7 0.000 > apt-get update
...
#7 4.872 > apt-get install -y gpg
...
#7 10.16 Downloading NVIDIA GPG key
#7 10.21 > apt-get update
...
#7 12.15 > apt-get install -y --no-install-recommends nvidia-container-toolkit-base
...
#7 17.80 time="2025-04-15T08:58:16Z" level=info msg="Generated CDI spec with version 0.8.0"
#7 DONE 17.8s

#8 [2/2] RUN --device=nvidia.com/gpu nvidia-smi -L
#8 0.527 GPU 0: Tesla T4 (UUID: GPU-6cf00fa7-59ac-16f2-3e83-d24ccdc56f84)
#8 DONE 1.6s
```

As you might have noticed, the step `#7` is preparing the `nvidia.com/gpu`
device by installing client libraries and the toolkit to generate the CDI
specifications for the GPU.

The `nvidia-smi -L` command is then executed in the container using the GPU
device. The output shows the GPU UUID.

You can check the generated CDI specification within the container builder with
the following command:

```console
$ docker exec -it buildx_buildkit_gpubuilder0 cat /etc/cdi/nvidia.yaml
```

For the EC2 instance [`g4dn.xlarge`](https://aws.amazon.com/ec2/instance-types/g4/)
used here, it looks like this:

```yaml {collapse=true}
cdiVersion: 0.6.0
containerEdits:
  deviceNodes:
  - path: /dev/nvidia-modeset
  - path: /dev/nvidia-uvm
  - path: /dev/nvidia-uvm-tools
  - path: /dev/nvidiactl
  env:
  - NVIDIA_VISIBLE_DEVICES=void
  hooks:
  - args:
    - nvidia-cdi-hook
    - create-symlinks
    - --link
    - ../libnvidia-allocator.so.1::/usr/lib/x86_64-linux-gnu/gbm/nvidia-drm_gbm.so
    hookName: createContainer
    path: /usr/bin/nvidia-cdi-hook
  - args:
    - nvidia-cdi-hook
    - create-symlinks
    - --link
    - libcuda.so.1::/usr/lib/x86_64-linux-gnu/libcuda.so
    hookName: createContainer
    path: /usr/bin/nvidia-cdi-hook
  - args:
    - nvidia-cdi-hook
    - enable-cuda-compat
    - --host-driver-version=570.133.20
    hookName: createContainer
    path: /usr/bin/nvidia-cdi-hook
  - args:
    - nvidia-cdi-hook
    - update-ldcache
    - --folder
    - /usr/lib/x86_64-linux-gnu
    hookName: createContainer
    path: /usr/bin/nvidia-cdi-hook
  mounts:
  - containerPath: /run/nvidia-persistenced/socket
    hostPath: /run/nvidia-persistenced/socket
    options:
    - ro
    - nosuid
    - nodev
    - bind
    - noexec
  - containerPath: /usr/bin/nvidia-cuda-mps-control
    hostPath: /usr/bin/nvidia-cuda-mps-control
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/bin/nvidia-cuda-mps-server
    hostPath: /usr/bin/nvidia-cuda-mps-server
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/bin/nvidia-debugdump
    hostPath: /usr/bin/nvidia-debugdump
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/bin/nvidia-persistenced
    hostPath: /usr/bin/nvidia-persistenced
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/bin/nvidia-smi
    hostPath: /usr/bin/nvidia-smi
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libcuda.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libcuda.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libcudadebugger.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libcudadebugger.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-allocator.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-allocator.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-cfg.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-cfg.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-gpucomp.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-gpucomp.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-nscq.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-nscq.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-nvvm.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-nvvm.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-opencl.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-pkcs11-openssl3.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-pkcs11-openssl3.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-pkcs11.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-pkcs11.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.570.133.20
    hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so.570.133.20
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /lib/firmware/nvidia/570.133.20/gsp_ga10x.bin
    hostPath: /lib/firmware/nvidia/570.133.20/gsp_ga10x.bin
    options:
    - ro
    - nosuid
    - nodev
    - bind
  - containerPath: /lib/firmware/nvidia/570.133.20/gsp_tu10x.bin
    hostPath: /lib/firmware/nvidia/570.133.20/gsp_tu10x.bin
    options:
    - ro
    - nosuid
    - nodev
    - bind
devices:
- containerEdits:
    deviceNodes:
    - path: /dev/nvidia0
  name: "0"
- containerEdits:
    deviceNodes:
    - path: /dev/nvidia0
  name: GPU-6cf00fa7-59ac-16f2-3e83-d24ccdc56f84
- containerEdits:
    deviceNodes:
    - path: /dev/nvidia0
  name: all
kind: nvidia.com/gpu
```

Congrats on your first build using a GPU device with BuildKit and CDI.


---

# Export binaries

*Sección: Build*

Did you know that you can use Docker to build your application to standalone
binaries? Sometimes, you don’t want to package and distribute your application
as a Docker image. Use Docker to build your application, and use exporters to
save the output to disk.

The default output format for `docker build` is a container image. That image is
automatically loaded to your local image store, where you can run a container
from that image, or push it to a registry. Under the hood, this uses the default
exporter, called the `docker` exporter.

To export your build results as files instead, you can use the `--output` flag,
or `-o` for short. The `--output` flag lets you change the output format of
your build.

## Export binaries from a build

If you specify a filepath to the `docker build --output` flag, Docker exports
the contents of the build container at the end of the build to the specified
location on your host's filesystem. This uses the `local`
[exporter](../exporters/local-tar.md).

The neat thing about this is that you can use Docker's powerful isolation and
build features to create standalone binaries. This
works well for Go, Rust, and other languages that can compile to a single
binary.

The following example creates a simple Rust program that prints "Hello,
World!", and exports the binary to the host filesystem.

1. Create a new directory for this example, and navigate to it:

   ```console
   $ mkdir hello-world-bin
   $ cd hello-world-bin
   ```

2. Create a Dockerfile with the following contents:

   ```Dockerfile
   # syntax=docker/dockerfile:1
   FROM rust:alpine AS build
   WORKDIR /src
   COPY <<EOT hello.rs
   fn main() {
       println!("Hello World!");
   }
   EOT
   RUN rustc -o /bin/hello hello.rs
   
   FROM scratch
   COPY --from=build /bin/hello /
   ENTRYPOINT ["/hello"]
   ```

   > [!TIP]
   > The `COPY <<EOT` syntax is a [here-document](../concepts/dockerfile.md#here-documents).
   > It lets you write multi-line strings in a Dockerfile. Here it's used to
   > create a simple Rust program inline in the Dockerfile.

   This Dockerfile uses a multi-stage build to compile the program in the first
   stage, and then copies the binary to a scratch image in the second. The
   final image is a minimal image that only contains the binary. This use case
   for the `scratch` image is common for creating minimal build artifacts for
   programs that don't require a full operating system to run.

3. Build the Dockerfile and export the binary to the current working directory:

   ```console
   $ docker build --output=. .
   ```

   This command builds the Dockerfile and exports the binary to the current
   working directory. The binary is named `hello`, and it's created in the
   current working directory.

## Exporting multi-platform builds

You use the `local` exporter to export binaries in combination with
[multi-platform builds](multi-platform.md). This lets you
compile multiple binaries at once, that can be run on any machine of any
architecture, provided that the target platform is supported by the compiler
you use.

Continuing on the example Dockerfile in the
[Export binaries from a build](#export-binaries-from-a-build) section:

```dockerfile
# syntax=docker/dockerfile:1
FROM rust:alpine AS build
WORKDIR /src
COPY <<EOT hello.rs
fn main() {
    println!("Hello World!");
}
EOT
RUN rustc -o /bin/hello hello.rs

FROM scratch
COPY --from=build /bin/hello /
ENTRYPOINT ["/hello"]
```

You can build this Rust program for multiple platforms using the `--platform`
flag with the `docker build` command. In combination with the `--output` flag,
the build exports the binaries for each target to the specified directory.

For example, to build the program for both `linux/amd64` and `linux/arm64`:

```console
$ docker build --platform=linux/amd64,linux/arm64 --output=out .
$ tree out/
out/
├── linux_amd64
│   └── hello
└── linux_arm64
    └── hello

3 directories, 2 files
```

## Additional information

In addition to the `local` exporter, there are other exporters available. To
learn more about the available exporters and how to use them, see the
[exporters](../exporters/index.md) documentation.


---

# Multi-platform builds

*Sección: Build*

A multi-platform build refers to a single build invocation that targets
multiple different operating system or CPU architecture combinations. When
building images, this lets you create a single image that can run on multiple
platforms, such as `linux/amd64`, `linux/arm64`, and `windows/amd64`.

## Why multi-platform builds?

Docker solves the "it works on my machine" problem by packaging applications
and their dependencies into containers. This makes it easy to run the same
application on different environments, such as development, testing, and
production.

But containerization by itself only solves part of the problem. Containers
share the host kernel, which means that the code that's running inside the
container must be compatible with the host's architecture. This is why you
can't run a `linux/amd64` container on an arm64 host (without using emulation),
or a Windows container on a Linux host.

Multi-platform builds solve this problem by packaging multiple variants of the
same application into a single image. This enables you to run the same image on
different types of hardware, such as development machines running x86-64 or
ARM-based Amazon EC2 instances in the cloud, without the need for emulation.

### Difference between single-platform and multi-platform images

Multi-platform images have a different structure than single-platform images.
Single-platform images contain a single manifest that points to a single
configuration and a single set of layers. Multi-platform images contain a
manifest list, pointing to multiple manifests, each of which points to a
different configuration and set of layers.

![Multi-platform image structure](/build/images/single-vs-multiplatform-image.svg)

When you push a multi-platform image to a registry, the registry stores the
manifest list and all the individual manifests. When you pull the image, the
registry returns the manifest list, and Docker automatically selects the
correct variant based on the host's architecture. For example, if you run a
multi-platform image on an ARM-based Raspberry Pi, Docker selects the
`linux/arm64` variant. If you run the same image on an x86-64 laptop, Docker
selects the `linux/amd64` variant (if you're using Linux containers).

## Prerequisites

Multi-platform images require an image store that supports manifest lists.
Docker Desktop and Docker Engine 29.0+ use the
[containerd image store](../../desktop/features/containerd.md) by default,
which supports multi-platform images out of the box. If you're using one of
these versions, no additional setup is needed.

If you're using an older version of Docker Engine, or if you upgraded from an
older version that still uses classic storage drivers, you have two options:

- Enable the containerd image store using the
  [daemon configuration file](../../engine/storage/containerd.md).
- Create a custom builder using the `docker-container` driver (see the following section).

### Custom builder

As an alternative to using the containerd image store, you can create a custom
builder that uses the `docker-container` driver. This driver supports
multi-platform builds, but the resulting images aren't loaded into your Docker
Engine image store. You can push them to a container registry directly with
`docker build --push`.

```console
$ docker buildx create \
  --name container-builder \
  --driver docker-container \
  --bootstrap --use
```

> [!NOTE]
> Builds with the `docker-container` driver aren't automatically loaded to your
> Docker Engine image store. For more information, see [Build
> drivers](../builders/drivers/index.md).

If you're using Docker Engine standalone and you need to build multi-platform
images using emulation, official BuildKit releases bundle QEMU user-mode
emulators, so in most cases you don't need to install QEMU manually. See
[Install QEMU manually](#install-qemu-manually) if emulation fails, for
example with a third-party BuildKit package that doesn't ship the bundled
emulators.

## Build multi-platform images

When triggering a build, use the `--platform` flag to define the target
platforms for the build output, such as `linux/amd64` and `linux/arm64`:

```console
$ docker buildx build --platform linux/amd64,linux/arm64 .
```

## Strategies

You can build multi-platform images using three different strategies,
depending on your use case:

1. Using emulation, via [QEMU](#qemu)
2. Use a builder with [multiple native nodes](#multiple-native-nodes)
3. Use [cross-compilation](#cross-compilation) with multi-stage builds

### QEMU

Building multi-platform images under emulation with QEMU is the easiest way to
get started if your builder already supports it. Using emulation requires no
changes to your Dockerfile, and BuildKit automatically detects the
architectures that are available for emulation.

> [!NOTE]
>
> Emulation with QEMU can be much slower than native builds, especially for
> compute-heavy tasks like compilation and compression or decompression.
>
> Use [multiple native nodes](#multiple-native-nodes) or
> [cross-compilation](#cross-compilation) instead, if possible.

Docker Desktop supports running and building multi-platform images under
emulation by default. No configuration is necessary as the builder uses the
QEMU that's bundled within the Docker Desktop VM.

#### Install QEMU manually

If the QEMU emulators bundled with BuildKit don't work for your build, for
example with a third-party BuildKit package that doesn't ship them, you can
install QEMU and register the executable types on the host OS. The
prerequisites for installing QEMU are:

- Linux kernel version 4.8 or later
- `binfmt-support` version 2.1.7 or later
- The QEMU binaries must be statically compiled and registered with the
  `fix_binary` flag

Use the [`tonistiigi/binfmt`](https://github.com/tonistiigi/binfmt) image to
install QEMU and register the executable types on the host with a single
command:

```console
$ docker run --privileged --rm tonistiigi/binfmt --install all
```

This installs the QEMU binaries and registers them with
[`binfmt_misc`](https://en.wikipedia.org/wiki/Binfmt_misc), enabling QEMU to
execute non-native file formats for emulation.

Once QEMU is installed and the executable types are registered on the host OS,
they work transparently inside containers. You can verify your registration by
checking if `F` is among the flags in `/proc/sys/fs/binfmt_misc/qemu-*`.

### Multiple native nodes

Using multiple native nodes provide better support for more complicated cases
that QEMU can't handle, and also provides better performance.

You can add additional nodes to a builder using the `--append` flag.

The following command creates a multi-node builder from Docker contexts named
`node-amd64` and `node-arm64`. This example assumes that you've already added
those contexts.

```console
$ docker buildx create --use --name mybuild node-amd64
mybuild
$ docker buildx create --append --name mybuild node-arm64
$ docker buildx build --platform linux/amd64,linux/arm64 .
```

While this approach has advantages over emulation, managing multi-node builders
introduces some overhead of setting up and managing builder clusters.
Alternatively, you can use Docker Build Cloud, a service that provides managed
multi-node builders on Docker's infrastructure. With Docker Build Cloud, you
get native multi-platform ARM and X86 builders without the burden of
maintaining them. Using cloud builders also provides additional benefits, such
as a shared build cache.

After signing up for Docker Build Cloud, add the builder to your local
environment and start building.

```console
$ docker buildx create --driver cloud <ORG>/<BUILDER_NAME>
cloud-<ORG>-<BUILDER_NAME>
$ docker build \
  --builder cloud-<ORG>-<BUILDER_NAME> \
  --platform linux/amd64,linux/arm64,linux/arm/v7 \
  --tag <IMAGE_NAME> \
  --push .
```

For more information, see [Docker Build Cloud](../../build-cloud/index.md).

### Cross-compilation

Depending on your project, if the programming language you use has good support
for cross-compilation, you can leverage multi-stage builds to build binaries
for target platforms from the native architecture of the builder. Special build
arguments, such as `BUILDPLATFORM` and `TARGETPLATFORM`, are automatically
available for use in your Dockerfile.

In the following example, the `FROM` instruction is pinned to the native
platform of the builder (using the `--platform=$BUILDPLATFORM` option) to
prevent emulation from kicking in. Then the pre-defined `$BUILDPLATFORM` and
`$TARGETPLATFORM` build arguments are interpolated in a `RUN` instruction. In
this case, the values are just printed to stdout with `echo`, but this
illustrates how you would pass them to the compiler for cross-compilation.

```dockerfile
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM golang:alpine AS build
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM" > /log
FROM alpine
COPY --from=build /log /log
```

## Examples

Here are some examples of multi-platform builds:

- [Simple multi-platform build using emulation](#simple-multi-platform-build-using-emulation)
- [Multi-platform Neovim build using Docker Build Cloud](#multi-platform-neovim-build-using-docker-build-cloud)
- [Cross-compiling a Go application](#cross-compiling-a-go-application)

### Simple multi-platform build using emulation

This example demonstrates how to build a simple multi-platform image using
emulation with QEMU. The image contains a single file that prints the
architecture of the container.

Prerequisites:

- Docker Desktop, or Docker Engine with [QEMU installed](#install-qemu-manually)

Steps:

1. Create an empty directory and navigate to it:

   ```console
   $ mkdir multi-platform
   $ cd multi-platform
   ```

2. Create a simple Dockerfile that prints the architecture of the container:

   ```dockerfile
   # syntax=docker/dockerfile:1
   FROM alpine
   RUN uname -m > /arch
   ```

3. Build the image for `linux/amd64` and `linux/arm64`:

   ```console
   $ docker build --platform linux/amd64,linux/arm64 -t multi-platform .
   ```

4. Run the image and print the architecture:

   ```console
   $ docker run --rm multi-platform cat /arch
   ```

   - If you're running on an x86-64 machine, you should see `x86_64`.
   - If you're running on an ARM machine, you should see `aarch64`.

### Multi-platform Neovim build using Docker Build Cloud

This example demonstrates how run a multi-platform build using Docker Build
Cloud to compile and export [Neovim](https://github.com/neovim/neovim) binaries
for the `linux/amd64` and `linux/arm64` platforms.

Docker Build Cloud provides managed multi-node builders that support native
multi-platform builds without the need for emulation, making it much faster to
do CPU-intensive tasks like compilation.

Prerequisites:

- You've [signed up for Docker Build Cloud and created a builder](../../build-cloud/setup.md)

Steps:

1. Create an empty directory and navigate to it:

   ```console
   $ mkdir docker-build-neovim
   $ cd docker-build-neovim
   ```

2. Create a Dockerfile that builds Neovim.

   ```dockerfile
   # syntax=docker/dockerfile:1
   FROM debian:bookworm AS build
   WORKDIR /work
   RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
       --mount=type=cache,target=/var/lib/apt,sharing=locked \
       apt-get update && apt-get install -y \
       build-essential \
       cmake \
       curl \
       gettext \
       ninja-build \
       unzip
   ADD https://github.com/neovim/neovim.git#stable .
   RUN make CMAKE_BUILD_TYPE=RelWithDebInfo

   FROM scratch
   COPY --from=build /work/build/bin/nvim /
   ```

3. Build the image for `linux/amd64` and `linux/arm64` using Docker Build Cloud:

   ```console
   $ docker build \
      --builder <cloud-builder> \
      --platform linux/amd64,linux/arm64 \
      --output ./bin .
   ```

   This command builds the image using the cloud builder and exports the
   binaries to the `bin` directory.

4. Verify that the binaries are built for both platforms. You should see the
   `nvim` binary for both `linux/amd64` and `linux/arm64`.

   ```console
   $ tree ./bin
   ./bin
   ├── linux_amd64
   │   └── nvim
   └── linux_arm64
       └── nvim

   3 directories, 2 files
   ```

### Cross-compiling a Go application

This example demonstrates how to cross-compile a Go application for multiple
platforms using multi-stage builds. The application is a simple HTTP server
that listens on port 8080 and returns the architecture of the container.
This example uses Go, but the same principles apply to other programming
languages that support cross-compilation.

Cross-compilation with Docker builds works by leveraging a series of
pre-defined (in BuildKit) build arguments that give you information about
platforms of the builder and the build targets. You can use these pre-defined
arguments to pass the platform information to the compiler.

In Go, you can use the `GOOS` and `GOARCH` environment variables to specify the
target platform to build for.

Prerequisites:

- Docker Desktop or Docker Engine

Steps:

1. Create an empty directory and navigate to it:

   ```console
   $ mkdir go-server
   $ cd go-server
   ```

2. Create a base Dockerfile that builds the Go application:

   ```dockerfile
   # syntax=docker/dockerfile:1
   FROM golang:alpine AS build
   WORKDIR /app
   ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 .
   RUN go build -o server .

   FROM alpine
   COPY --from=build /app/server /server
   ENTRYPOINT ["/server"]
   ```

   This Dockerfile can't build multi-platform with cross-compilation yet. If
   you were to try to build this Dockerfile with `docker build`, the builder
   would attempt to use emulation to build the image for the specified
   platforms.

3. To add cross-compilation support, update the Dockerfile to use the
   pre-defined `BUILDPLATFORM`, `TARGETOS` and `TARGETARCH` build arguments.
   - Pin the `golang` image to the platform of the builder using the
     `--platform=$BUILDPLATFORM` option.
   - Add `ARG` instructions for the Go compilation stages to make the
     `TARGETOS` and `TARGETARCH` build arguments available to the commands in
     this stage.
   - Set the `GOOS` and `GOARCH` environment variables to the values of
     `TARGETOS` and `TARGETARCH`. The Go compiler uses these variables to do
     cross-compilation.

   {{< tabs >}}
   {{< tab name="Updated Dockerfile" >}}

   ```dockerfile
   # syntax=docker/dockerfile:1
   FROM --platform=$BUILDPLATFORM golang:alpine AS build
   ARG TARGETOS
   ARG TARGETARCH
   WORKDIR /app
   ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 .
   RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o server .

   FROM alpine
   COPY --from=build /app/server /server
   ENTRYPOINT ["/server"]
   ```

   {{< /tab >}}
   {{< tab name="Old Dockerfile" >}}

   ```dockerfile
   # syntax=docker/dockerfile:1
   FROM golang:alpine AS build
   WORKDIR /app
   ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 .
   RUN go build -o server .

   FROM alpine
   COPY --from=build /app/server /server
   ENTRYPOINT ["/server"]
   ```

   {{< /tab >}}
   {{< tab name="Diff" >}}

   ```diff
   # syntax=docker/dockerfile:1
   -FROM golang:alpine AS build
   +FROM --platform=$BUILDPLATFORM golang:alpine AS build
   +ARG TARGETOS
   +ARG TARGETARCH
   WORKDIR /app
   ADD https://github.com/dvdksn/buildme.git#eb6279e0ad8a10003718656c6867539bd9426ad8 .
   -RUN go build -o server .
   +RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o server .

   FROM alpine
   COPY --from=build /app/server /server
   ENTRYPOINT ["/server"]
   ```

   {{< /tab >}}
   {{< /tabs >}}

4. Build the image for `linux/amd64` and `linux/arm64`:

   ```console
   $ docker build --platform linux/amd64,linux/arm64 -t go-server .
   ```

This example has shown how to cross-compile a Go application for multiple
platforms with Docker builds. The specific steps on how to do cross-compilation
may vary depending on the programming language you're using. Consult the
documentation for your programming language to learn more about cross-compiling
for different platforms.

> [!TIP]
> You may also want to consider checking out
> [xx - Dockerfile cross-compilation helpers](https://github.com/tonistiigi/xx).
> `xx` is a Docker image containing utility scripts that make cross-compiling with Docker builds easier.


---

# Multi-stage builds

*Sección: Build*

Multi-stage builds are useful to anyone who has struggled to optimize
Dockerfiles while keeping them easy to read and maintain.

## Use multi-stage builds

With multi-stage builds, you use multiple `FROM` statements in your Dockerfile.
Each `FROM` instruction can use a different base, and each of them begins a new
stage of the build. You can selectively copy artifacts from one stage to
another, leaving behind everything you don't want in the final image.

The following Dockerfile has two separate stages: one for building a binary,
and another where the binary gets copied from the first stage into the next stage.

```dockerfile
# syntax=docker/dockerfile:1
FROM golang:{{% param "example_go_version" %}}
WORKDIR /src
COPY <<EOF ./main.go
package main

import "fmt"

func main() {
  fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go

FROM scratch
COPY --from=0 /bin/hello /bin/hello
CMD ["/bin/hello"]
```

You only need the single Dockerfile. No need for a separate build script. Just
run `docker build`.

```console
$ docker build -t hello .
```

The end result is a tiny production image with nothing but the binary inside.
None of the build tools required to build the application are included in the
resulting image.

How does it work? The second `FROM` instruction starts a new build stage with
the `scratch` image as its base. The `COPY --from=0` line copies just the
built artifact from the previous stage into this new stage. The Go SDK and any
intermediate artifacts are left behind, and not saved in the final image.

## Name your build stages

By default, the stages aren't named, and you refer to them by their integer
number, starting with 0 for the first `FROM` instruction. However, you can
name your stages, by adding an `AS <NAME>` to the `FROM` instruction. This
example improves the previous one by naming the stages and using the name in
the `COPY` instruction. This means that even if the instructions in your
Dockerfile are re-ordered later, the `COPY` doesn't break.

```dockerfile
# syntax=docker/dockerfile:1
FROM golang:{{% param "example_go_version" %}} AS build
WORKDIR /src
COPY <<EOF /src/main.go
package main

import "fmt"

func main() {
  fmt.Println("hello, world")
}
EOF
RUN go build -o /bin/hello ./main.go

FROM scratch
COPY --from=build /bin/hello /bin/hello
CMD ["/bin/hello"]
```

## Stop at a specific build stage

When you build your image, you don't necessarily need to build the entire
Dockerfile including every stage. You can specify a target build stage. The
following command assumes you are using the previous `Dockerfile` but stops at
the stage named `build`:

```console
$ docker build --target build -t hello .
```

A few scenarios where this might be useful are:

- Debugging a specific build stage
- Using a `debug` stage with all debugging symbols or tools enabled, and a
  lean `production` stage
- Using a `testing` stage in which your app gets populated with test data, but
  building for production using a different stage which uses real data

## Use an external image as a stage

When using multi-stage builds, you aren't limited to copying from stages you
created earlier in your Dockerfile. You can use the `COPY --from` instruction to
copy from a separate image, either using the local image name, a tag available
locally or on a Docker registry, or a tag ID. The Docker client pulls the image
if necessary and copies the artifact from there. The syntax is:

```dockerfile
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
```

## Use a previous stage as a new stage

You can pick up where a previous stage left off by referring to it when using
the `FROM` directive. For example:

```dockerfile
# syntax=docker/dockerfile:1

FROM alpine:latest AS builder
RUN apk --no-cache add build-base

FROM builder AS build1
COPY source1.cpp source.cpp
RUN g++ -o /binary source.cpp

FROM builder AS build2
COPY source2.cpp source.cpp
RUN g++ -o /binary source.cpp
```

## Differences between legacy builder and BuildKit

The legacy Docker Engine builder processes all stages of a Dockerfile leading
up to the selected `--target`. It will build a stage even if the selected
target doesn't depend on that stage.

[BuildKit](../buildkit/index.md) only builds the stages that the target stage
depends on.

For example, given the following Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu AS base
RUN echo "base"

FROM base AS stage1
RUN echo "stage1"

FROM base AS stage2
RUN echo "stage2"
```

With [BuildKit enabled](../buildkit/index.md#getting-started), building the
`stage2` target in this Dockerfile means only `base` and `stage2` are processed.
There is no dependency on `stage1`, so it's skipped.

```console
$ DOCKER_BUILDKIT=1 docker build --no-cache -f Dockerfile --target stage2 .
[+] Building 0.4s (7/7) FINISHED                                                                    
 => [internal] load build definition from Dockerfile                                            0.0s
 => => transferring dockerfile: 36B                                                             0.0s
 => [internal] load .dockerignore                                                               0.0s
 => => transferring context: 2B                                                                 0.0s
 => [internal] load metadata for docker.io/library/ubuntu:latest                                0.0s
 => CACHED [base 1/2] FROM docker.io/library/ubuntu                                             0.0s
 => [base 2/2] RUN echo "base"                                                                  0.1s
 => [stage2 1/1] RUN echo "stage2"                                                              0.2s
 => exporting to image                                                                          0.0s
 => => exporting layers                                                                         0.0s
 => => writing image sha256:f55003b607cef37614f607f0728e6fd4d113a4bf7ef12210da338c716f2cfd15    0.0s
```

On the other hand, building the same target without BuildKit results in all
stages being processed:

```console
$ DOCKER_BUILDKIT=0 docker build --no-cache -f Dockerfile --target stage2 .
Sending build context to Docker daemon  219.1kB
Step 1/6 : FROM ubuntu AS base
 ---> a7870fd478f4
Step 2/6 : RUN echo "base"
 ---> Running in e850d0e42eca
base
Removing intermediate container e850d0e42eca
 ---> d9f69f23cac8
Step 3/6 : FROM base AS stage1
 ---> d9f69f23cac8
Step 4/6 : RUN echo "stage1"
 ---> Running in 758ba6c1a9a3
stage1
Removing intermediate container 758ba6c1a9a3
 ---> 396baa55b8c3
Step 5/6 : FROM base AS stage2
 ---> d9f69f23cac8
Step 6/6 : RUN echo "stage2"
 ---> Running in bbc025b93175
stage2
Removing intermediate container bbc025b93175
 ---> 09fc3770a9c4
Successfully built 09fc3770a9c4
```

The legacy builder processes `stage1`, even if `stage2` doesn't depend on it.


---

# Build secrets

*Sección: Build*

A build secret is any piece of sensitive information, such as a password or API
token, consumed as part of your application's build process.

Build arguments and environment variables are inappropriate for passing secrets
to your build, because they persist in the final image. Instead, you should use
secret mounts or SSH mounts, which expose secrets to your builds securely.

## Types of build secrets

- [Secret mounts](#secret-mounts) are general-purpose mounts for passing
  secrets into your build. A secret mount takes a secret from the build client
  and makes it temporarily available inside the build container, for the
  duration of the build instruction. This is useful if, for example, your build
  needs to communicate with a private artifact server or API.
- [SSH mounts](#ssh-mounts) are special-purpose mounts for making SSH sockets
  or keys available inside builds. They're commonly used when you need to fetch
  private Git repositories in your builds.
- [Git authentication for remote contexts](#git-authentication-for-remote-contexts)
  is a set of pre-defined secrets for when you build with a remote Git context
  that's also a private repository. These secrets are "pre-flight" secrets:
  they are not consumed within your build instruction, but they're used to
  provide the builder with the necessary credentials to fetch the context.

## Using build secrets

For secret mounts and SSH mounts, using build secrets is a two-step process.
First you need to pass the secret into the `docker build` command, and then you
need to consume the secret in your Dockerfile.

To pass a secret to a build, use the [`docker build --secret`
flag](/reference/cli/docker/buildx/build/#secret), or the
equivalent options for [Bake](../bake/reference.md#targetsecret).

{{< tabs >}}
{{< tab name="CLI" >}}

```console
$ docker build --secret id=aws,src=$HOME/.aws/credentials .
```

{{< /tab >}}
{{< tab name="Bake" >}}

```hcl
variable "HOME" {
  default = null
}

target "default" {
  secret = [
    "id=aws,src=${HOME}/.aws/credentials"
  ]
}
```

{{< /tab >}}
{{< /tabs >}}

To consume a secret in a build and make it accessible to the `RUN` instruction,
use the [`--mount=type=secret`](../concepts/dockerfile.md#run---mounttypesecret)
flag in the Dockerfile.

```dockerfile
RUN --mount=type=secret,id=aws \
    AWS_SHARED_CREDENTIALS_FILE=/run/secrets/aws \
    aws s3 cp ...
```

## Secret mounts

Secret mounts expose secrets to the build containers, as files or environment
variables. You can use secret mounts to pass sensitive information to your
builds, such as API tokens, passwords, or SSH keys.

### Sources

The source of a secret can be either a
[file](/reference/cli/docker/buildx/build/#file) or an
[environment variable](/reference/cli/docker/buildx/build/#typeenv).
When you use the CLI or Bake, the type can be detected automatically. You can
also specify it explicitly with `type=file` or `type=env`.

The following example mounts the environment variable `KUBECONFIG` to secret ID `kube`,
as a file in the build container at `/run/secrets/kube`.

```console
$ docker build --secret id=kube,env=KUBECONFIG .
```

When you use secrets from environment variables, you can omit the `env` parameter
to bind the secret to a file with the same name as the variable.
In the following example, the value of the `API_TOKEN` variable
is mounted to `/run/secrets/API_TOKEN` in the build container.

```console
$ docker build --secret id=API_TOKEN .
```

### Target

When consuming a secret in a Dockerfile, the secret is mounted to a file by
default. The default file path of the secret, inside the build container, is
`/run/secrets/<id>`. You can customize how the secrets get mounted in the build
container using the `target` and `env` options for the `RUN --mount` flag in
the Dockerfile.

The following example takes secret id `aws` and mounts it to a file at
`/run/secrets/aws` in the build container.

```dockerfile
RUN --mount=type=secret,id=aws \
    AWS_SHARED_CREDENTIALS_FILE=/run/secrets/aws \
    aws s3 cp ...
```

To mount a secret as a file with a different name, use the `target` option in
the `--mount` flag.

```dockerfile
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
    aws s3 cp ...
```

To mount a secret as an environment variable instead of a file, use the
`env` option in the `--mount` flag.

```dockerfile
RUN --mount=type=secret,id=aws-key-id,env=AWS_ACCESS_KEY_ID \
    --mount=type=secret,id=aws-secret-key,env=AWS_SECRET_ACCESS_KEY \
    --mount=type=secret,id=aws-session-token,env=AWS_SESSION_TOKEN \
    aws s3 cp ...
```

It's possible to use the `target` and `env` options together to mount a secret
as both a file and an environment variable.

## SSH mounts

If the credential you want to use in your build is an SSH agent socket or key,
you can use the SSH mount instead of a secret mount. Cloning private Git
repositories is a common use case for SSH mounts.

The following example clones a private GitHub repository using a [Dockerfile
SSH mount](../concepts/dockerfile.md#run---mounttypessh).

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
ADD git@github.com:me/myprivaterepo.git /src/
```

To pass an SSH socket the build, you use the [`docker build --ssh`
flag](/reference/cli/docker/buildx/build/#ssh), or equivalent
options for [Bake](../bake/reference.md#targetssh).

```console
$ docker buildx build --ssh default .
```

## Git authentication for remote contexts

BuildKit supports two pre-defined build secrets, `GIT_AUTH_TOKEN` and
`GIT_AUTH_HEADER`. Use them to specify HTTP authentication parameters when
building with remote, private Git repositories, including:

- Building with a private Git repository as build context
- Fetching private Git repositories in a build with `ADD`

For example, say you have a private GitHub repository at
`https://github.com/example/todo-app.git`, and you want to run a build using
that repository as the build context. An unauthenticated `docker build` command
fails because the builder isn't authorized to pull the repository:

```console
$ docker build https://github.com/example/todo-app.git
[+] Building 0.4s (1/1) FINISHED
 => ERROR [internal] load git source https://github.com/example/todo-app.git
------
 > [internal] load git source https://github.com/example/todo-app.git:
0.313 fatal: could not read Username for 'https://github.com': terminal prompts disabled
------
```

To authenticate the builder to GitHub, set the `GIT_AUTH_TOKEN`
environment variable to contain a valid GitHub access token, and pass it as a
secret to the build:

```console
$ GIT_AUTH_TOKEN=$(gh auth token) docker build \
  --secret id=GIT_AUTH_TOKEN \
  https://github.com/example/todo-app.git
```

The `GIT_AUTH_TOKEN` also works with `ADD` to fetch private Git repositories as
part of your build:

```dockerfile
FROM alpine
ADD https://github.com/example/todo-app.git /src
```

### HTTP authentication scheme

BuildKit supports two Git authentication secrets:

- **`GIT_AUTH_TOKEN`**: Uses Basic authentication with a fixed username of `x-access-token` (the GitHub-style default)
- **`GIT_AUTH_HEADER`**: Uses the raw authorization header value you provide (works with any Git provider)

#### Using GIT_AUTH_TOKEN (for example, GitHub)

When you use `GIT_AUTH_TOKEN`, BuildKit constructs a Basic authentication header using `x-access-token` as the user:

```http
Authorization: Basic <base64("x-access-token:<GIT_AUTH_TOKEN>")>
```

This method works for providers that accept the `x-access-token` Basic auth pattern, such as GitHub. Example usage:

```console
$ export GIT_AUTH_TOKEN=$(gh auth token)
$ docker build \
  --secret id=GIT_AUTH_TOKEN \
  https://github.com/example/todo-app.git
```

#### Using GIT_AUTH_HEADER (custom authorization header)

When you use `GIT_AUTH_HEADER`, BuildKit uses the exact value you provide as the `Authorization` header:

```http
Authorization: <GIT_AUTH_HEADER>
```

Example usage with GitLab CI/CD token:

```console
$ export GIT_AUTH_HEADER="Basic $(echo -n "gitlab-ci-token:${CI_JOB_TOKEN}" | base64)"
$ docker build \
  --secret id=GIT_AUTH_HEADER \
  https://gitlab.com/example/todo-app.git
```

### Multiple hosts

You can set the `GIT_AUTH_TOKEN` and `GIT_AUTH_HEADER` secrets on a per-host
basis, which lets you use different authentication parameters for different
hostnames. To specify a hostname, append the hostname as a suffix to the secret
ID:

```console
$ export GITHUB_TOKEN=$(gh auth token)
$ export GITLAB_AUTH_HEADER="Basic $(echo -n "gitlab-ci-token:${CI_JOB_TOKEN}" | base64)"
$ docker build \
  --secret id=GIT_AUTH_TOKEN.github.com,env=GITHUB_TOKEN \
  --secret id=GIT_AUTH_HEADER.gitlab.com,env=GITLAB_AUTH_HEADER \
  https://github.com/example/todo-app.git
```

## HTTP authentication for `COPY` and `ADD`

To use secrets in `COPY` or `ADD` commands, you can create
`HTTP_AUTH_TOKEN_<host>` or `HTTP_AUTH_HEADER_<host>` secrets for use when
accessing the specified host. For example `HTTP_AUTH_TOKEN_127.0.0.1=token` will
make requests to `127.0.0.1` add a header `Authorization: Bearer token`.

These variables follow the same convention as the [Git HTTP authentication
scheme](#http-authentication-scheme) handling.


---

# Build variables

*Sección: Build*

In Docker Build, build arguments (`ARG`) and environment variables (`ENV`)
both serve as a means to pass information into the build process.
You can use them to parameterize the build, allowing for more flexible and configurable builds.

> [!WARNING]
>
> Build arguments and environment variables are inappropriate for passing secrets
> to your build, because they're exposed in the final image. Instead, use
> secret mounts or SSH mounts, which expose secrets to your builds securely.
>
> See [Build secrets](secrets.md) for more information.

## Similarities and differences

Build arguments and environment variables are similar.
They're both declared in the Dockerfile and can be set using flags for the `docker build` command.
Both can be used to parameterize the build.
But they each serve a distinct purpose.

### Build arguments

Build arguments are variables for the Dockerfile itself.
Use them to parameterize values of Dockerfile instructions.
For example, you might use a build argument to specify the version of a dependency to install.

Build arguments have no effect on the build unless it's used in an instruction.
They're not accessible or present in containers instantiated from the image
unless explicitly passed through from the Dockerfile into the image filesystem or configuration.
They may persist in the image metadata, as provenance attestations and in the image history,
which is why they're not suitable for holding secrets.

They make Dockerfiles more flexible, and easier to maintain.

For an example on how you can use build arguments,
see [`ARG` usage example](#arg-usage-example).

### Environment variables

Environment variables are passed through to the build execution environment,
and persist in containers instantiated from the image.

Environment variables are primarily used to:

- Configure the execution environment for builds
- Set default environment variables for containers

Environment variables, if set, can directly influence the execution of your build,
and the behavior or configuration of the application.

You can't override or set an environment variable at build-time.
Values for environment variables must be declared in the Dockerfile.
You can combine environment variables and build arguments to allow
environment variables to be configured at build-time.

For an example on how to use environment variables for configuring builds,
see [`ENV` usage example](#env-usage-example).

## `ARG` usage example

Build arguments are commonly used to specify versions of components,
such as image variants or package versions, used in a build.

Specifying versions as build arguments lets you build with different versions
without having to manually update the Dockerfile.
It also makes it easier to maintain the Dockerfile,
since it lets you declare versions at the top of the file.

Build arguments can also be a way to reuse a value in multiple places.
For example, if you use multiple flavors of `alpine` in your build,
you can ensure you're using the same version of `alpine` everywhere:

- `golang:1.22-alpine${ALPINE_VERSION}`
- `python:3.12-alpine${ALPINE_VERSION}`
- `nginx:1-alpine${ALPINE_VERSION}`

The following example defines the version of `node` and `alpine` using build arguments.

```dockerfile
# syntax=docker/dockerfile:1

ARG NODE_VERSION="{{% param example_node_version %}}"
ARG ALPINE_VERSION="{{% param example_alpine_version %}}"

FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS base
WORKDIR /src

FROM base AS build
COPY package*.json ./
RUN npm ci
RUN npm run build

FROM base AS production
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=build /src/dist/ .
CMD ["node", "app.js"]
```

In this case, the build arguments have default values.
Specifying their values when you invoke a build is optional.
To override the defaults, you would use the `--build-arg` CLI flag:

```console
$ docker build --build-arg NODE_VERSION=current .
```

For more information on how to use build arguments, refer to:

- [`ARG` Dockerfile reference](../concepts/dockerfile.md#arg)
- [`docker build --build-arg` reference](/reference/cli/docker/buildx/build/#build-arg)

## `ENV` usage example

Declaring an environment variable with `ENV` makes the variable
available to all subsequent instructions in the build stage.
The following example shows an example setting `NODE_ENV` to `production`
before installing JavaScript dependencies with `npm`.
Setting the variable makes `npm` omits packages needed only for local development.

```dockerfile
# syntax=docker/dockerfile:1

FROM node:20
WORKDIR /app
COPY package*.json ./
ENV NODE_ENV=production
RUN npm ci && npm cache clean --force
COPY . .
CMD ["node", "app.js"]
```

Environment variables aren't configurable at build-time by default.
If you want to change the value of an `ENV` at build-time,
you can combine environment variables and build arguments:

```dockerfile
# syntax=docker/dockerfile:1

FROM node:20
ARG NODE_ENV=production
ENV NODE_ENV=$NODE_ENV
WORKDIR /app
COPY package*.json ./
RUN npm ci && npm cache clean --force
COPY . .
CMD ["node", "app.js"]
```

With this Dockerfile, you can use `--build-arg` to override the default value of `NODE_ENV`:

```console
$ docker build --build-arg NODE_ENV=development .
```

Note that, because the environment variables you set persist in containers,
using them can lead to unintended side-effects for the application's runtime.

For more information on how to use environment variables in builds, refer to:

- [`ENV` Dockerfile reference](../concepts/dockerfile.md#env)

## Scoping

Build arguments declared in the global scope of a Dockerfile
aren't automatically inherited into the build stages.
They're only accessible in the global scope.

```dockerfile
# syntax=docker/dockerfile:1

# The following build argument is declared in the global scope:
ARG NAME="joe"

FROM alpine
# The following instruction doesn't have access to the $NAME build argument
# because the argument was defined in the global scope, not for this stage.
RUN echo "hello ${NAME}!"
```

The `echo` command in this example evaluates to `hello !`
because the value of the `NAME` build argument is out of scope.
To inherit global build arguments into a stage, you must consume them:

```dockerfile
# syntax=docker/dockerfile:1

# Declare the build argument in the global scope
ARG NAME="joe"

FROM alpine
# Consume the build argument in the build stage
ARG NAME
RUN echo $NAME
```

Once a build argument is declared or consumed in a stage,
it's automatically inherited by child stages.

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine AS base
# Declare the build argument in the build stage
ARG NAME="joe"

# Create a new stage based on "base"
FROM base AS build
# The NAME build argument is available here
# since it's declared in a parent stage
RUN echo "hello $NAME!"
```

The following diagram further exemplifies how build argument
and environment variable inheritance works for multi-stage builds.

{{< figure src="../../images/build-variables.svg" class="invertible" >}}

## Pre-defined build arguments

This section describes pre-defined build arguments available to all builds by default.

### Multi-platform build arguments

Multi-platform build arguments describe the build and target platforms for the build.

The build platform is the operating system, architecture, and platform variant
of the host system where the builder (the BuildKit daemon) is running.

- `BUILDPLATFORM`
- `BUILDOS`
- `BUILDARCH`
- `BUILDVARIANT`

The target platform arguments hold the same values for the target platforms for the build,
specified using the `--platform` flag for the `docker build` command.

- `TARGETPLATFORM`
- `TARGETOS`
- `TARGETARCH`
- `TARGETVARIANT`

These arguments are useful for doing cross-compilation in multi-platform builds.
They're available in the global scope of the Dockerfile,
but they aren't automatically inherited by build stages.
To use them inside stage, you must declare them:

```dockerfile
# syntax=docker/dockerfile:1

# Pre-defined build arguments are available in the global scope
FROM --platform=$BUILDPLATFORM golang
# To inherit them to a stage, declare them with ARG
ARG TARGETOS
RUN GOOS=$TARGETOS go build -o ./exe .
```

For more information about multi-platform build arguments, refer to
[Multi-platform arguments](../concepts/dockerfile.md#automatic-platform-args-in-the-global-scope)

### Proxy arguments

Proxy build arguments let you specify proxies to use for your build.
You don't need to declare or reference these arguments in the Dockerfile.
Specifying a proxy with `--build-arg` is enough to make your build use the proxy.

Proxy arguments are automatically excluded from the build cache
and the output of `docker history` by default.
If you do reference the arguments in your Dockerfile,
the proxy configuration ends up in the build cache.

The builder respects the following proxy build arguments.
The variables are case insensitive.

- `HTTP_PROXY`
- `HTTPS_PROXY`
- `FTP_PROXY`
- `NO_PROXY`
- `ALL_PROXY`

To configure a proxy for your build:

```console
$ docker build --build-arg HTTP_PROXY=https://my-proxy.example.com .
```

For more information about proxy build arguments, refer to
[Proxy arguments](../concepts/dockerfile.md#predefined-args).

## Build tool configuration variables

The following environment variables enable, disable, or change the behavior of Buildx and BuildKit.
Note that these variables aren't used to configure the build container;
they aren't available inside the build and they have no relation to the `ENV` instruction.
They're used to configure the Buildx client, or the BuildKit daemon.

| Variable                                                                    | Type              | Description                                                      |
|-----------------------------------------------------------------------------|-------------------|------------------------------------------------------------------|
| [BUILDKIT_COLORS](#buildkit_colors)                                         | String            | Configure text color for the terminal output.                    |
| [BUILDKIT_HOST](#buildkit_host)                                             | String            | Specify host to use for remote builders.                         |
| [BUILDKIT_PROGRESS](#buildkit_progress)                                     | String            | Configure type of progress output.                               |
| [BUILDKIT_TTY_LOG_LINES](#buildkit_tty_log_lines)                           | String            | Number of log lines (for active steps in TTY mode).              |
| [BUILDX_BAKE_FILE](#buildx_bake_file)                                       | String            | Specify the build definition file(s) for `docker buildx bake`.   |
| [BUILDX_BAKE_FILE_SEPARATOR](#buildx_bake_file_separator)                   | String            | Specify the file-path separator for `BUILDX_BAKE_FILE`.          |
| [BUILDX_BAKE_GIT_AUTH_HEADER](#buildx_bake_git_auth_header)                 | String            | HTTP authentication scheme for remote Bake files.                |
| [BUILDX_BAKE_GIT_AUTH_TOKEN](#buildx_bake_git_auth_token)                   | String            | HTTP authentication token for remote Bake files.                 |
| [BUILDX_BAKE_GIT_SSH](#buildx_bake_git_ssh)                                 | String            | SSH authentication for remote Bake files.                        |
| [BUILDX_BUILDER](#buildx_builder)                                           | String            | Specify the builder instance to use.                             |
| [BUILDX_CONFIG](#buildx_config)                                             | String            | Specify location for configuration, state, and logs.             |
| [BUILDX_CPU_PROFILE](#buildx_cpu_profile)                                   | String            | Generate a `pprof` CPU profile at the specified location.        |
| [BUILDX_EXPERIMENTAL](#buildx_experimental)                                 | Boolean           | Turn on experimental features.                                   |
| [BUILDX_GIT_CHECK_DIRTY](#buildx_git_check_dirty)                           | Boolean           | Enable dirty Git checkout detection.                             |
| [BUILDX_GIT_INFO](#buildx_git_info)                                         | Boolean           | Remove Git information in provenance attestations.               |
| [BUILDX_GIT_LABELS](#buildx_git_labels)                                     | String \| Boolean | Add Git provenance labels to images.                             |
| [BUILDX_MEM_PROFILE](#buildx_mem_profile)                                   | String            | Generate a `pprof` memory profile at the specified location.     |
| [BUILDX_METADATA_PROVENANCE](#buildx_metadata_provenance)                   | String \| Boolean | Customize provenance information included in the metadata file.  |
| [BUILDX_METADATA_WARNINGS](#buildx_metadata_warnings)                       | String            | Include build warnings in the metadata file.                     |
| [BUILDX_NO_DEFAULT_ATTESTATIONS](#buildx_no_default_attestations)           | Boolean           | Turn off default provenance attestations.                        |
| [BUILDX_NO_DEFAULT_OCI_ARTIFACT](#buildx_no_default_oci_artifact)           | Boolean           | Turn off OCI artifact storage for attestations by default.       |
| [BUILDX_NO_DEFAULT_LOAD](#buildx_no_default_load)                           | Boolean           | Turn off loading images to image store by default.               |
| [EXPERIMENTAL_BUILDKIT_SOURCE_POLICY](#experimental_buildkit_source_policy) | String            | Specify a BuildKit source policy file.                           |

BuildKit also supports a few additional configuration parameters. Refer to
[BuildKit built-in build args](../concepts/dockerfile.md#buildkit-built-in-build-args).

You can express Boolean values for environment variables in different ways.
For example, `true`, `1`, and `T` all evaluate to true.
Evaluation is done using the `strconv.ParseBool` function in the Go standard library.
See the [reference documentation](https://pkg.go.dev/strconv#ParseBool) for details.

<!-- vale Docker.HeadingSentenceCase = NO -->

### BUILDKIT_COLORS

Changes the colors of the terminal output. Set `BUILDKIT_COLORS` to a CSV string
in the following format:

```console
$ export BUILDKIT_COLORS="run=123,20,245:error=yellow:cancel=blue:warning=white"
```

Color values can be any valid RGB hex code, or one of the
[BuildKit predefined colors](https://github.com/moby/buildkit/blob/master/util/progress/progressui/colors.go).

Setting `NO_COLOR` to anything turns off colorized output, as recommended by
[no-color.org](https://no-color.org/).

### BUILDKIT_HOST

{{< summary-bar feature_name="Buildkit host" >}}

You use the `BUILDKIT_HOST` to specify the address of a BuildKit daemon to use
as a remote builder. This is the same as specifying the address as a positional
argument to `docker buildx create`.

Usage:

```console
$ export BUILDKIT_HOST=tcp://localhost:1234
$ docker buildx create --name=remote --driver=remote
```

If you specify both the `BUILDKIT_HOST` environment variable and a positional
argument, the argument takes priority.

### BUILDKIT_PROGRESS

Sets the type of the BuildKit progress output. Valid values are:

- `auto` (default): automatically uses `tty` in interactive terminals, `plain` otherwise
- `plain`: displays build steps sequentially in simple text format
- `tty`: interactive output with formatted progress bars and build steps
- `quiet`: suppresses progress output, only shows errors and final image ID
- `none`: no progress output, only shows errors
- `rawjson`: outputs build progress as raw JSON (useful for parsing by other tools)

Usage:

```console
$ export BUILDKIT_PROGRESS=plain
```

### BUILDKIT_TTY_LOG_LINES

You can change how many log lines are visible for active steps in TTY mode by
setting `BUILDKIT_TTY_LOG_LINES` to a number (default to `6`).

```console
$ export BUILDKIT_TTY_LOG_LINES=8
```

### EXPERIMENTAL_BUILDKIT_SOURCE_POLICY

Lets you specify a
[BuildKit source policy](https://github.com/moby/buildkit/blob/master/docs/build-repro.md#reproducing-the-pinned-dependencies)
file for creating reproducible builds with pinned dependencies.

```console
$ export EXPERIMENTAL_BUILDKIT_SOURCE_POLICY=./policy.json
```

Example:

```json
{
  "rules": [
    {
      "action": "CONVERT",
      "selector": {
        "identifier": "docker-image://docker.io/library/alpine:latest"
      },
      "updates": {
        "identifier": "docker-image://docker.io/library/alpine:latest@sha256:4edbd2beb5f78b1014028f4fbb99f3237d9561100b6881aabbf5acce2c4f9454"
      }
    },
    {
      "action": "CONVERT",
      "selector": {
        "identifier": "https://raw.githubusercontent.com/moby/buildkit/v0.10.1/README.md"
      },
      "updates": {
        "attrs": {"http.checksum": "sha256:6e4b94fc270e708e1068be28bd3551dc6917a4fc5a61293d51bb36e6b75c4b53"}
      }
    },
    {
      "action": "DENY",
      "selector": {
        "identifier": "docker-image://docker.io/library/golang*"
      }
    }
  ]
}
```

### BUILDX_BAKE_FILE

{{< summary-bar feature_name="Buildx bake file" >}}

Specify one or more build definition files for `docker buildx bake`. 

This environment variable provides an alternative to the `-f` / `--file` command-line flag.

Multiple files can be specified by separating them with the system path separator (":" on Linux/macOS, ";" on Windows):

```console
export BUILDX_BAKE_FILE=file1.hcl:file2.hcl
```

Or with a custom separator defined by the [BUILDX_BAKE_FILE_SEPARATOR](#buildx_bake_file_separator) variable:

```console
export BUILDX_BAKE_FILE_SEPARATOR=@
export BUILDX_BAKE_FILE=file1.hcl@file2.hcl
```

If both `BUILDX_BAKE_FILE` and the `-f` flag are set, only the files provided via `-f` are used. 

If a listed file does not exist or is invalid, bake returns an error.

### BUILDX_BAKE_FILE_SEPARATOR

{{< summary-bar feature_name="Buildx bake file separator" >}}

Controls the separator used between file paths in the `BUILDX_BAKE_FILE` environment variable. 

This is useful if your file paths contain the default separator character or if you want to standardize separators across different platforms.

```console
export BUILDX_BAKE_PATH_SEPARATOR=@
export BUILDX_BAKE_FILE=file1.hcl@file2.hcl
```

### BUILDX_BAKE_GIT_AUTH_HEADER

{{< summary-bar feature_name="Buildx bake Git auth token" >}}

Sets the HTTP authentication scheme when using a remote Bake definition in a private Git repository.
This is equivalent to the [`GIT_AUTH_HEADER` secret](./secrets#http-authentication-scheme),
but facilitates the pre-flight authentication in Bake when loading the remote Bake file.
Supported values are `bearer` (default) and `basic`.

Usage:

```console
$ export BUILDX_BAKE_GIT_AUTH_HEADER=basic
```

### BUILDX_BAKE_GIT_AUTH_TOKEN

{{< summary-bar feature_name="Buildx bake Git auth token" >}}

Sets the HTTP authentication token when using a remote Bake definition in a private Git repository.
This is equivalent to the [`GIT_AUTH_TOKEN` secret](./secrets#git-authentication-for-remote-contexts),
but facilitates the pre-flight authentication in Bake when loading the remote Bake file.

Usage:

```console
$ export BUILDX_BAKE_GIT_AUTH_TOKEN=$(cat git-token.txt)
```

### BUILDX_BAKE_GIT_SSH

{{< summary-bar feature_name="Buildx bake Git SSH" >}}

Lets you specify a list of SSH agent socket filepaths to forward to Bake
for authenticating to a Git server when using a remote Bake definition in a private repository.
This is similar to SSH mounts for builds, but facilitates the pre-flight authentication in Bake when resolving the build definition.

Setting this environment is typically not necessary, because Bake will use the `SSH_AUTH_SOCK` agent socket by default.
You only need to specify this variable if you want to use a socket with a different filepath.
This variable can take multiple paths using a comma-separated string.

Usage:

```console
$ export BUILDX_BAKE_GIT_SSH=/run/foo/listener.sock,~/.creds/ssh.sock
```

### BUILDX_BUILDER

Overrides the configured builder instance. Same as the `docker buildx --builder`
CLI flag.

Usage:

```console
$ export BUILDX_BUILDER=my-builder
```

### BUILDX_CONFIG

You can use `BUILDX_CONFIG` to specify the directory to use for build
configuration, state, and logs. The lookup order for this directory is as
follows:

- `$BUILDX_CONFIG`
- `$DOCKER_CONFIG/buildx`
- `~/.docker/buildx` (default)

Usage:

```console
$ export BUILDX_CONFIG=/usr/local/etc
```

### BUILDX_CPU_PROFILE

{{< summary-bar feature_name="Buildx CPU profile" >}}

If specified, Buildx generates a `pprof` CPU profile at the specified location.

> [!NOTE]
> This property is only useful for when developing Buildx. The profiling data
> is not relevant for analyzing a build's performance.

Usage:

```console
$ export BUILDX_CPU_PROFILE=buildx_cpu.prof
```

### BUILDX_EXPERIMENTAL

Enables experimental build features.

Usage:

```console
$ export BUILDX_EXPERIMENTAL=1
```

### BUILDX_GIT_CHECK_DIRTY

{{< summary-bar feature_name="Buildx Git check dirty" >}}

When set to true, checks for dirty state in source control information for
[provenance attestations](../metadata/attestations/slsa-provenance.md).

Usage:

```console
$ export BUILDX_GIT_CHECK_DIRTY=1
```

### BUILDX_GIT_INFO

{{< summary-bar feature_name="Buildx Git info" >}}

When set to false, removes source control information from
[provenance attestations](../metadata/attestations/slsa-provenance.md).

Usage:

```console
$ export BUILDX_GIT_INFO=0
```

### BUILDX_GIT_LABELS

{{< summary-bar feature_name="Buildx Git labels" >}}

Adds provenance labels, based on Git information, to images that you build. The
labels are:

- `com.docker.image.source.entrypoint`: Location of the Dockerfile relative to
  the project root
- `org.opencontainers.image.revision`: Git commit revision
- `org.opencontainers.image.source`: SSH or HTTPS address of the repository

Example:

```json
  "Labels": {
    "com.docker.image.source.entrypoint": "Dockerfile",
    "org.opencontainers.image.revision": "5734329c6af43c2ae295010778cd308866b95d9b",
    "org.opencontainers.image.source": "git@github.com:foo/bar.git"
  }
```

Usage:

- Set `BUILDX_GIT_LABELS=1` to include the `entrypoint` and `revision` labels.
- Set `BUILDX_GIT_LABELS=full` to include all labels.

If the repository is in a dirty state, the `revision` gets a `-dirty` suffix.

### BUILDX_MEM_PROFILE

{{< summary-bar feature_name="Buildx mem profile" >}}

If specified, Buildx generates a `pprof` memory profile at the specified
location.

> [!NOTE]
> This property is only useful for when developing Buildx. The profiling data
> is not relevant for analyzing a build's performance.

Usage:

```console
$ export BUILDX_MEM_PROFILE=buildx_mem.prof
```

### BUILDX_METADATA_PROVENANCE

{{< summary-bar feature_name="Buildx metadata provenance" >}}

By default, Buildx includes minimal provenance information in the metadata file
through [`--metadata-file` flag](/reference/cli/docker/buildx/build/#metadata-file).
This environment variable allows you to customize the provenance information
included in the metadata file:
* `min` sets minimal provenance (default).
* `max` sets full provenance.
* `disabled`, `false` or `0` does not set any provenance.

### BUILDX_METADATA_WARNINGS

{{< summary-bar feature_name="Buildx metadata warnings" >}}

By default, Buildx does not include build warnings in the metadata file through
[`--metadata-file` flag](/reference/cli/docker/buildx/build/#metadata-file).
You can set this environment variable to `1` or `true` to include them.

### BUILDX_NO_DEFAULT_ATTESTATIONS

{{< summary-bar feature_name="Buildx no default" >}}

By default, BuildKit v0.11 and later adds
[provenance attestations](../metadata/attestations/slsa-provenance.md) to images you
build. Set `BUILDX_NO_DEFAULT_ATTESTATIONS=1` to disable the default provenance
attestations.

Usage:

```console
$ export BUILDX_NO_DEFAULT_ATTESTATIONS=1
```

### BUILDX_NO_DEFAULT_OCI_ARTIFACT

{{< summary-bar feature_name="Buildx no default OCI artifact" >}}

Starting with BuildKit v0.32.0, BuildKit stores attestations as OCI artifacts
when OCI media types are enabled. Set `BUILDX_NO_DEFAULT_OCI_ARTIFACT=1` to
make Buildx set `oci-artifact=false` when the build uses an exporter that
supports attestations and you haven't explicitly set the `oci-artifact`
exporter attribute.

Usage:

```console
$ export BUILDX_NO_DEFAULT_OCI_ARTIFACT=1
```

### BUILDX_NO_DEFAULT_LOAD

When you build an image using the `docker` driver, the image is automatically
loaded to the image store when the build finishes. Set `BUILDX_NO_DEFAULT_LOAD`
to disable automatic loading of images to the local container store.

Usage:

```console
$ export BUILDX_NO_DEFAULT_LOAD=1
```

<!-- vale Docker.HeadingSentenceCase = YES -->


---

# BuildKit

*Sección: Build*

[BuildKit](https://github.com/moby/buildkit) is the builder backend used by
Docker. BuildKit provides improved functionality and improves your builds'
performance over the legacy builder used in earlier versions of Docker. It also
introduces support for handling more complex scenarios:

- Detect and skip executing unused build stages
- Parallelize building independent build stages
- Incrementally transfer only the changed files in your
  [build context](../concepts/context.md) between builds
- Detect and skip transferring unused files in your
  [build context](../concepts/context.md)
- Use [Dockerfile frontend](frontend.md) implementations with many
  additional features
- Avoid side effects with rest of the API (intermediate images and containers)
- Prioritize your build cache for automatic pruning

The main areas BuildKit improves on the legacy builder are performance, storage
management, and extensibility. From the performance side, a significant update
is a fully concurrent build graph solver. It can run build steps in parallel when possible and optimize out
commands that don't have an impact on the final result.
The access to the local source files has also been optimized. By tracking
only the updates made to these
files between repeated build invocations, there is no need to wait for local
files to be read or uploaded before the work can begin.

## LLB

At the core of BuildKit is a
[Low-Level Build (LLB)](https://github.com/moby/buildkit#exploring-llb) definition format. LLB is an intermediate binary format
that allows developers to extend BuildKit. LLB defines a content-addressable
dependency graph that can be used to put together complex build
definitions. It also supports features not exposed in Dockerfiles, like direct
data mounting and nested invocation.

{{< figure src="../images/buildkit-dag.svg" class="invertible" >}}

Everything about execution and caching of your builds is defined in LLB. The
caching model is entirely rewritten compared to the legacy builder. Rather than
using heuristics to compare images, LLB directly tracks the checksums of build
graphs and content mounted to specific operations. This makes it much faster,
more precise, and portable. The build cache can even be exported to a registry,
where it can be pulled on-demand by subsequent invocations on any host.

LLB can be generated directly using a
[golang client package](https://pkg.go.dev/github.com/moby/buildkit/client/llb) that allows defining the relationships between your
build operations using Go language primitives. This gives you full power to run
anything you can imagine, but will probably not be how most people will define
their builds. Instead, most users would use a frontend component, or LLB nested
invocation, to run a prepared set of build steps.

## Frontend

A frontend is a component that takes a human-readable build format and converts
it to LLB so BuildKit can execute it. Frontends can be distributed as images,
and the user can target a specific version of a frontend that is guaranteed to
work for the features used by their definition.

For example, to build a [Dockerfile](../concepts/dockerfile.md) with
BuildKit, you would
[use an external Dockerfile frontend](frontend.md).

## Getting started

BuildKit is the default builder for Docker Desktop and Docker Engine users.
If you're building Windows containers, the legacy builder is used instead.

## BuildKit on Windows

> [!WARNING]
>
> BuildKit only fully supports building Linux containers. Windows container
> support is experimental.

BuildKit has experimental support for Windows containers (WCOW) as of version 0.13.
This section walks you through the steps for trying it out.
To share feedback, [open an issue in the repository](https://github.com/moby/buildkit/issues/new), especially `buildkitd.exe`.

### Known limitations

For information about open bugs and limitations related to BuildKit on Windows,
see [GitHub issues](https://github.com/moby/buildkit/issues?q=is%3Aissue%20state%3Aopen%20label%3Aarea%2Fwindows-wcow).

### Prerequisites

- Architecture: `amd64`, `arm64` (binaries available but not officially tested yet).
- Supported OS: Windows Server 2019, Windows Server 2022, Windows 11.
- Base images: `ServerCore:ltsc2019`, `ServerCore:ltsc2022`, `NanoServer:ltsc2022`.
  See the [compatibility map here](https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2019%2Cwindows-11#windows-server-host-os-compatibility).
- Docker Desktop version 4.29 or later

### Steps

> [!NOTE]
>
> The following commands require administrator (elevated) privileges in a PowerShell terminal.

1. Enable the **Hyper-V** and **Containers** Windows features.

   ```console
   > Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V, Containers -All
   ```

   If you see `RestartNeeded` as `True`, restart your machine and re-open a PowerShell terminal as an administrator.
   Otherwise, continue with the next step.

2. Switch to Windows containers in Docker Desktop.

   Select the Docker icon in the taskbar, and then **Switch to Windows containers...**.

3. Install containerd version 1.7.7 or later following the [setup instructions](https://github.com/containerd/containerd/blob/main/docs/getting-started.md#installing-containerd-on-windows).

4. Download and extract the latest BuildKit release.

   ```powershell
   $version = "v0.22.0" # specify the release version, v0.13+
   $arch = "amd64" # arm64 binary available too
   curl.exe -LO https://github.com/moby/buildkit/releases/download/$version/buildkit-$version.windows-$arch.tar.gz
   # there could be another `.\bin` directory from containerd instructions
   # you can move those
   mv bin bin2
   tar.exe xvf .\buildkit-$version.windows-$arch.tar.gz
   ## x bin/
   ## x bin/buildctl.exe
   ## x bin/buildkitd.exe
   ```

5. Install BuildKit binaries on `PATH`.

   ```powershell
   # after the binaries are extracted in the bin directory
   # move them to an appropriate path in your $Env:PATH directories or:
   Copy-Item -Path ".\bin" -Destination "$Env:ProgramFiles\buildkit" -Recurse -Force
   # add `buildkitd.exe` and `buildctl.exe` binaries in the $Env:PATH
   $Path = [Environment]::GetEnvironmentVariable("PATH", "Machine") + `
       [IO.Path]::PathSeparator + "$Env:ProgramFiles\buildkit"
   [Environment]::SetEnvironmentVariable( "Path", $Path, "Machine")
   $Env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + `
       [System.Environment]::GetEnvironmentVariable("Path","User")
   ```

6. Start the BuildKit daemon.

   ```console
   > buildkitd.exe
   ```

   > [!NOTE]
   > If you are running a _dockerd-managed_ `containerd` process, use that instead, by supplying the address:
   > `buildkitd.exe --containerd-worker-addr "npipe:////./pipe/docker-containerd"`

7. In another terminal with administrator privileges, create a remote builder that uses the local BuildKit daemon.

   > [!NOTE]
   >
   > This requires Docker Desktop version 4.29 or later.

   ```console
   > docker buildx create --name buildkit-exp --use --driver=remote npipe:////./pipe/buildkitd
   buildkit-exp
   ```

8. Verify the builder connection by running `docker buildx inspect`.

   ```console
   > docker buildx inspect
   ```

   The output should indicate that the builder platform is Windows,
   and that the endpoint of the builder is a named pipe.

   ```text
   Name:          buildkit-exp
    Driver:        remote
    Last Activity: 2024-04-15 17:51:58 +0000 UTC
    Nodes:
    Name:             buildkit-exp0
    Endpoint:         npipe:////./pipe/buildkitd
    Status:           running
    BuildKit version: v0.13.1
    Platforms:        windows/amd64
   ...
   ```

9. Create a Dockerfile and build a `hello-buildkit` image.

   ```console
   > mkdir sample_dockerfile
   > cd sample_dockerfile
   > Set-Content Dockerfile @"
   FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
   USER ContainerAdministrator
   COPY hello.txt C:/
   RUN echo "Goodbye!" >> hello.txt
   CMD ["cmd", "/C", "type C:\\hello.txt"]
   "@
   Set-Content hello.txt @"
   Hello from BuildKit!
   This message shows that your installation appears to be working correctly.
   "@
   ```

10. Build and push the image to a registry.

    ```console
    > docker buildx build --push -t <username>/hello-buildkit .
    ```

11. After pushing to the registry, run the image with `docker run`.

    ```console
    > docker run <username>/hello-buildkit
    ```


---

# Configure BuildKit

*Sección: Build*

If you create a `docker-container` or `kubernetes` builder with Buildx, you can
apply a custom [BuildKit configuration](toml-configuration.md) by passing the
[`--buildkitd-config` flag](/reference/cli/docker/buildx/create/#buildkitd-config)
to the `docker buildx create` command.

## Registry mirror

You can define a registry mirror to use for your builds. Doing so redirects
BuildKit to pull images from a different hostname. The following steps exemplify
defining a mirror for `docker.io` (Docker Hub) to `mirror.gcr.io`.

1. Create a TOML at `/etc/buildkitd.toml` with the following content:

   ```toml
   debug = true
   [registry."docker.io"]
     mirrors = ["mirror.gcr.io"]
   ```

   > [!NOTE]
   >
   > `debug = true` turns on debug requests in the BuildKit daemon, which logs a
   > message that shows when a mirror is being used.

2. Create a `docker-container` builder that uses this BuildKit configuration:

   ```console
   $ docker buildx create --use --bootstrap \
     --name mybuilder \
     --driver docker-container \
     --buildkitd-config /etc/buildkitd.toml
   ```

3. Build an image:

   ```bash
   docker buildx build --load . -f - <<EOF
   FROM alpine
   RUN echo "hello world"
   EOF
   ```

The BuildKit logs for this builder now shows that it uses the GCR mirror. You
can tell by the fact that the response messages include the `x-goog-*` HTTP
headers.

```console
$ docker logs buildx_buildkit_mybuilder0
```

```text
...
time="2022-02-06T17:47:48Z" level=debug msg="do request" request.header.accept="application/vnd.docker.container.image.v1+json, */*" request.header.user-agent=containerd/1.5.8+unknown request.method=GET spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg="fetch response received" response.header.accept-ranges=bytes response.header.age=1356 response.header.alt-svc="h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"" response.header.cache-control="public, max-age=3600" response.header.content-length=1469 response.header.content-type=application/octet-stream response.header.date="Sun, 06 Feb 2022 17:25:17 GMT" response.header.etag="\"774380abda8f4eae9a149e5d5d3efc83\"" response.header.expires="Sun, 06 Feb 2022 18:25:17 GMT" response.header.last-modified="Wed, 24 Nov 2021 21:07:57 GMT" response.header.server=UploadServer response.header.x-goog-generation=1637788077652182 response.header.x-goog-hash="crc32c=V3DSrg==" response.header.x-goog-hash.1="md5=d0OAq9qPTq6aFJ5dXT78gw==" response.header.x-goog-metageneration=1 response.header.x-goog-storage-class=STANDARD response.header.x-goog-stored-content-encoding=identity response.header.x-goog-stored-content-length=1469 response.header.x-guploader-uploadid=ADPycduqQipVAXc3tzXmTzKQ2gTT6CV736B2J628smtD1iDytEyiYCgvvdD8zz9BT1J1sASUq9pW_ctUyC4B-v2jvhIxnZTlKg response.status="200 OK" spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg="fetch response received" response.header.accept-ranges=bytes response.header.age=760 response.header.alt-svc="h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"" response.header.cache-control="public, max-age=3600" response.header.content-length=1471 response.header.content-type=application/octet-stream response.header.date="Sun, 06 Feb 2022 17:35:13 GMT" response.header.etag="\"35d688bd15327daafcdb4d4395e616a8\"" response.header.expires="Sun, 06 Feb 2022 18:35:13 GMT" response.header.last-modified="Wed, 24 Nov 2021 21:07:12 GMT" response.header.server=UploadServer response.header.x-goog-generation=1637788032100793 response.header.x-goog-hash="crc32c=aWgRjA==" response.header.x-goog-hash.1="md5=NdaIvRUyfar8201DleYWqA==" response.header.x-goog-metageneration=1 response.header.x-goog-storage-class=STANDARD response.header.x-goog-stored-content-encoding=identity response.header.x-goog-stored-content-length=1471 response.header.x-guploader-uploadid=ADPycdtR-gJYwC7yHquIkJWFFG8FovDySvtmRnZBqlO3yVDanBXh_VqKYt400yhuf0XbQ3ZMB9IZV2vlcyHezn_Pu3a1SMMtiw response.status="200 OK" spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg=fetch spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg=fetch spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg=fetch spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg=fetch spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg="do request" request.header.accept="application/vnd.docker.image.rootfs.diff.tar.gzip, */*" request.header.user-agent=containerd/1.5.8+unknown request.method=GET spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
time="2022-02-06T17:47:48Z" level=debug msg="fetch response received" response.header.accept-ranges=bytes response.header.age=1356 response.header.alt-svc="h3=\":443\"; ma=2592000,h3-29=\":443\"; ma=2592000,h3-Q050=\":443\"; ma=2592000,h3-Q046=\":443\"; ma=2592000,h3-Q043=\":443\"; ma=2592000,quic=\":443\"; ma=2592000; v=\"46,43\"" response.header.cache-control="public, max-age=3600" response.header.content-length=2818413 response.header.content-type=application/octet-stream response.header.date="Sun, 06 Feb 2022 17:25:17 GMT" response.header.etag="\"1d55e7be5a77c4a908ad11bc33ebea1c\"" response.header.expires="Sun, 06 Feb 2022 18:25:17 GMT" response.header.last-modified="Wed, 24 Nov 2021 21:07:06 GMT" response.header.server=UploadServer response.header.x-goog-generation=1637788026431708 response.header.x-goog-hash="crc32c=ZojF+g==" response.header.x-goog-hash.1="md5=HVXnvlp3xKkIrRG8M+vqHA==" response.header.x-goog-metageneration=1 response.header.x-goog-storage-class=STANDARD response.header.x-goog-stored-content-encoding=identity response.header.x-goog-stored-content-length=2818413 response.header.x-guploader-uploadid=ADPycdsebqxiTBJqZ0bv9zBigjFxgQydD2ESZSkKchpE0ILlN9Ibko3C5r4fJTJ4UR9ddp-UBd-2v_4eRpZ8Yo2llW_j4k8WhQ response.status="200 OK" spanID=9460e5b6e64cec91 traceID=b162d3040ddf86d6614e79c66a01a577
...
```

## Setting registry certificates

If you specify registry certificates in the BuildKit configuration, the daemon
copies the files into the container under `/etc/buildkit/certs`. The following
steps show adding a self-signed registry certificate to the BuildKit
configuration.

1. Add the following configuration to `/etc/buildkitd.toml`:

   ```toml
   # /etc/buildkitd.toml
   debug = true
   [registry."myregistry.com"]
     ca=["/etc/certs/myregistry.pem"]
     [[registry."myregistry.com".keypair]]
       key="/etc/certs/myregistry_key.pem"
       cert="/etc/certs/myregistry_cert.pem"
   ```

   This tells the builder to push images to the `myregistry.com` registry using
   the certificates in the specified location (`/etc/certs`).

2. Create a `docker-container` builder that uses this configuration:

   ```console
   $ docker buildx create --use --bootstrap \
     --name mybuilder \
     --driver docker-container \
     --buildkitd-config /etc/buildkitd.toml
   ```

3. Inspect the builder's configuration file (`/etc/buildkit/buildkitd.toml`), it
   shows that the certificate configuration is now configured in the builder.

   ```console
   $ docker exec -it buildx_buildkit_mybuilder0 cat /etc/buildkit/buildkitd.toml
   ```

   ```toml
   debug = true

   [registry]

     [registry."myregistry.com"]
       ca = ["/etc/buildkit/certs/myregistry.com/myregistry.pem"]

       [[registry."myregistry.com".keypair]]
         cert = "/etc/buildkit/certs/myregistry.com/myregistry_cert.pem"
         key = "/etc/buildkit/certs/myregistry.com/myregistry_key.pem"
   ```

4. Verify that the certificates are inside the container:

   ```console
   $ docker exec -it buildx_buildkit_mybuilder0 ls /etc/buildkit/certs/myregistry.com/
   myregistry.pem    myregistry_cert.pem   myregistry_key.pem
   ```

Now you can push to the registry using this builder, and it will authenticate
using the certificates:

```console
$ docker buildx build --push --tag myregistry.com/myimage:latest .
```

## CNI networking

CNI networking for builders can be useful for dealing with network port
contention during concurrent builds.

### Bridge networking

The BuildKit image ships with a built-in bridge network provider that uses a
minimal set of bundled CNI plugins, so you don't need to build a custom image
or supply your own CNI configuration. To use it, set the worker network mode to
`bridge` when you create the builder:

```console
$ docker buildx create --use --bootstrap \
  --name mybuilder \
  --driver docker-container \
  --buildkitd-flags "--oci-worker-net=bridge"
```

BuildKit creates a `buildkit0` bridge with a default subnet of `10.10.0.0/16`,
and cleans up the bridge automatically when the daemon shuts down.

### Custom CNI configuration

For more control over networking, build a custom BuildKit image with your own
CNI configuration and plugins.

The following Dockerfile example shows a custom BuildKit image with CNI support.
It uses the [CNI config for integration tests](https://github.com/moby/buildkit/blob/master//hack/fixtures/cni.json)
in BuildKit as an example. Feel free to include your own CNI configuration.

```dockerfile
# syntax=docker/dockerfile:1

ARG BUILDKIT_VERSION=v{{% param "buildkit_version" %}}
ARG CNI_VERSION=v1.0.1

FROM --platform=$BUILDPLATFORM alpine AS cni-plugins
RUN apk add --no-cache curl
ARG CNI_VERSION
ARG TARGETOS
ARG TARGETARCH
WORKDIR /opt/cni/bin
RUN curl -Ls https://github.com/containernetworking/plugins/releases/download/$CNI_VERSION/cni-plugins-$TARGETOS-$TARGETARCH-$CNI_VERSION.tgz | tar xzv

FROM moby/buildkit:${BUILDKIT_VERSION}
ARG BUILDKIT_VERSION
RUN apk add --no-cache iptables
COPY --from=cni-plugins /opt/cni/bin /opt/cni/bin
ADD https://raw.githubusercontent.com/moby/buildkit/${BUILDKIT_VERSION}/hack/fixtures/cni.json /etc/buildkit/cni.json
```

Now you can build this image, and create a builder instance from it using
[the `--driver-opt image` option](/reference/cli/docker/buildx/create/#driver-opt):

```console
$ docker buildx build --tag buildkit-cni:local --load .
$ docker buildx create --use --bootstrap \
  --name mybuilder \
  --driver docker-container \
  --driver-opt "image=buildkit-cni:local" \
  --buildkitd-flags "--oci-worker-net=cni"
```

## Resource limiting

### Max parallelism

You can limit the parallelism of the BuildKit solver, which is particularly useful
for low-powered machines, using a [BuildKit configuration](toml-configuration.md)
while creating a builder with the [`--buildkitd-config` flag](/reference/cli/docker/buildx/create/#buildkitd-config).

```toml
# /etc/buildkitd.toml
[worker.oci]
  max-parallelism = 4
```

Now you can [create a `docker-container` builder](../builders/drivers/docker-container.md)
that will use this BuildKit configuration to limit parallelism.

```console
$ docker buildx create --use \
  --name mybuilder \
  --driver docker-container \
  --buildkitd-config /etc/buildkitd.toml
```

### TCP connection limit

TCP connections are limited to 4 simultaneous connections per registry for
pulling and pushing images, plus one additional connection dedicated to metadata
requests. This connection limit prevents your build from getting stuck while
pulling images. The dedicated metadata connection helps reduce the overall build
time.

More information: [moby/buildkit#2259](https://github.com/moby/buildkit/pull/2259)


---

# Dockerfile release notes

*Sección: Build*




---

# Custom Dockerfile syntax

*Sección: Build*

## Dockerfile frontend

BuildKit supports loading frontends dynamically from container images. To use
an external Dockerfile frontend, the first line of your [Dockerfile](../concepts/dockerfile.md)
needs to set the [`syntax` directive](../concepts/dockerfile.md#syntax)
pointing to the specific image you want to use:

```dockerfile
# syntax=[remote image reference]
```

For example:

```dockerfile
# syntax=docker/dockerfile:1
# syntax=docker.io/docker/dockerfile:1
# syntax=example.com/user/repo:tag@sha256:abcdef...
```

You can also use the predefined `BUILDKIT_SYNTAX` build argument to set the
frontend image reference on the command line:

```console
$ docker build --build-arg BUILDKIT_SYNTAX=docker/dockerfile:1 .
```

This defines the location of the Dockerfile syntax that is used to build the
Dockerfile. The BuildKit backend allows seamlessly using external
implementations that are distributed as Docker images and execute inside a
container sandbox environment.

Custom Dockerfile implementations allow you to:

- Automatically get bug fixes without updating the Docker daemon
- Make sure all users are using the same implementation to build your Dockerfile
- Use the latest features without updating the Docker daemon
- Try out new features or third-party features before they are integrated in the Docker daemon
- Use [alternative build definitions, or create your own](https://github.com/moby/buildkit#exploring-llb)
- Build your own Dockerfile frontend with custom features

> [!NOTE]
>
> BuildKit ships with a built-in Dockerfile frontend, but it's recommended
> to use an external image to make sure that all users use the same version on
> the builder and to pick up bug fixes automatically without waiting for a new
> version of BuildKit or Docker Engine.

## Official releases

Docker distributes official versions of the images that can be used for building
Dockerfiles under `docker/dockerfile` repository on Docker Hub. There are two
channels where new images are released: `stable` and `labs`.

### Stable channel

The `stable` channel follows [semantic versioning](https://semver.org).
For example:

- `docker/dockerfile:1` - kept updated with the latest `1.x.x` minor _and_ patch
  release.
- `docker/dockerfile:1.2` - kept updated with the latest `1.2.x` patch release,
  and stops receiving updates once version `1.3.0` is released.
- `docker/dockerfile:1.2.1` - immutable: never updated.

We recommend using `docker/dockerfile:1`, which always points to the latest
stable release of the version 1 syntax, and receives both "minor" and "patch"
updates for the version 1 release cycle. BuildKit automatically checks for
updates of the syntax when performing a build, making sure you are using the
most current version.

If a specific version is used, such as `1.2` or `1.2.1`, the Dockerfile needs
to be updated manually to continue receiving bugfixes and new features. Old
versions of the Dockerfile remain compatible with the new versions of the
builder.

### Labs channel

The `labs` channel provides early access to Dockerfile features that are not yet
available in the `stable` channel. `labs` images are released at the same time
as stable releases, and follow the same version pattern, but use the `-labs`
suffix, for example:

- `docker/dockerfile:labs` - latest release on `labs` channel.
- `docker/dockerfile:1-labs` - same as `dockerfile:1`, with experimental
  features enabled.
- `docker/dockerfile:1.2-labs` - same as `dockerfile:1.2`, with experimental
  features enabled.
- `docker/dockerfile:1.2.1-labs` - immutable: never updated. Same as
  `dockerfile:1.2.1`, with experimental features enabled.

Choose a channel that best fits your needs. If you want to benefit from
new features, use the `labs` channel. Images in the `labs` channel contain
all the features in the `stable` channel, plus early access features.
Stable features in the `labs` channel follow [semantic versioning](https://semver.org),
but early access features don't, and newer releases may not be backwards
compatible. Pin the version to avoid having to deal with breaking changes.

## Other resources

For documentation on `labs` features, master builds, and nightly feature
releases, refer to the description in [the BuildKit source repository on GitHub](https://github.com/moby/buildkit/blob/master/README.md).
For a full list of available images, visit the [`docker/dockerfile` repository on Docker Hub](https://hub.docker.com/r/docker/dockerfile),
and the [`docker/dockerfile-upstream` repository on Docker Hub](https://hub.docker.com/r/docker/dockerfile-upstream)
for development builds.


---

# Docker build cache

*Sección: Build*

When you build the same Docker image multiple times, knowing how to optimize
the build cache is a great tool for making sure the builds run fast.

## How the build cache works

Understanding Docker's build cache helps you write better Dockerfiles that
result in faster builds.

The following example shows a small Dockerfile for a program written in C.

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:latest

RUN apt-get update && apt-get install -y build-essentials
COPY main.c Makefile /src/
WORKDIR /src/
RUN make build
```

Each instruction in this Dockerfile translates to a layer in your final image.
You can think of image layers as a stack, with each layer adding more content
on top of the layers that came before it:

![Image layer diagram](../images/cache-stack.png)

Whenever a layer changes, that layer will need to be re-built. For example,
suppose you make a change to your program in the `main.c` file. After this
change, the `COPY` command will have to run again in order for those changes to
appear in the image. In other words, Docker will invalidate the cache for this
layer.

If a layer changes, all other layers that come after it are also affected. When
the layer with the `COPY` command gets invalidated, all layers that follow will
need to run again, too:

![Image layer diagram, showing cache invalidation](../images/cache-stack-invalidated.png)

And that's the Docker build cache in a nutshell. Once a layer changes, then all
downstream layers need to be rebuilt as well. Even if they wouldn't build
anything differently, they still need to re-run.

## Other resources

For more information on using cache to do efficient builds, see:

- [Cache invalidation](invalidation.md)
- [Optimize build cache](../../build-cloud/optimization.md)
- [Garbage collection](garbage-collection.md)
- [Cache storage backends](backends/index.md)


---

# Cache storage backends

*Sección: Build*

To ensure fast builds, BuildKit automatically caches the build result in its own
internal cache. Additionally, BuildKit also supports exporting build cache to an
external location, making it possible to import in future builds.

An external cache becomes almost essential in CI/CD build environments. Such
environments usually have little-to-no persistence between runs, but it's still
important to keep the runtime of image builds as low as possible.

The default `docker` driver supports the `inline`, `local`, `registry`, and
`gha` cache backends, but only if you have enabled the [containerd image store](../../../desktop/features/containerd.md).
Other cache backends require you to select a different [driver](../../builders/drivers/index.md).

> [!WARNING]
>
> If you use secrets or credentials inside your build process, ensure you
> manipulate them using the dedicated
> [`--secret` option](/reference/cli/docker/buildx/build/#secret).
> Manually managing secrets using `COPY` or `ARG` could result in leaked
> credentials.

## Backends

Buildx supports the following cache storage backends:

- `inline`: embeds the build cache into the image.

  The inline cache gets pushed to the same location as the main output result.
  This only works with the [`image` exporter](../../exporters/image-registry.md).

- `registry`: embeds the build cache into a separate image, and pushes to a
  dedicated location separate from the main output.

- `local`: writes the build cache to a local directory on the filesystem.

- `gha`: uploads the build cache to
  [GitHub Actions cache](https://docs.github.com/en/rest/actions/cache) (beta).

- `s3`: uploads the build cache to an
  [AWS S3 bucket](https://aws.amazon.com/s3/) (unreleased).

- `azblob`: uploads the build cache to
  [Azure Blob Storage](https://azure.microsoft.com/en-us/services/storage/blobs/)
  (unreleased).

## Command syntax

To use any of the cache backends, you first need to specify it on build with the
[`--cache-to` option](/reference/cli/docker/buildx/build/#cache-to)
to export the cache to your storage backend of choice. Then, use the
[`--cache-from` option](/reference/cli/docker/buildx/build/#cache-from)
to import the cache from the storage backend into the current build. Unlike the
local BuildKit cache (which is always enabled), all of the cache storage
backends must be explicitly exported to, and explicitly imported from.

Example `buildx` command using the `registry` backend, using import and export
cache:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>[,parameters...] \
  --cache-from type=registry,ref=<registry>/<cache-image>[,parameters...] .
```

> [!WARNING]
>
> As a general rule, each cache writes to some location. No location can be
> written to twice, without overwriting the previously cached data. If you want
> to maintain multiple scoped caches (for example, a cache per Git branch), then
> ensure that you use different locations for exported cache.

## Multiple caches

BuildKit supports multiple cache exporters, allowing you to push cache to more 
than one destination. You can also import from as many remote caches as you'd 
like. For example, a common pattern is to use the cache of both the current 
branch and the main branch. The following example shows importing cache from 
multiple locations using the registry cache backend:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>:<branch> \
  --cache-from type=registry,ref=<registry>/<cache-image>:<branch> \
  --cache-from type=registry,ref=<registry>/<cache-image>:main .
```

## Configuration options

This section describes some configuration options available when generating
cache exports. The options described here are common for at least two or more
backend types. Additionally, the different backend types support specific
parameters as well. See the detailed page about each backend type for more
information about which configuration parameters apply.

The common parameters described here are:

- [Cache mode](#cache-mode)
- [Cache compression](#cache-compression)
- [OCI media type](#oci-media-types)

### Cache mode

When generating a cache output, the `--cache-to` argument accepts a `mode`
option for defining which layers to include in the exported cache. This is
supported by all cache backends except for the `inline` cache.

Mode can be set to either of two options: `mode=min` or `mode=max`. For example,
to build the cache with `mode=max` with the registry backend:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>,mode=max \
  --cache-from type=registry,ref=<registry>/<cache-image> .
```

This option is only set when exporting a cache, using `--cache-to`. When
importing a cache (`--cache-from`) the relevant parameters are automatically
detected.

In `min` cache mode (the default), only layers that are exported into the
resulting image are cached, while in `max` cache mode, all layers are cached,
even those of intermediate steps.

While `min` cache is typically smaller (which speeds up import/export times, and
reduces storage costs), `max` cache is more likely to get more cache hits.
Depending on the complexity and location of your build, you should experiment
with both parameters to find the results that work best for you.

### Cache compression

The cache compression options are the same as the
[exporter compression options](../../exporters/index.md#compression). This is
supported by the `local` and `registry` cache backends.

For example, to compress the `registry` cache with `zstd` compression:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>,compression=zstd \
  --cache-from type=registry,ref=<registry>/<cache-image> .
```

### OCI media types

The cache OCI options are the same as the
[exporter OCI options](../../exporters/index.md#oci-media-types). These are
supported by the `local` and `registry` cache backends.

For example, to export OCI media type cache, use the `oci-mediatypes` property:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>,oci-mediatypes=true \
  --cache-from type=registry,ref=<registry>/<cache-image> .
```

This property is only meaningful with the `--cache-to` flag. When fetching
cache, BuildKit will auto-detect the correct media types to use.

By default, the OCI media type generates an image index for the cache image.
Some OCI registries, such as Amazon ECR, don't support the image index media
type: `application/vnd.oci.image.index.v1+json`. If you export cache images to
ECR, or any other registry that doesn't support image indices, set the
`image-manifest` parameter to `true` to generate a single image manifest
instead of an image index for the cache image:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>,oci-mediatypes=true,image-manifest=true \
  --cache-from type=registry,ref=<registry>/<cache-image> .
```

> [!NOTE]
> Since BuildKit v0.21, `image-manifest` is enabled by default.


---

# Azure Blob Storage cache

*Sección: Build*

{{< summary-bar feature_name="Azure blob" >}}

The `azblob` cache store uploads your resulting build cache to
[Azure's blob storage service](https://azure.microsoft.com/en-us/services/storage/blobs/).

This cache storage backend is not supported with the default `docker` driver.
To use this feature, create a new builder using a different driver. See
[Build drivers](../../builders/drivers/index.md) for more information.

## Synopsis

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=azblob,name=<cache-image>[,parameters...] \
  --cache-from type=azblob,name=<cache-image>[,parameters...] .
```

The following table describes the available CSV parameters that you can pass to
`--cache-to` and `--cache-from`.

| Name                | Option                  | Type        | Default | Description                                        |
| ------------------- | ----------------------- | ----------- | ------- | -------------------------------------------------- |
| `name`              | `cache-to`,`cache-from` | String      |         | Required. The name of the cache image.             |
| `account_url`       | `cache-to`,`cache-from` | String      |         | Base URL of the storage account.                   |
| `secret_access_key` | `cache-to`,`cache-from` | String      |         | Blob storage account key, see [authentication][1]. |
| `mode`              | `cache-to`              | `min`,`max` | `min`   | Cache layers to export, see [cache mode][2].       |
| `ignore-error`      | `cache-to`              | Boolean     | `false` | Ignore errors caused by failed cache exports.      |

[1]: #authentication
[2]: index.md#cache-mode

## Authentication

The `secret_access_key`, if left unspecified, is read from environment variables
on the BuildKit server following the scheme for the
[Azure Go SDK](https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication).
The environment variables are read from the server, not the Buildx client.

## Further reading

For an introduction to caching see [Docker build cache](../index.md).

For more information on the `azblob` cache backend, see the
[BuildKit README](https://github.com/moby/buildkit#azure-blob-storage-cache-experimental).


---

# GitHub Actions cache

*Sección: Build*

{{< summary-bar feature_name="GitHub Actions cache" >}}

The GitHub Actions cache utilizes the
[GitHub-provided Action's cache](https://github.com/actions/cache) or other
cache services supporting the GitHub Actions cache protocol. This is the
recommended cache to use inside your GitHub Actions workflows, as long as your
use case falls within the
[size and usage limits set by GitHub](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy).

This cache storage backend is not supported with the default `docker` driver.
To use this feature, create a new builder using a different driver. See
[Build drivers](../../builders/drivers/index.md) for more information.

## Synopsis

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=gha[,parameters...] \
  --cache-from type=gha[,parameters...] .
```

The following table describes the available CSV parameters that you can pass to
`--cache-to` and `--cache-from`.

| Name           | Option                  | Type        | Default                                        | Description                                                          |
|----------------|-------------------------|-------------|------------------------------------------------|----------------------------------------------------------------------|
| `url`          | `cache-to`,`cache-from` | String      | `$ACTIONS_CACHE_URL` or `$ACTIONS_RESULTS_URL` | Cache server URL, see [authentication][1]. Ignored when `version=2`. |
| `url_v2`       | `cache-to`,`cache-from` | String      | `$ACTIONS_RESULTS_URL`                         | Cache v2 server URL, see [authentication][1].                        |
| `token`        | `cache-to`,`cache-from` | String      | `$ACTIONS_RUNTIME_TOKEN`                       | Access token, see [authentication][1].                               |
| `scope`        | `cache-to`,`cache-from` | String      | `buildkit`                                     | Which scope cache object belongs to, see [scope][2]                  |
| `mode`         | `cache-to`              | `min`,`max` | `min`                                          | Cache layers to export, see [cache mode][3].                         |
| `ignore-error` | `cache-to`              | Boolean     | `false`                                        | Ignore errors caused by failed cache exports.                        |
| `timeout`      | `cache-to`,`cache-from` | String      | `10m`                                          | Max duration for importing or exporting cache before it's timed out. |
| `repository`   | `cache-to`              | String      |                                                | GitHub repository used for cache storage.                            |
| `ghtoken`      | `cache-to`              | String      |                                                | GitHub token required for accessing the GitHub API.                  |
| `version`      | `cache-to`,`cache-from` | String      | `1` unless `$ACTIONS_CACHE_SERVICE_V2` is set, then `2` | Selects GitHub Actions cache version, see [version][4]      |

[1]: #authentication
[2]: #scope
[3]: index.md#cache-mode
[4]: #version

## Authentication

If the `url`, `url_v2` or `token` parameters are left unspecified, the `gha`
cache backend will fall back to using environment variables. If you invoke the
`docker buildx` command manually from an inline step, then the variables must
be manually exposed. Consider using the
[`crazy-max/ghaction-github-runtime`](https://github.com/crazy-max/ghaction-github-runtime),
GitHub Action as a helper for exposing the variables.

## Scope

Scope is a key used to identify the cache object. By default, it is set to
`buildkit`. If you build multiple images, each build will overwrite the cache
of the previous, leaving only the final cache.

To preserve the cache for multiple builds, you can specify this scope attribute
with a specific name. In the following example, the cache is set to the image
name, to ensure each image gets its own cache:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=gha,url=...,token=...,scope=image \
  --cache-from type=gha,url=...,token=...,scope=image .
$ docker buildx build --push -t <registry>/<image2> \
  --cache-to type=gha,url=...,token=...,scope=image2 \
  --cache-from type=gha,url=...,token=...,scope=image2 .
```

GitHub's [cache access restrictions](https://docs.github.com/en/actions/advanced-guides/caching-dependencies-to-speed-up-workflows#restrictions-for-accessing-a-cache),
still apply. Only the cache for the current branch, the base branch and the
default branch is accessible by a workflow.

Cache writes also depend on the workflow's cache access. Some events receive
read-only access in the default-branch context. See
[Cache write restrictions](../../ci/github-actions/cache.md#cache-write-restrictions)
for affected triggers and how to configure cache imports and exports.

## Version

If you don’t set `version` explicitly, the default is v1. However, if the environment variable `$ACTIONS_CACHE_SERVICE_V2` is set to a value interpreted as `true` ( `1`, `true`, `yes`), then v2 is used automatically.

Only one URL is relevant at a time:

 - With v1, use `url` (defaults to `$ACTIONS_CACHE_URL`).
 - With v2, use `url_v2` (defaults to `$ACTIONS_RESULTS_URL`).

### Using `docker/build-push-action`

When using the
[`docker/build-push-action`](https://github.com/docker/build-push-action), the
`url` and `token` parameters are automatically populated. No need to manually
specify them, or include any additional workarounds.

For example:

```yaml
- name: Build and push
  uses: docker/build-push-action@{{% param "build_push_action_version" %}}
  with:
    context: .
    push: true
    tags: "<registry>/<image>:latest"
    cache-from: type=gha
    cache-to: type=gha,mode=max
```

## Avoid GitHub Actions cache API throttling

GitHub's [usage limits and eviction policy](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy)
causes stale cache entries to be removed after a certain period of time. By
default, the `gha` cache backend uses the GitHub Actions cache API to check the
status of cache entries.

The GitHub Actions cache API is subject to rate limiting if you make too many
requests in a short period of time, which may happen as a result of cache
lookups during a build using the `gha` cache backend.

```text
#31 exporting to GitHub Actions Cache
#31 preparing build cache for export
#31 preparing build cache for export 600.3s done
#31 ERROR: maximum timeout reached
------
 > exporting to GitHub Actions Cache:
------
ERROR: failed to solve: maximum timeout reached
make: *** [Makefile:35: release] Error 1
Error: Process completed with exit code 2.
```

To mitigate this issue, you can supply a GitHub token to BuildKit. This lets
BuildKit utilize the standard GitHub API for checking cache keys, thereby
reducing the number of requests made to the cache API.

To provide a GitHub token, you can use the `ghtoken` parameter, and a
`repository` parameter to specify the repository to use for cache storage. The
`ghtoken` parameter is a GitHub token with the `repo` scope, which is required
to access the GitHub Actions cache API.

The `ghtoken` parameter is automatically set to the value of
`secrets.GITHUB_TOKEN` when you build with the `docker/build-push-action`
action. You can also set the `ghtoken` parameter manually using the
`github-token` input, as shown in the following example:

```yaml
- name: Build and push
  uses: docker/build-push-action@{{% param "build_push_action_version" %}}
  with:
    context: .
    push: true
    tags: "<registry>/<image>:latest"
    cache-from: type=gha
    cache-to: type=gha,mode=max
    github-token: ${{ secrets.MY_CUSTOM_TOKEN }}
```

## Further reading

For an introduction to caching see [Docker build cache](../index.md).

For more information on the `gha` cache backend, see the
[BuildKit README](https://github.com/moby/buildkit#github-actions-cache-experimental).

For more information about using GitHub Actions with Docker, see
[Introduction to GitHub Actions](../../ci/github-actions/index.md)


---

# Inline cache

*Sección: Build*

The `inline` cache storage backend is the simplest way to get an external cache
and is easy to get started using if you're already building and pushing an
image.

The downside of inline cache is that it doesn't scale with multi-stage builds
as well as the other drivers do. It also doesn't offer separation between your
output artifacts and your cache output. This means that if you're using a
particularly complex build flow, or not exporting your images directly to a
registry, then you may want to consider the [registry](registry.md) cache.

## Synopsis

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=inline \
  --cache-from type=registry,ref=<registry>/<image> .
```

No additional parameters are supported for the `inline` cache.

To export cache using `inline` storage, pass `type=inline` to the `--cache-to`
option:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=inline .
```

Alternatively, you can also export inline cache by setting the build argument
`BUILDKIT_INLINE_CACHE=1`, instead of using the `--cache-to` flag:

```console
$ docker buildx build --push -t <registry>/<image> \
  --build-arg BUILDKIT_INLINE_CACHE=1 .
```

To import the resulting cache on a future build, pass `type=registry` to
`--cache-from` which lets you extract the cache from inside a Docker image in
the specified registry:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-from type=registry,ref=<registry>/<image> .
```

## Further reading

For an introduction to caching see [Docker build cache](../index.md).

For more information on the `inline` cache backend, see the
[BuildKit README](https://github.com/moby/buildkit#inline-push-image-and-cache-together).


---

# Local cache

*Sección: Build*

The `local` cache store is a simple cache option that stores your cache as files
in a directory on your filesystem, using an
[OCI image layout](https://github.com/opencontainers/image-spec/blob/main/image-layout.md)
for the underlying directory structure. Local cache is a good choice if you're
just testing, or if you want the flexibility to self-manage a shared storage
solution.

## Synopsis

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=local,dest=path/to/local/dir[,parameters...] \
  --cache-from type=local,src=path/to/local/dir .
```

The following table describes the available CSV parameters that you can pass to
`--cache-to` and `--cache-from`.

| Name                | Option       | Type                    | Default | Description                                                                                                                     |
|---------------------|--------------|-------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------|
| `src`               | `cache-from` | String                  |         | Path of the local directory where cache gets imported from.                                                                     |
| `digest`            | `cache-from` | String                  |         | Digest of manifest to import, see [cache versioning][4].                                                                        |
| `tag`               | `cache-to`,`cache-from` | String                  | `latest` | Tag of the cache manifest, see [cache versioning][4].                                                                          |
| `dest`              | `cache-to`   | String                  |         | Path of the local directory where cache gets exported to.                                                                       |
| `mode`              | `cache-to`   | `min`,`max`             | `min`   | Cache layers to export, see [cache mode][1].                                                                                    |
| `oci-mediatypes`    | `cache-to`   | `true`,`false`          | `true`  | Use OCI media types in exported manifests, see [OCI media types][2].                                                            |
| `image-manifest`    | `cache-to`   | `true`,`false`          | `true`  | When using OCI media types, generate an image manifest instead of an image index for the cache image, see [OCI media types][2]. |
| `compression`       | `cache-to`   | `gzip`,`estargz`,`zstd` | `gzip`  | Compression type, see [cache compression][3].                                                                                   |
| `compression-level` | `cache-to`   | `0..22`                 |         | Compression level, see [cache compression][3].                                                                                  |
| `force-compression` | `cache-to`   | `true`,`false`          | `false` | Forcibly apply compression, see [cache compression][3].                                                                         |
| `ignore-error`      | `cache-to`   | Boolean                 | `false` | Ignore errors caused by failed cache exports.                                                                                   |
| `reset`             | `cache-to`   | `true`,`false`          | `false` | Delete blobs that no tag references, see [cache versioning][4].                                                                 |

[1]: index.md#cache-mode
[2]: index.md#oci-media-types
[3]: index.md#cache-compression
[4]: #cache-versioning

If the `src` cache doesn't exist, then the cache import step will fail, but the
build continues.

## Cache versioning

A local cache directory uses an OCI image layout. Its `index.json` file
associates tags with cache manifests, while the `blobs` directory stores the
manifest and cache data.

By default, BuildKit exports and imports the cache tagged `latest`. Use
different tags to keep multiple caches in the same directory:

```console
$ docker buildx build --cache-to type=local,dest=path/to/local/dir,tag=v1 .
$ docker buildx build --cache-to type=local,dest=path/to/local/dir,tag=v2 .
```

Exporting another cache with the same tag updates that tag to reference the new
manifest. Manifests referenced by other tags remain unchanged.

Import a cache by specifying its tag:

```console
$ docker buildx build --cache-from type=local,src=path/to/local/dir,tag=v1 .
```

A digest identifies an exact cache manifest. BuildKit reports the digest of
each exported manifest in the build output. Use `digest` instead of `tag` when
you need a specific manifest:

```console
$ docker buildx build \
  --cache-from type=local,src=path/to/local/dir,digest=sha256:<DIGEST> .
```

If you specify both `digest` and `tag`, BuildKit uses `digest`.

By default, updating a tag doesn't delete the blobs used by its previous
manifest. The previous manifest remains available by digest, so the local cache
directory grows over time.

Buildx version 0.35.0 and later supports `reset=true` on export, which deletes
blobs that no tag references:

```console
$ docker buildx build --cache-to type=local,dest=path/to/local/dir,reset=true .
```

Blobs that other tags reference are kept. Manifests that no tag references are
deleted, so you can no longer import them by digest.

## Further reading

For an introduction to caching see [Docker build cache](../index.md).

For more information on the `local` cache backend, see the
[BuildKit README](https://github.com/moby/buildkit#local-directory-1).


---

# Registry cache

*Sección: Build*

The `registry` cache storage can be thought of as an extension to the `inline`
cache. Unlike the `inline` cache, the `registry` cache is entirely separate from
the image, which allows for more flexible usage - `registry`-backed cache can do
everything that the inline cache can do, and more:

- Allows for separating the cache and resulting image artifacts so that you can
  distribute your final image without the cache inside.
- It can efficiently cache multi-stage builds in `max` mode, instead of only the
  final stage.
- It works with other exporters for more flexibility, instead of only the
  `image` exporter.

This cache storage backend works with the default `docker` driver only when the
[containerd image store](../../../desktop/features/containerd.md) is enabled. If
the containerd image store isn't enabled, use a different driver. See
[Build drivers](../../builders/drivers/index.md) for more information.

## Synopsis

Unlike the simpler `inline` cache, the `registry` cache supports several
configuration parameters:

```console
$ docker buildx build --push -t <registry>/<image> \
  --cache-to type=registry,ref=<registry>/<cache-image>[,parameters...] \
  --cache-from type=registry,ref=<registry>/<cache-image> .
```

The following table describes the available CSV parameters that you can pass to
`--cache-to` and `--cache-from`.

| Name                | Option                  | Type                    | Default | Description                                                                                                                     |
|---------------------|-------------------------|-------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------|
| `ref`               | `cache-to`,`cache-from` | String                  |         | Full name of the cache image to import.                                                                                         |
| `mode`              | `cache-to`              | `min`,`max`             | `min`   | Cache layers to export, see [cache mode][1].                                                                                    |
| `oci-mediatypes`    | `cache-to`              | `true`,`false`          | `true`  | Use OCI media types in exported manifests, see [OCI media types][2].                                                            |
| `image-manifest`    | `cache-to`              | `true`,`false`          | `true`  | When using OCI media types, generate an image manifest instead of an image index for the cache image, see [OCI media types][2]. |
| `compression`       | `cache-to`              | `gzip`,`estargz`,`zstd` | `gzip`  | Compression type, see [cache compression][3].                                                                                   |
| `compression-level` | `cache-to`              | `0..22`                 |         | Compression level, see [cache compression][3].                                                                                  |
| `force-compression` | `cache-to`              | `true`,`false`          | `false` | Forcibly apply compression, see [cache compression][3].                                                                         |
| `ignore-error`      | `cache-to`              | Boolean                 | `false` | Ignore errors caused by failed cache exports.                                                                                   |

[1]: index.md#cache-mode
[2]: index.md#oci-media-types
[3]: index.md#cache-compression

You can choose any valid value for `ref`, as long as it's not the same as the
target location that you push your image to. You might choose different tags
(e.g. `foo/bar:latest` and `foo/bar:build-cache`), separate image names (e.g.
`foo/bar` and `foo/bar-cache`), or even different repositories (e.g.
`docker.io/foo/bar` and `ghcr.io/foo/bar`). It's up to you to decide the
strategy that you want to use for separating your image from your cache images.

If the `--cache-from` target doesn't exist, then the cache import step will
fail, but the build continues.

## Further reading

For an introduction to caching see [Docker build cache](../index.md).

For more information on the `registry` cache backend, see the
[BuildKit README](https://github.com/moby/buildkit#registry-push-image-and-cache-separately).


---

# Amazon S3 cache

*Sección: Build*

{{< summary-bar feature_name="Amazon S3 cache" >}}

The `s3` cache storage uploads your resulting build cache to
[Amazon S3 file storage service](https://aws.amazon.com/s3/)
or other S3-compatible services, such as [MinIO](https://min.io/).

This cache storage backend is not supported with the default `docker` driver.
To use this feature, create a new builder using a different driver. See
[Build drivers](../../builders/drivers/index.md) for more information.

## Synopsis

```console
$ docker buildx build --push -t <user>/<image> \
  --cache-to type=s3,region=<region>,bucket=<bucket>,name=<cache-image>[,parameters...] \
  --cache-from type=s3,region=<region>,bucket=<bucket>,name=<cache-image> .
```

The following table describes the available CSV parameters that you can pass to
`--cache-to` and `--cache-from`.

| Name                 | Option                  | Type        | Default      | Description                                                    |
|----------------------| ----------------------- | ----------- |--------------|----------------------------------------------------------------|
| `region`             | `cache-to`,`cache-from` | String      |              | Required. Geographic location.                                 |
| `bucket`             | `cache-to`,`cache-from` | String      |              | Required. Name of the S3 bucket.                               |
| `name`               | `cache-to`,`cache-from` | String      | `buildkit`   | Name of the cache image.                                       |
| `endpoint_url`       | `cache-to`,`cache-from` | String      |              | Endpoint of the S3 bucket.                                     |
| `prefix`             | `cache-to`,`cache-from` | String      |              | Prefix to prepend to all filenames.                            |
| `blobs_prefix`       | `cache-to`,`cache-from` | String      | `blobs/`     | Prefix to prepend to blob filenames.                           |
| `upload_parallelism` | `cache-to`              | Integer     | `4`          | Number of parallel layer uploads.                              |
| `touch_refresh`      | `cache-to`              | Time        | `24h`        | Interval for updating the timestamp of unchanged cache layers. |
| `manifests_prefix`   | `cache-to`,`cache-from` | String      | `manifests/` | Prefix to prepend to manifest filenames.                       |
| `use_path_style`     | `cache-to`,`cache-from` | Boolean     | `false`      | When `true`, uses `bucket` in the URL instead of hostname.     |
| `access_key_id`      | `cache-to`,`cache-from` | String      |              | See [authentication][1].                                       |
| `secret_access_key`  | `cache-to`,`cache-from` | String      |              | See [authentication][1].                                       |
| `session_token`      | `cache-to`,`cache-from` | String      |              | See [authentication][1].                                       |
| `mode`               | `cache-to`              | `min`,`max` | `min`        | Cache layers to export, see [cache mode][2].                   |
| `ignore-error`       | `cache-to`              | Boolean     | `false`      | Ignore errors caused by failed cache exports.                  |

[1]: #authentication
[2]: index.md#cache-mode

## Authentication

Buildx can reuse existing AWS credentials, configured either using a
credentials file or environment variables, for pushing and pulling cache to S3.
Alternatively, you can use the `access_key_id`, `secret_access_key`, and
`session_token` attributes to specify credentials directly on the CLI.

Refer to [AWS Go SDK, Specifying Credentials][3] for details about
authentication using environment variables and credentials file.

[3]: https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/configure-gosdk.html#specifying-credentials

## Further reading

For an introduction to caching see [Docker build cache](../index.md).

For more information on the `s3` cache backend, see the
[BuildKit README](https://github.com/moby/buildkit#s3-cache-experimental).


---

# Build garbage collection

*Sección: Build*

While [`docker builder prune`](/reference/cli/docker/builder/prune/)
or [`docker buildx prune`](/reference/cli/docker/buildx/prune/)
commands run at once, Garbage Collection (GC) runs periodically and follows an
ordered list of prune policies. The BuildKit daemon clears the build cache when
the cache size becomes too big, or when the cache age expires.

For most users, the default GC behavior is sufficient and doesn't require any
intervention. Advanced users, particularly those working with large-scale
builds, self-managed builders, or constrained storage environments, might
benefit from customizing these settings to better align with their workflow
needs. The following sections explain how GC works and provide guidance on
tailoring its behavior through custom configuration.

## Garbage collection policies

GC policies define a set of rules that determine how the build cache is managed
and cleaned up. These policies include criteria for when to remove cache
entries, such as the age of the cache, the amount of space being used, and the
type of cache records to prune.

Each GC policy is evaluated in sequence, starting with the most specific
criteria, and proceeds to broader rules if previous policies do not free up
enough cache. This lets BuildKit prioritize cache entries, preserving the most
valuable cache while ensuring the system maintains performance and
availability.

For example, say you have the following GC policies:

1. Find "stale" cache records that haven't been used in the past 48 hours, and
   delete records until there's maximum 5GB of "stale" cache left.
2. If the build cache size exceeds 10GB, delete records until the total cache
   size is no more than 10GB.

The first rule is more specific, prioritizing stale cache records and setting a
lower limit for a less valuable type of cache. The second rule imposes a higher
hard limit that applies to any type of cache records. With these policies, if
you have 11GB worth of build cache, where:

- 7GB of which is "stale" cache
- 4GB is other, more valuable cache

A GC sweep would delete 2GB of stale cache as part of the 1st policy, leaving
9GB of cache in total, meaning the 2nd policy does not need to clear any more
cache.

The default GC policies are (approximately):

1. Remove cache that can be easily regenerated, such as build contexts from
   local directories or remote Git repositories, and cache mounts, if hasn't
   been used for more than 48 hours.
2. Remove cache that hasn't been used in a build for more than 60 days.
3. Remove unshared cache that exceeds the build cache size limit. Unshared
   cache records refers to layer blobs that are not used by other resources
   (typically, as image layers).
4. Remove any build cache that exceeds the build cache size limit.

The precise algorithm and the means of configuring the policies differ slightly
depending on what kind of builder you're using. Refer to
[Configuration](#configuration) for more details.

## Configuration

> [!NOTE]
> If you're satisfied with the default garbage collection behavior and don't
> need to fine-tune its settings, you can skip this section. Default
> configurations work well for most use cases and require no additional setup.

Depending on the type of [build driver](../builders/drivers/index.md) you use,
you will use different configuration files to change the builder's GC settings:

- If you use the default builder for Docker Engine (the `docker` driver), use
  the [Docker daemon configuration file](#docker-daemon-configuration-file).
- If you use a custom builder, use a [BuildKit configuration file](#buildkit-configuration-file).

### Docker daemon configuration file

If you're using the default [`docker` driver](../builders/drivers/docker.md),
GC is configured in the [`daemon.json` configuration file](/reference/cli/dockerd.md#daemon-configuration-file),
or if you use Docker Desktop, in [**Settings > Docker Engine**](../../desktop/settings-and-maintenance/settings.md).

The following snippet shows the default builder configuration for the `docker`
driver for Docker Desktop users:

```json
{
  "builder": {
    "gc": {
      "defaultKeepStorage": "20GB",
      "enabled": true
    }
  }
}
```

The `defaultKeepStorage` option configures the size limit of the build cache,
which influences the GC policies. The default policies for the `docker` driver
work as follows:

1. Remove ephemeral, unused build cache older than 48 hours if it exceeds 13.8%
   of `defaultKeepStorage`, or at minimum 512MB.
2. Remove unused build cache older than 60 days.
3. Remove unshared build cache that exceeds the `defaultKeepStorage` limit.
4. Remove any build cache that exceeds the `defaultKeepStorage` limit.

Given the Docker Desktop default value for `defaultKeepStorage` of 20GB, the
default GC policies resolve to:

```json
{
  "builder": {
    "gc": {
      "enabled": true,
      "policy": [
        {
          "reservedSpace": "2.764GB",
          "keepDuration": "48h",
          "filter": [
            "type=source.local,type=exec.cachemount,type=source.git.checkout"
          ]
        },
        { "reservedSpace": "20GB", "keepDuration": ["1440h"] },
        { "reservedSpace": "20GB" },
        { "reservedSpace": "20GB", "all": true }
      ]
    }
  }
}
```

The easiest way to tweak the build cache configuration for the `docker` driver
is to adjust the `defaultKeepStorage` option:

- Increase the limit if you feel like you think the GC is too aggressive.
- Decrease the limit if you need to preserve space.

#### Custom GC policies in the Docker daemon configuration file

If you need even more control, you can define your own GC policies directly.
The following example defines a more conservative GC configuration with the
following policies:

1. Remove unused cache entries older than 1440 hours, or 60 days, if build cache exceeds 50GB.
2. Remove unshared cache entries if build cache exceeds 50GB.
3. Remove any cache entries if build cache exceeds 100GB.

```json
{
  "builder": {
    "gc": {
      "enabled": true,
      "policy": [
        { "reservedSpace": "50GB", "keepDuration": ["1440h"] },
        { "reservedSpace": "50GB" },
        { "reservedSpace": "100GB", "all": true }
      ]
    }
  }
}
```

> [!NOTE]
> In the Docker daemon configuration file, the "equals" operator in GC filters
> is denoted using a single `=`, whereas BuildKit's configuration file uses
> `==`:
>
> | `daemon.json`       | `buildkitd.toml`     |
> |---------------------|----------------------|
> | `type=source.local` | `type==source.local` |
> | `private=true`      | `private==true`      |
> | `shared=true`       | `shared==true`       |
>
> See [prune filters](/reference/cli/docker/buildx/prune/#filter) for
> information about available GC filters. GC configuration in `daemon.json`
> supports all filters except `mutable` and `immutable`.

### BuildKit configuration file

For build drivers other than `docker`, GC is configured using a
[`buildkitd.toml`](../buildkit/toml-configuration.md) configuration file. This
file uses the following high-level configuration options that you can use to
tweak the thresholds for how much disk space BuildKit should use for cache:

| Option          | Description                                                                                                                                             | Default value                                         |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| `reservedSpace` | The minimum amount of disk space BuildKit is allowed to allocate for cache. Usage below this threshold will not be reclaimed during garbage collection. | 10% of total disk space or 10GB (whichever is lower)  |
| `maxUsedSpace`  | The maximum amount of disk space that BuildKit is allowed to use. Usage above this threshold will be reclaimed during garbage collection.               | 60% of total disk space or 100GB (whichever is lower) |
| `minFreeSpace`  | The amount of disk space that must be kept free.                                                                                                        | 20GB                                                  |

You can set these options either as number of bytes, a unit string (for
example, `512MB`), or as a percentage of the total disk size. Changing these
options influences the default GC policies used by the BuildKit worker. With
the default thresholds, the GC policies resolve as follows:

```toml
# Global defaults
[worker.oci]
  gc = true
  reservedSpace = "10GB"
  maxUsedSpace = "100GB"
  minFreeSpace = "20%"

# Policy 1
[[worker.oci.gcpolicy]]
  filters = [ "type==source.local", "type==exec.cachemount", "type==source.git.checkout" ]
  keepDuration = "48h"
  maxUsedSpace = "512MB"

# Policy 2
[[worker.oci.gcpolicy]]
  keepDuration = "1440h" # 60 days
  reservedSpace = "10GB"
  maxUsedSpace = "100GB"

# Policy 3
[[worker.oci.gcpolicy]]
  reservedSpace = "10GB"
  maxUsedSpace = "100GB"

# Policy 4
[[worker.oci.gcpolicy]]
  all = true
  reservedSpace = "10GB"
  maxUsedSpace = "100GB"
```

In practical terms, this means:

- Policy 1: If the build cache exceeds 512MB, BuildKit removes cache records
  for local build contexts, remote Git contexts, and cache mounts that haven’t
  been used in the last 48 hours.
- Policy 2: If disk usage exceeds 100GB, unshared build cache older than 60
  days is removed, ensuring at least 10GB of disk space is reserved for cache.
- Policy 3: If disk usage exceeds 100GB, any unshared cache is removed,
  ensuring at least 10GB of disk space is reserved for cache.
- Policy 4: If disk usage exceeds 100GB, all cache—including shared and
  internal records—is removed, ensuring at least 10GB of disk space is reserved
  for cache.

`reservedSpace` has the highest priority in defining the lower limit for build
cache size. If `maxUsedSpace` or `minFreeSpace` would define a lower value, the
minimum cache size would never be brought below `reservedSpace`.

If both `reservedSpace` and `maxUsedSpace` are set, a GC sweep results in a
cache size between those thresholds. For example, if `reservedSpace` is set to
10GB, and `maxUsedSpace` is set to 20GB, the resulting amount of cache after a
GC run is less than 20GB, but at least 10GB.

You can also define completely custom GC policies. Custom policies also let you
define filters, which lets you pinpoint the types of cache entries that a given
policy is allowed to prune.

#### Custom GC policies in BuildKit

Custom GC policies let you fine-tune how BuildKit manages its cache, and gives
you full control over cache retention based on criteria such as cache type,
duration, or disk space thresholds. If you need full control over the cache
thresholds and how cache records should be prioritized, defining custom GC
policies is the way to go.

To define a custom GC policy, use the `[[worker.oci.gcpolicy]]` configuration
block in `buildkitd.toml`. Each policy define the thresholds that will be used
for that policy. The global values for `reservedSpace`, `maxUsedSpace`, and
`minFreeSpace` do not apply if you use custom policies.

Here’s an example configuration:

```toml
# Custom GC Policy 1: Remove unused local contexts older than 24 hours
[[worker.oci.gcpolicy]]
  filters = ["type==source.local"]
  keepDuration = "24h"
  reservedSpace = "5GB"
  maxUsedSpace = "50GB"

# Custom GC Policy 2: Remove remote Git contexts older than 30 days
[[worker.oci.gcpolicy]]
  filters = ["type==source.git.checkout"]
  keepDuration = "720h"
  reservedSpace = "5GB"
  maxUsedSpace = "30GB"

# Custom GC Policy 3: Aggressively clean all cache if disk usage exceeds 90GB
[[worker.oci.gcpolicy]]
  all = true
  reservedSpace = "5GB"
  maxUsedSpace = "90GB"
```

In addition to the `reservedSpace`, `maxUsedSpace`, and `minFreeSpace` threshold,
when defining a GC policy you have two additional configuration options:

- `all`: By default, BuildKit will exclude some cache records from being pruned
  during GC. Setting this option to `true` will allow any cache records to be
  pruned.
- `filters`: Filters let you specify specific types of cache records that a GC
  policy is allowed to prune.

See [buildx prune filters](/reference/cli/docker/buildx/prune/#filter) for
information about available GC filters.


---

# Build cache invalidation

*Sección: Build*

When building an image, Docker steps through the instructions in your
Dockerfile, executing each in the order specified. For each instruction, the
[builder](../builders/index.md) checks whether it can reuse the
instruction from the build cache.

## General rules

The basic rules of build cache invalidation are as follows:

- The builder begins by checking if the base image is already cached. Each
  subsequent instruction is compared against the cached layers. If no cached
  layer matches the instruction exactly, the cache is invalidated.

- In most cases, comparing the Dockerfile instruction with the corresponding
  cached layer is sufficient. However, some instructions require additional
  checks and explanations.

- For the `ADD` and `COPY` instructions, and for `RUN` instructions with bind
  mounts (`RUN --mount=type=bind`), the builder calculates a cache checksum
  from file metadata to determine whether cache is valid. During cache lookup,
  cache is invalidated if the file metadata has changed for any of the files
  involved.

  The modification time of a file (`mtime`) is not taken into account when
  calculating the cache checksum. If only the `mtime` of the copied files have
  changed, the cache is not invalidated.

- Aside from the `ADD` and `COPY` commands, cache checking doesn't look at the
  files in the container to determine a cache match. For example, when processing
  a `RUN apt-get -y update` command the files updated in the container
  aren't examined to determine if a cache hit exists. In that case just
  the command string itself is used to find a match.

Once the cache is invalidated, all subsequent Dockerfile commands generate new
images and the cache isn't used.

If your build contains several layers and you want to ensure the build cache is
reusable, order the instructions from less frequently changed to more
frequently changed where possible.

## WORKDIR and SOURCE_DATE_EPOCH

The `WORKDIR` instruction respects the `SOURCE_DATE_EPOCH` build argument when
determining cache validity. Changing `SOURCE_DATE_EPOCH` between builds
invalidates the cache for `WORKDIR` and all subsequent instructions.

`SOURCE_DATE_EPOCH` sets timestamps for files created during the build. If you
set this to a dynamic value like a Git commit timestamp, the cache breaks with
each commit. This is expected behavior when tracking build provenance.

For reproducible builds without frequent cache invalidation, use a fixed
timestamp:

```console
$ docker build --build-arg SOURCE_DATE_EPOCH=0 .
```

## RUN instructions

The cache for `RUN` instructions isn't invalidated automatically between builds.
Suppose you have a step in your Dockerfile to install `curl`:

```dockerfile
FROM alpine:{{% param "example_alpine_version" %}} AS install
RUN apk add curl
```

This doesn't mean that the version of `curl` in your image is always up-to-date.
Rebuilding the image one week later will still get you the same packages as before.
To force a re-execution of the `RUN` instruction, you can:

- Make sure that a layer before it has changed
- Clear the build cache ahead of the build using
  [`docker builder prune`](/reference/cli/docker/builder/prune/)
- Use the `--no-cache` or `--no-cache-filter` options

The `--no-cache-filter` option lets you specify a specific build stage to
invalidate the cache for:

```console
$ docker build --no-cache-filter install .
```

## Build secrets

The contents of build secrets are not part of the build cache.
Changing the value of a secret doesn't result in cache invalidation.

If you want to force cache invalidation after changing a secret value,
you can pass a build argument with an arbitrary value that you also change when changing the secret.
Build arguments do result in cache invalidation.

```dockerfile
FROM alpine
ARG CACHEBUST
RUN --mount=type=secret,id=TOKEN,env=TOKEN \
    some-command ...
```

```console
$ TOKEN="tkn_pat123456" docker build --secret id=TOKEN --build-arg CACHEBUST=1 .
```

Properties of secrets such as IDs and mount paths do participate in the cache
checksum, and result in cache invalidation if changed.


---

# Optimize cache usage in builds

*Sección: Build*

When building with Docker, a layer is reused from the build cache if the
instruction and the files it depends on hasn't changed since it was previously
built. Reusing layers from the cache speeds up the build process because Docker
doesn't have to rebuild the layer again.

Here are a few techniques you can use to optimize build caching and speed up
the build process:

- [Order your layers](#order-your-layers): Putting the commands in your
  Dockerfile into a logical order can help you avoid unnecessary cache
  invalidation.
- [Keep the context small](#keep-the-context-small): The context is the set of
  files and directories that are sent to the builder to process a build
  instruction. Keeping the context as small as possible reduces the amount of data that
  needs to be sent to the builder, and reduces the likelihood of cache
  invalidation.
- [Use bind mounts](#use-bind-mounts): Bind mounts let you mount a file or
  directory from the host machine into the build container. Using bind mounts
  can help you avoid unnecessary layers in the image, which can slow down the
  build process.
- [Use cache mounts](#use-cache-mounts): Cache mounts let you specify a
  persistent package cache to be used during builds. The persistent cache helps
  speed up build steps, especially steps that involve installing packages using
  a package manager. Having a persistent cache for packages means that even if
  you rebuild a layer, you only download new or changed packages.
- [Use an external cache](#use-an-external-cache): An external cache lets you
  store build cache at a remote location. The external cache image can be
  shared between multiple builds, and across different environments.

## Order your layers

Putting the commands in your Dockerfile into a logical order is a great place
to start. Because a change causes a rebuild for steps that follow, try to make
expensive steps appear near the beginning of the Dockerfile. Steps that change
often should appear near the end of the Dockerfile, to avoid triggering
rebuilds of layers that haven't changed.

Consider the following example. A Dockerfile snippet that runs a JavaScript
build from the source files in the current directory:

```dockerfile
# syntax=docker/dockerfile:1
FROM node
WORKDIR /app
COPY . .          # Copy over all files in the current directory
RUN npm install   # Install dependencies
RUN npm build     # Run build
```

This Dockerfile is rather inefficient. Updating any file causes a reinstall of
all dependencies every time you build the Docker image even if the dependencies
didn't change since last time.

Instead, the `COPY` command can be split in two. First, copy over the package
management files (in this case, `package.json` and `yarn.lock`). Then, install
the dependencies. Finally, copy over the project source code, which is subject
to frequent change.

```dockerfile
# syntax=docker/dockerfile:1
FROM node
WORKDIR /app
COPY package.json yarn.lock .    # Copy package management files
RUN npm install                  # Install dependencies
COPY . .                         # Copy over project files
RUN npm build                    # Run build
```

By installing dependencies in earlier layers of the Dockerfile, there is
no need to rebuild those layers when a project file has changed.

## Keep the context small

The easiest way to make sure your context doesn't include unnecessary files is
to create a `.dockerignore` file in the root of your build context. The
`.dockerignore` file works similarly to `.gitignore` files, and lets you
exclude files and directories from the build context.

Here's an example `.dockerignore` file that excludes the `node_modules`
directory, all files and directories that start with `tmp`:

```plaintext {title=".dockerignore"}
node_modules
tmp*
```

Ignore-rules specified in the `.dockerignore` file apply to the entire build
context, including subdirectories. This means it's a rather coarse-grained
mechanism, but it's a good way to exclude files and directories that you know
you don't need in the build context, such as temporary files, log files, and
build artifacts.

## Use bind mounts

You might be familiar with bind mounts for when you run containers with `docker
run` or Docker Compose. Bind mounts let you mount a file or directory from the
host machine into a container.

```bash
# bind mount using the -v flag
docker run -v $(pwd):/path/in/container image-name
# bind mount using the --mount flag
docker run --mount=type=bind,src=.,dst=/path/in/container image-name
```

To use bind mounts in a build, you can use the `--mount` flag with the `RUN`
instruction in your Dockerfile:

```dockerfile
FROM golang:latest
WORKDIR /build
RUN --mount=type=bind,target=. go build -o /app/hello
```

In this example, the current directory is mounted into the build container at
`/build` before the `go build` command gets executed. The build output is
written to `/app/hello`, which is outside the mount point. This distinction is
important: the build output must be written outside the bind mount target,
since the mount is read-only by default. The source code is available in the
build container for the duration of that `RUN` instruction. When the
instruction is done executing, the mounted files are not persisted in the final
image, or in the build cache. Only the output of the `go build` command
remains.

The `COPY` and `ADD` instructions in a Dockerfile lets you copy files from the
build context into the build container. Using bind mounts is beneficial for
build cache optimization because you're not adding unnecessary layers to the
cache. If you have build context that's on the larger side, and it's only used
to generate an artifact, you're better off using bind mounts to temporarily
mount the source code required to generate the artifact into the build. If you
use `COPY` to add the files to the build container, BuildKit will include all
of those files in the cache, even if the files aren't used in the final image.

There are a few things to be aware of when using bind mounts in a build:

- Bind mounts are read-only by default. If you need to write to the mounted
  directory, you need to specify the `rw` option. However, even with the `rw`
  option, the changes are not persisted in the final image or the build cache.
  The file writes are sustained for the duration of the `RUN` instruction, and
  are discarded after the instruction is done.
- Mounted files are not persisted in the final image. Only the output of the
  `RUN` instruction is persisted in the final image. If you need to include
  files from the build context in the final image, you need to use the `COPY`
  or `ADD` instructions.
- If the target directory is not empty, the contents of the target directory
  are hidden by the mounted files. The original contents are restored after the
  `RUN` instruction is done.

  {{< accordion title="Example" >}}

  For example, given a build context with only a `Dockerfile` in it:

  ```plaintext
  .
  └── Dockerfile
  ```

  And a Dockerfile that mounts the current directory into the build container:

  ```dockerfile
  FROM alpine:latest
  WORKDIR /work
  RUN touch foo.txt
  RUN --mount=type=bind,target=. ls
  RUN ls
  ```

  The first `ls` command with the bind mount shows the contents of the mounted
  directory. The second `ls` lists the contents of the original build context.

  ```plaintext {title="Build log"}
  #8 [stage-0 3/5] RUN touch foo.txt
  #8 DONE 0.1s
  
  #9 [stage-0 4/5] RUN --mount=target=. ls -1
  #9 0.040 Dockerfile
  #9 DONE 0.0s
  
  #10 [stage-0 5/5] RUN ls -1
  #10 0.046 foo.txt
  #10 DONE 0.1s
  ```

  {{< /accordion >}}

## Use cache mounts

Regular cache layers in Docker correspond to an exact match of the instruction
and the files it depends on. If the instruction and the files it depends on
have changed since the layer was built, the layer is invalidated, and the build
process has to rebuild the layer.

Cache mounts are a way to specify a persistent cache location to be used during
builds. The cache is cumulative across builds, so you can read and write to the
cache multiple times. This persistent caching means that even if you need to
rebuild a layer, you only download new or changed packages. Any unchanged
packages are reused from the cache mount.

To use cache mounts in a build, you can use the `--mount` flag with the `RUN`
instruction in your Dockerfile:

```dockerfile
FROM node:latest
WORKDIR /app
RUN --mount=type=cache,target=/root/.npm npm install
```

In this example, the `npm install` command uses a cache mount for the
`/root/.npm` directory, the default location for the npm cache. The cache mount
is persisted across builds, so even if you end up rebuilding the layer, you
only download new or changed packages. Any changes to the cache are persisted
across builds, and the cache is shared between multiple builds.

How you specify cache mounts depends on the build tool you're using. If you're
unsure how to specify cache mounts, refer to the documentation for the build
tool you're using. Here are a few examples:

{{< tabs >}}
{{< tab name="Go" >}}

```dockerfile
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go build -o /app/hello
```

{{< /tab >}}
{{< tab name="Apt" >}}

```dockerfile
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
  --mount=type=cache,target=/var/lib/apt,sharing=locked \
  apt update && apt-get --no-install-recommends install -y gcc
```

{{< /tab >}}
{{< tab name="Python" >}}

```dockerfile
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt
```

{{< /tab >}}
{{< tab name="Ruby" >}}

```dockerfile
RUN --mount=type=cache,target=/root/.gem \
    bundle install
```

{{< /tab >}}
{{< tab name="Rust" >}}

```dockerfile
RUN --mount=type=cache,target=/app/target/ \
    --mount=type=cache,target=/var/cache/cargo \
    CARGO_HOME=/var/cache/cargo cargo build
```

The cache mount uses a single `CARGO_HOME` so concurrent builds coordinate
access through Cargo's cache lock. Setting `CARGO_HOME` also changes where
Cargo looks for global configuration and credentials. Project-level
`.cargo/config.toml` files are unaffected.

{{< /tab >}}
{{< tab name=".NET" >}}

```dockerfile
RUN --mount=type=cache,target=/root/.nuget/packages \
    dotnet restore
```

{{< /tab >}}
{{< tab name="PHP" >}}  

```dockerfile
RUN --mount=type=cache,target=/tmp/cache \
    composer install
```

{{< /tab >}}
{{< /tabs >}}

It's important that you read the documentation for the build tool you're using
to make sure you're using the correct cache mount options. Package managers
have different requirements for how they use the cache, and using the wrong
options can lead to unexpected behavior. For example, Apt needs exclusive
access to its data, so the caches use the option `sharing=locked` to ensure
parallel builds using the same cache mount wait for each other and not access
the same cache files at the same time.

## Use an external cache

The default cache storage for builds is internal to the builder (BuildKit
instance) you're using. Each builder uses its own cache storage. When you
switch between different builders, the cache is not shared between them. Using
an external cache lets you define a remote location for pushing and pulling
cache data.

External caches are especially useful for CI/CD pipelines, where the builders
are often ephemeral, and build minutes are precious. Reusing the cache between
builds can drastically speed up the build process and reduce cost. You can even
make use of the same cache in your local development environment.

To use an external cache, you specify the `--cache-to` and `--cache-from`
options with the `docker buildx build` command.

- `--cache-to` exports the build cache to the specified location.
- `--cache-from` specifies remote caches for the build to use.

The following example shows how to set up a GitHub Actions workflow using
`docker/build-push-action`, and push the build cache layers to an OCI registry
image:

```yaml {title=".github/workflows/ci.yml"}
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest
          cache-from: type=registry,ref=user/app:buildcache
          cache-to: type=registry,ref=user/app:buildcache,mode=max
```

This setup tells BuildKit to look for cache in the `user/app:buildcache` image.
And when the build is done, the new build cache is pushed to the same image,
overwriting the old cache.

This cache can be used locally as well. To pull the cache in a local build,
you can use the `--cache-from` option with the `docker buildx build` command:

```console
$ docker buildx build --cache-from type=registry,ref=user/app:buildcache .
```

## Summary

Optimizing cache usage in builds can significantly speed up the build process.
Keeping the build context small, using bind mounts, cache mounts, and external
caches are all techniques you can use to make the most of the build cache and
speed up the build process.

For more information about the concepts discussed in this guide, see:

- [.dockerignore files](../concepts/context.md#dockerignore-files)
- [Cache invalidation](invalidation.md)
- [Cache mounts](../concepts/dockerfile.md#run---mounttypecache)
- [Cache backend types](backends/index.md)
- [Building best practices](../building/best-practices.md)


---

# Checking your build configuration

*Sección: Build*

{{< summary-bar feature_name="Build checks" >}}

Build checks are a feature introduced in Dockerfile 1.8. It lets you validate
your build configuration and conduct a series of checks prior to executing your
build. Think of it as an advanced form of linting for your Dockerfile and build
options, or a dry-run mode for builds.

You can find the list of checks available, and a description of each, in the
[Build checks reference](/reference/build-checks/).

## How build checks work

Typically, when you run a build, Docker executes the build steps in your
Dockerfile and build options as specified. With build checks, rather than
executing the build steps, Docker checks the Dockerfile and options you provide
and reports any issues it detects.

Build checks are useful for:

- Validating your Dockerfile and build options before running a build.
- Ensuring that your Dockerfile and build options are up-to-date with the
  latest best practices.
- Identifying potential issues or anti-patterns in your Dockerfile and build
  options.

> [!TIP]
>
> To improve linting, code navigation, and vulnerability scanning of your Dockerfiles in Visual Studio Code
> see the [Docker DX](https://marketplace.visualstudio.com/items?itemName=docker.docker) extension.

## Build with checks

Build checks are supported in:

- Buildx version 0.15.0 and later
- [docker/build-push-action](https://github.com/docker/build-push-action) version 6.6.0 and later
- [docker/bake-action](https://github.com/docker/bake-action) version 5.6.0 and later

Invoking a build runs the checks by default, and displays any violations in the
build output. For example, the following command both builds the image and runs
the checks:

```console
$ docker build .
[+] Building 3.5s (11/11) FINISHED
...

1 warning found (use --debug to expand):
  - Lint Rule 'JSONArgsRecommended': JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 7)

```

In this example, the build ran successfully, but a
[JSONArgsRecommended](/reference/build-checks/json-args-recommended/) warning
was reported, because `CMD` instructions should use JSON array syntax.

With the GitHub Actions, the checks display in the diff view of pull requests.

```yaml
name: Build and push Docker images
on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
```

![GitHub Actions build check annotations](./images/gha-check-annotations.png)

### More verbose output

Check warnings for a regular `docker build` display a concise message
containing the rule name, the message, and the line number of where in the
Dockerfile the issue originated. If you want to see more detailed information
about the checks, you can use the `--debug` flag. For example:

```console
$ docker --debug build .
[+] Building 3.5s (11/11) FINISHED
...

 1 warning found:
 - JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 4)
JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals
More info: https://docs.docker.com/go/dockerfile/rule/json-args-recommended/
Dockerfile:4
--------------------
   2 |
   3 |     FROM alpine
   4 | >>> CMD echo "Hello, world!"
   5 |
--------------------

```

With the `--debug` flag, the output includes a link to the documentation for
the check, and a snippet of the Dockerfile where the issue was found.

## Check a build without building

To run build checks without actually building, you can use the `docker build`
command as you typically would, but with the addition of the `--check` flag.
Here's an example:

```console
$ docker build --check .
```

Instead of executing the build steps, this command only runs the checks and
reports any issues it finds. If there are any issues, they will be reported in
the output. For example:

```text {title="Output with --check"}
[+] Building 1.5s (5/5) FINISHED
=> [internal] connecting to local controller
=> [internal] load build definition from Dockerfile
=> => transferring dockerfile: 253B
=> [internal] load metadata for docker.io/library/node:22
=> [auth] library/node:pull token for registry-1.docker.io
=> [internal] load .dockerignore
=> => transferring context: 50B
JSONArgsRecommended - https://docs.docker.com/go/dockerfile/rule/json-args-recommended/
JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals
Dockerfile:7
--------------------
5 |
6 |     COPY index.js .
7 | >>> CMD node index.js
8 |
--------------------
```

This output with `--check` shows the [verbose message](#more-verbose-output)
for the check.

Unlike a regular build, if any violations are reported when using the `--check`
flag, the command exits with a non-zero status code.

## Fail build on check violations

Check violations for builds are reported as warnings, with exit code 0, by
default. You can configure Docker to fail the build when violations are
reported, using a `check=error=true` directive in your Dockerfile. This will
cause the build to error out when after the build checks are run, before the
actual build gets executed.

```dockerfile {title=Dockerfile,linenos=true,hl_lines=2}
# syntax=docker/dockerfile:1
# check=error=true

FROM alpine
CMD echo "Hello, world!"
```

Without the `# check=error=true` directive, this build would complete with an
exit code of 0. However, with the directive, build check violation results in
non-zero exit code:

```console
$ docker build .
[+] Building 1.5s (5/5) FINISHED
...

 1 warning found (use --debug to expand):
 - JSONArgsRecommended: JSON arguments recommended for CMD to prevent unintended behavior related to OS signals (line 5)
Dockerfile:1
--------------------
   1 | >>> # syntax=docker/dockerfile:1
   2 |     # check=error=true
   3 |
--------------------
ERROR: lint violation found for rules: JSONArgsRecommended
$ echo $?
1
```

You can also set the error directive on the CLI by passing the
`BUILDKIT_DOCKERFILE_CHECK` build argument:

```console
$ docker build --check --build-arg "BUILDKIT_DOCKERFILE_CHECK=error=true" .
```

## Skip checks

By default, all checks are run when you build an image. If you want to skip
specific checks, you can use the `check=skip` directive in your Dockerfile.
The `skip` parameter takes a CSV string of the check IDs you want to skip.
For example:

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
# check=skip=JSONArgsRecommended,StageNameCasing

FROM alpine AS BASE_STAGE
CMD echo "Hello, world!"
```

Building this Dockerfile results in no check violations.

You can also skip checks by passing the `BUILDKIT_DOCKERFILE_CHECK` build
argument with a CSV string of check IDs you want to skip. For example:

```console
$ docker build --check --build-arg "BUILDKIT_DOCKERFILE_CHECK=skip=JSONArgsRecommended,StageNameCasing" .
```

To skip all checks, use the `skip=all` parameter:

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
# check=skip=all
```

## Combine error and skip parameters for check directives

To both skip specific checks and error on check violations, pass both the
`skip` and `error` parameters separated by a semi-colon (`;`) to the `check`
directive in your Dockerfile or in a build argument. For example:

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
# check=skip=JSONArgsRecommended,StageNameCasing;error=true
```

```console {title="Build argument"}
$ docker build --check --build-arg "BUILDKIT_DOCKERFILE_CHECK=skip=JSONArgsRecommended,StageNameCasing;error=true" .
```

## Experimental checks

Before checks are promoted to stable, they may be available as experimental
checks. Experimental checks are disabled by default. To see the list of
experimental checks available, refer to the [Build checks reference](/reference/build-checks/).

To enable all experimental checks, set the `BUILDKIT_DOCKERFILE_CHECK` build
argument to `experimental=all`:

```console
$ docker build --check --build-arg "BUILDKIT_DOCKERFILE_CHECK=experimental=all" .
```

You can also enable experimental checks in your Dockerfile using the `check`
directive:

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
# check=experimental=all
```

To selectively enable experimental checks, you can pass a CSV string of the
check IDs you want to enable, either to the `check` directive in your Dockerfile
or as a build argument. For example:

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
# check=experimental=JSONArgsRecommended,StageNameCasing
```

Note that the `experimental` directive takes precedence over the `skip`
directive, meaning that experimental checks will run regardless of the `skip`
directive you have set. For example, if you set `skip=all` and enable
experimental checks, the experimental checks will still run:

```dockerfile {title=Dockerfile}
# syntax=docker/dockerfile:1
# check=skip=all;experimental=all
```

## Further reading

For more information about using build checks, see:

- [Build checks reference](/reference/build-checks/)
- [Validating build configuration with GitHub Actions](ci/github-actions/checks.md)


---

# Continuous integration with Docker

*Sección: Build*

Continuous Integration (CI) is the part of the development process where you're
looking to get your code changes merged with the main branch of the project. At
this point, development teams run tests and builds to vet that the code changes
don't cause any unwanted or unexpected behaviors.

![Git branches about to get merged](./images/continuous-integration.svg)

There are several uses for Docker at this stage of development, even if you
don't end up packaging your application as a container image.

## Docker as a build environment

Containers are reproducible, isolated environments that yield predictable
results. Building and testing your application in a Docker container makes it
easier to prevent unexpected behaviors from occurring. Using a Dockerfile, you
define the exact requirements for the build environment, including programming
runtimes, operating system, binaries, and more.

Using Docker to manage your build environment also eases maintenance. For
example, updating to a new version of a programming runtime can be as simple as
changing a tag or digest in a Dockerfile. No need to SSH into a pet VM to
manually reinstall a newer version and update the related configuration files.

Additionally, just as you expect third-party open source packages to be secure,
the same should go for your build environment. You can scan and index a builder
image, just like you would for any other containerized application.

The following links provide instructions for how you can get started using
Docker for building your applications in CI:

- [GitHub Actions](https://docs.github.com/en/actions/creating-actions/creating-a-docker-container-action)
- [GitLab](https://docs.gitlab.com/runner/executors/docker.html)
- [Circle CI](https://circleci.com/docs/using-docker/)
- [Render](https://render.com/docs/docker)

### Docker in Docker

You can also use a Dockerized build environment to build container images using
Docker. That is, your build environment runs inside a container which itself is
equipped to run Docker builds. This method is referred to as "Docker in Docker".

Docker provides an official [Docker image](https://hub.docker.com/_/docker)
that you can use for this purpose.

## What's next

Docker maintains a set of official GitHub Actions that you can use to build,
annotate, and push container images on the GitHub Actions platform. See
[Introduction to GitHub Actions](github-actions/index.md) to learn more and
get started.


---

# Docker Build GitHub Actions

*Sección: Build*

GitHub Actions is a popular CI/CD platform for automating your build, test, and
deployment pipeline. Docker provides a set of official GitHub Actions for you to
use in your workflows. These official actions are reusable, easy-to-use
components for building, annotating, and pushing images.

The following GitHub Actions are available:

- [Build and push Docker images](https://github.com/marketplace/actions/build-and-push-docker-images):
  build and push Docker images with BuildKit.
- [Docker Buildx Bake](https://github.com/marketplace/actions/docker-buildx-bake):
  enables using high-level builds with [Bake](../../bake/index.md).
- [Docker Login](https://github.com/marketplace/actions/docker-login):
  sign in to a Docker registry.
- [Docker Setup Buildx](https://github.com/marketplace/actions/docker-setup-buildx):
  creates and boots a BuildKit builder.
- [Docker Metadata action](https://github.com/marketplace/actions/docker-metadata-action):
  extracts metadata from Git reference and GitHub events to generate tags,
  labels, and annotations.
- [Docker Setup Compose](https://github.com/marketplace/actions/docker-setup-compose):
  installs and sets up [Compose](../../../compose).
- [Docker Setup Docker](https://github.com/marketplace/actions/docker-setup-docker):
  installs Docker Engine.
- [Docker Setup QEMU](https://github.com/marketplace/actions/docker-setup-qemu):
  installs [QEMU](https://github.com/qemu/qemu) static binaries for
  multi-platform builds.
- [Docker Scout](https://github.com/docker/scout-action):
  analyze Docker images for security vulnerabilities.

Using Docker's actions provides an easy-to-use interface, while still allowing
flexibility for customizing build parameters.

## Examples

If you're looking for examples on how to use the Docker GitHub Actions,
refer to the following sections:

{{% sectionlinks %}}

## Get started with GitHub Actions

The [Introduction to GitHub Actions with Docker](/guides/gha.md) guide walks
you through the process of setting up and using Docker GitHub Actions for
building Docker images, and pushing images to Docker Hub.


---

# Add image annotations with GitHub Actions

*Sección: Build*

Annotations let you specify arbitrary metadata for OCI image components, such
as manifests, indexes, and descriptors.

To add annotations when building images with GitHub Actions, use the
[metadata-action] to automatically create OCI-compliant annotations. The
metadata action creates an `annotations` output that you can reference, both
with [build-push-action] and [bake-action].

[metadata-action]: https://github.com/docker/metadata-action#overwrite-labels-and-annotations
[build-push-action]: https://github.com/docker/build-push-action/
[bake-action]: https://github.com/docker/bake-action/

{{< tabs >}}
{{< tab name="build-push-action" >}}

```yaml {hl_lines=32}
name: ci

on:
  push:

env:
  IMAGE_NAME: user/app

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: ${{ env.IMAGE_NAME }}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          tags: ${{ steps.meta.outputs.tags }}
          annotations: ${{ steps.meta.outputs.annotations }}
          push: true
```

{{< /tab >}}
{{< tab name="bake-action" >}}

```yaml {hl_lines=37}
name: ci

on:
  push:

env:
  IMAGE_NAME: user/app

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: ${{ env.IMAGE_NAME }}

      - name: Build
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        with:
          files: |
            ./docker-bake.hcl
            cwd://${{ steps.meta.outputs.bake-file-tags }}
            cwd://${{ steps.meta.outputs.bake-file-annotations }}
          push: true
```

{{< /tab >}}
{{< /tabs >}}

## Configure annotation level

By default, annotations are placed on image manifests. To configure the
[annotation level](../../metadata/annotations.md#specify-annotation-level), set
the `DOCKER_METADATA_ANNOTATIONS_LEVELS` environment variable on the
`metadata-action` step to a comma-separated list of all the levels that you
want to annotate. For example, setting `DOCKER_METADATA_ANNOTATIONS_LEVELS` to
`index` results in annotations on the image index instead of the manifests.

The following example creates annotations on both the image index and
manifests.

```yaml {hl_lines=28}
name: ci

on:
  push:

env:
  IMAGE_NAME: user/app

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: ${{ env.IMAGE_NAME }}
        env:
          DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          tags: ${{ steps.meta.outputs.tags }}
          annotations: ${{ steps.meta.outputs.annotations }}
          push: true
```

> [!NOTE]
>
> The build must produce the components that you want to annotate. For example,
> to annotate an image index, the build must produce an index. If the build
> produces only a manifest and you specify `index` or `index-descriptor`, the
> build fails.


---

# Add SBOM and provenance attestations with GitHub Actions

*Sección: Build*

Software Bill of Material (SBOM) and provenance
[attestations](../../metadata/attestations/index.md) add metadata about the contents of
your image, and how it was built.

Attestations are supported with version 4 and later of the
`docker/build-push-action`.

## Default provenance

The `docker/build-push-action` GitHub Action automatically adds provenance
attestations to your image, with the following conditions:

- If the GitHub repository is public, provenance attestations with `mode=max`
  are automatically added to the image.
- If the GitHub repository is private, provenance attestations with `mode=min`
  are automatically added to the image.
- If you're using the [`docker` exporter](../../exporters/oci-docker.md), or
  you're loading the build results to the runner with `load: true`, no
  attestations are added to the image. These output formats don't support
  attestations.

> [!WARNING]
>
> If you're using `docker/build-push-action` to build images for code in a
> public GitHub repository, the provenance attestations attached to your image
> by default contains the values of build arguments. If you're misusing build
> arguments to pass secrets to your build, such as user credentials or
> authentication tokens, those secrets are exposed in the provenance
> attestation. Refactor your build to pass those secrets using
> [secret mounts](/reference/cli/docker/buildx/build/#secret)
> instead. Also remember to rotate any secrets you may have exposed.

## Max-level provenance

It's recommended that you build your images with max-level provenance
attestations. Private repositories only add min-level provenance by default,
but you can manually override the provenance level by setting the `provenance`
input on the `docker/build-push-action` GitHub Action to `mode=max`.

Note that adding attestations to an image means you must push the image to a
registry directly, as opposed to loading the image to the local image store of
the runner. This is because the local image store doesn't support loading
images with attestations.

```yaml
name: ci

on:
  push:

env:
  IMAGE_NAME: user/app

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: ${{ env.IMAGE_NAME }}

      - name: Build and push image
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          provenance: mode=max
          tags: ${{ steps.meta.outputs.tags }}
```

## SBOM

SBOM attestations aren't automatically added to the image. To add SBOM
attestations, set the `sbom` input of the `docker/build-push-action` to true.

Note that adding attestations to an image means you must push the image to a
registry directly, as opposed to loading the image to the local image store of
the runner. This is because the local image store doesn't support loading
images with attestations.

```yaml
name: ci

on:
  push:

env:
  IMAGE_NAME: user/app

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: ${{ env.IMAGE_NAME }}

      - name: Build and push image
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          sbom: true
          push: true
          tags: ${{ steps.meta.outputs.tags }}
```


---

# GitHub Actions build summary

*Sección: Build*

Docker's GitHub Actions for building and pushing images generate a job summary
for your build that outlines the execution and materials used:

- A summary showing the Dockerfile used, the build duration, and cache utilization
- Inputs for the build, such as build arguments, tags, labels, and build contexts
- For builds with [Bake](../../bake/index.md), the full bake definition for the build

![A GitHub Actions build summary](../images/gha_build_summary.png)

Job summaries for Docker builds appear automatically if you use the following
versions of the [Build and push Docker images](https://github.com/marketplace/actions/build-and-push-docker-images)
or [Docker Buildx Bake](https://github.com/marketplace/actions/docker-buildx-bake)
GitHub Actions:

- `docker/build-push-action@{{% param "build_push_action_version" %}}`
- `docker/bake-action@{{% param "bake_action_version" %}}`

To view the job summary, open the details page for the job in GitHub after the
job has finished. The summary is available for both failed and successful
builds. In the case of a failed build, the summary also displays the error
message that caused the build to fail:

![Builds summary error message](../images/build_summary_error.png)

## Import build records to Docker Desktop

The job summary includes a link for downloading a build record archive for the
run. The build record archive is a ZIP file containing the details about a build
(or builds, if you use `docker/bake-action` to build multiple targets). You can
import this build record archive into Docker Desktop, which gives you a
powerful, graphical interface for further analyzing the build's performance via
the [Docker Desktop **Builds** view](../../../desktop/use-desktop/builds.md).

To import the build record archive into Docker Desktop:

1. Download and install [Docker Desktop](/get-started/get-docker.md).

2. Download the build record archive from the job summary in GitHub Actions.

3. Open the **Builds** view in Docker Desktop.

4. Select the **Import build** button, and then browse for the `.zip` archive
   job summary that you downloaded. Alternatively, you can drag-and-drop the
   build record archive ZIP file onto the Docker Desktop window after opening
   the import build dialog.

5. Select **Import** to add the build records.

After a few seconds, the builds from the GitHub Actions run appear under the
**Completed builds** tab in the Builds view. To inspect a build and see a
detailed view of all the inputs, results, build steps, and cache utilization,
select the item in the list.

## Disable job summary

To disable job summaries, set the `DOCKER_BUILD_SUMMARY` environment variable
in the YAML configuration for your build step:

```yaml {hl_lines=4}
      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        env:
          DOCKER_BUILD_SUMMARY: false
        with:
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
```

## Disable build record upload

To disable the upload of the build record archive to GitHub, set the
`DOCKER_BUILD_RECORD_UPLOAD` environment variable in the YAML configuration for
your build step:

```yaml {hl_lines=4}
      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        env:
          DOCKER_BUILD_RECORD_UPLOAD: false
        with:
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
```

With this configuration, the build summary is still generated, but does not
contain a link to download the build record archive.

## Limitations

Build summaries are currently not supported for:

- Repositories hosted on GitHub Enterprise Servers. Summaries can only be
  viewed for repositories hosted on GitHub.com.


---

# Cache management with GitHub Actions

*Sección: Build*

This page contains examples on using the cache storage backends with GitHub
Actions.

> [!NOTE]
>
> See [Cache storage backends](../../cache/backends/index.md) for more
> details about cache storage backends.

## Inline cache

In most cases you want to use the [inline cache exporter](../../cache/backends/inline.md).
However, note that the `inline` cache exporter only supports `min` cache mode.
To use `max` cache mode, push the image and the cache separately using the
registry cache exporter with the `cache-to` option, as shown in the [registry cache example](#registry-cache).

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest
          cache-from: type=registry,ref=user/app:latest
          cache-to: type=inline
```

## Registry cache

You can import/export cache from a cache manifest or (special) image
configuration on the registry with the [registry cache exporter](../../cache/backends/registry.md).

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest
          cache-from: type=registry,ref=user/app:buildcache
          cache-to: type=registry,ref=user/app:buildcache,mode=max
```

## GitHub cache

### Cache backend API

{{< summary-bar feature_name="Cache backend API" >}}

The [GitHub Actions cache exporter](../../cache/backends/gha.md)
backend uses the [GitHub Cache service API](https://github.com/tonistiigi/go-actions-cache)
to fetch and upload cache blobs. That's why you should only use this cache
backend in a GitHub Action workflow, as the `url` (`$ACTIONS_RESULTS_URL`) and
`token` (`$ACTIONS_RUNTIME_TOKEN`) attributes only get populated in a workflow
context.

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max
```

> [!IMPORTANT]
>
> As of April 15th, 2025, [only GitHub Cache service API v2 is supported.](https://gh.io/gha-cache-sunset). The legacy v1 API has been shut down.
>
> If you encounter the following error during your build:
>
> ```console
> ERROR: failed to solve: This legacy service is shutting down, effective April 15, 2025. Migrate to the new service ASAP. For more information: https://gh.io/gha-cache-sunset
> ```
>
> You're probably using outdated tools that only support the legacy GitHub
> Cache service API v1. Here are the minimum versions you need to upgrade to
> depending on your use case:
> * Docker Buildx >= v0.21.0
> * BuildKit >= v0.20.0
> * Docker Compose >= v2.33.1
> * Docker Engine >= v28.0.0 (if you're building using the Docker driver with containerd image store enabled)
>
> If you're building using the `docker/build-push-action` or `docker/bake-action`
> actions on GitHub hosted runners, Docker Buildx and BuildKit are already up
> to date but on self-hosted runners, you may need to update them yourself.
> Alternatively, you can use the `docker/setup-buildx-action` action to install
> the latest version of Docker Buildx:
>
> ```yaml
> - name: Set up Docker Buildx
>   uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
>   with:
>    version: latest
> ```
>
> If you're building using Docker Compose, you can use the
> `docker/setup-compose-action` action:
>
> ```yaml
> - name: Set up Docker Compose
>   uses: docker/setup-compose-action@{{% param "setup_compose_action_version" %}}
>   with:
>    version: latest
> ```
>
> If you're building using the Docker Engine with the containerd image store
> enabled, you can use the `docker/setup-docker-action` action:
>
> ```yaml
> -
>   name: Set up Docker
>   uses: docker/setup-docker-action@{{% param "setup_docker_action_version" %}}
>   with:
>     version: latest
>     daemon-config: |
>       {
>         "features": {
>           "containerd-snapshotter": true
>         }
>       }
> ```

### Cache write restrictions

Cache export requires write access to the GitHub Actions cache. GitHub gives
events such as `issue_comment` and `pull_request_target` read-only cache access
by default when they run in the default-branch context. These workflows can
restore existing cache entries, but exporting with `cache-to: type=gha` can fail
with `error writing layer blob: failed to reserve cache`, even after the image
has been built and pushed.

This also affects `pull_request` workflows with `types: [closed]` when a pull
request is merged into the default branch: the run uses the target branch ref
instead of the pull request merge ref. Regular `pull_request` runs using a
merge ref retain read-write cache access by default. See GitHub's
[cache access policy](https://github.blog/changelog/2026-06-26-read-only-actions-cache-for-untrusted-triggers/).

For workflows with read-only cache access, keep `cache-from: type=gha` and omit
`cache-to`. Populate the cache from a workflow with write access, such as a
`push` workflow on the default branch. For builds after a merge, use `push` on
the target branch instead of `pull_request` with `types: [closed]`.

GitHub's workflow or job-level
[`cache-mode` setting](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#cache-mode)
can override the default cache access. Granting write access to untrusted
workflows increases the risk of cache poisoning.

If cache export is optional, you can make export failures non-fatal:

```yaml
cache-from: type=gha
cache-to: type=gha,mode=max,ignore-error=true
```

`ignore-error=true` suppresses all cache export errors, not only access errors.
It doesn't grant write access or save the cache when writes are denied.

### Cache mounts

BuildKit doesn't preserve cache mounts in the GitHub Actions cache by default.
To put your cache mounts into GitHub Actions cache and reuse it
between builds, you can use a workaround provided by
[`reproducible-containers/buildkit-cache-dance`](https://github.com/reproducible-containers/buildkit-cache-dance).

This GitHub Action creates temporary containers to extract and inject the
cache mount data with your Docker build steps.

The following example shows how to use this workaround with a Go project.

Example Dockerfile in `build/package/Dockerfile`

```Dockerfile
FROM golang:1.21.1-alpine as base-build

WORKDIR /build

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=bind,source=go.mod,target=go.mod \
    --mount=type=bind,source=go.sum,target=go.sum \
    go mod download

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    --mount=type=bind,target=. \
    go build -o /bin/app ./src
...
```

Example CI action

```yaml
name: ci

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Docker meta
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: user/app
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}

      - name: Go Build Cache for Docker
        uses: actions/cache@{{% param "cache_action_version" %}}
        with:
          path: go-build-cache
          key: ${{ runner.os }}-go-build-cache-${{ hashFiles('**/go.sum') }}

      - name: Inject go-build-cache
        uses: reproducible-containers/buildkit-cache-dance@4b2444fec0c0fb9dbf175a96c094720a692ef810 # v2.1.4
        with:
          cache-source: go-build-cache

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          cache-from: type=gha
          cache-to: type=gha,mode=max
          file: build/package/Dockerfile
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64,linux/arm64
```

For more information about this workaround, refer to the
[GitHub repository](https://github.com/reproducible-containers/buildkit-cache-dance).

### Local cache

> [!NOTE]
>
> Exporting to a directory that already holds a cache leaves the blobs of the
> previous export behind, so the directory grows with every run. The following
> example passes `reset=true` to delete them. This parameter requires Buildx
> version 0.35.0 or later.

You can also leverage [GitHub cache](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows)
using the [actions/cache](https://github.com/actions/cache) and [local cache exporter](../../cache/backends/local.md)
with this action:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Cache Docker layers
        uses: actions/cache@{{% param "cache_action_version" %}}
        with:
          path: ${{ runner.temp }}/.buildx-cache
          key: ${{ runner.os }}-buildx-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-buildx-

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest
          cache-from: type=local,src=${{ runner.temp }}/.buildx-cache
          cache-to: type=local,dest=${{ runner.temp }}/.buildx-cache,mode=max,reset=true
```


---

# Validating build configuration with GitHub Actions

*Sección: Build*

[Build checks](../../checks.md) let you validate your `docker build`
configuration without actually running the build.

## Run checks with `docker/build-push-action`

To run build checks in a GitHub Actions workflow with the `build-push-action`,
set the `call` input parameter to `check`. With this set, the workflow fails if
any check warnings are detected for your build's configuration.

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Validate build configuration
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          call: check

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest
```

## Run checks with `docker/bake-action`

If you're using Bake and `docker/bake-action` to run your builds, you don't
need to specify any special inputs in your GitHub Actions workflow
configuration. Instead, define a Bake target that calls the `check` method,
and invoke that target in your CI.

```hcl
target "build" {
  dockerfile = "Dockerfile"
  args = {
    FOO = "bar"
  }
}
target "validate-build" {
  inherits = ["build"]
  call = "check"
}
```

```yaml
name: ci

on:
  push:

env:
  IMAGE_NAME: user/app

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Validate build configuration
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        with:
          targets: validate-build

      - name: Build
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        with:
          targets: build
          push: true
```

### Using the `call` input directly

You can also set the build method with the `call` input which is equivalent to using the `--call` flag with `docker buildx bake`

For example, to run a check without defining `call` in your Bake file:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Validate build configuration
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        with:
          targets: build
          call: check
```


---

# Configuring your GitHub Actions builder

*Sección: Build*

This page contains instructions on configuring your BuildKit instances when
using our [Setup Buildx Action](https://github.com/docker/setup-buildx-action).

## Version pinning

By default, the action will attempt to use the latest version of [Buildx](https://github.com/docker/buildx)
available on the GitHub Runner (the build client) and the latest release of
[BuildKit](https://github.com/moby/buildkit) (the build server).

To pin to a specific version of Buildx, use the `version` input. For example,
to pin to Buildx v0.10.0:

```yaml
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
  with:
    version: v0.10.0
```

To pin to a specific version of BuildKit, use the `image` option in the
`driver-opts` input. For example, to pin to BuildKit v0.11.0:

```yaml
- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
  with:
    driver-opts: image=moby/buildkit:v0.11.0
```

## BuildKit container logs

To display BuildKit container logs when using the `docker-container` driver,
you must either [enable step debug logging](https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging#enabling-step-debug-logging),
or set the `--debug` buildkitd flag in the [Docker Setup Buildx](https://github.com/marketplace/actions/docker-setup-buildx) action:

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          buildkitd-flags: --debug
      
      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
```

Logs will be available at the end of a job:

![BuildKit container logs](images/buildkit-container-logs.png)

## BuildKit Daemon configuration

You can provide a [BuildKit configuration](../../buildkit/toml-configuration.md)
to your builder if you're using the [`docker-container` driver](../../builders/drivers/docker-container.md)
(default) with the `config` or `buildkitd-config-inline` inputs:

### Registry mirror

You can configure a registry mirror using an inline block directly in your
workflow with the `buildkitd-config-inline` input:

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          buildkitd-config-inline: |
            [registry."docker.io"]
              mirrors = ["mirror.gcr.io"]
```

For more information about using a registry mirror, see [Registry mirror](../../buildkit/configure.md#registry-mirror).

### Max parallelism

You can limit the parallelism of the BuildKit solver which is particularly
useful for low-powered machines.

You can use the `buildkitd-config-inline` input like the previous example, or you can use
a dedicated BuildKit config file from your repository if you want with the
`config` input:

```toml
# .github/buildkitd.toml
[worker.oci]
  max-parallelism = 4
```

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          config: .github/buildkitd.toml
```

## Append additional nodes to the builder

Buildx supports running builds on multiple machines. This is useful for building
[multi-platform images](../../building/multi-platform.md) on native nodes for
more complicated cases that aren't handled by QEMU. Building on native nodes
generally has better performance, and allows you to distribute the build across
multiple machines.

You can append nodes to the builder you're creating using the `append` option.
It takes input in the form of a YAML string document to remove limitations
intrinsically linked to GitHub Actions: you can only use strings in the input
fields:

| Name              | Type   | Description                                                                                                                                                                                                                                                             |
| ----------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`            | String | [Name of the node](/reference/cli/docker/buildx/create/#node). If empty, it's the name of the builder it belongs to, with an index number suffix. This is useful to set it if you want to modify/remove a node in an underlying step of your workflow. |
| `endpoint`        | String | [Docker context or endpoint](/reference/cli/docker/buildx/create/#description) of the node to add to the builder                                                                                                                                      |
| `driver-opts`     | List   | List of additional [driver-specific options](/reference/cli/docker/buildx/create/#driver-opt)                                                                                                                                                         |
| `buildkitd-flags` | String | [Flags for buildkitd](/reference/cli/docker/buildx/create/#buildkitd-flags) daemon                                                                                                                                                                    |
| `platforms`       | String | Fixed [platforms](/reference/cli/docker/buildx/create/#platform) for the node. If not empty, values take priority over the detected ones.                                                                                                             |

Here is an example using remote nodes with the [`remote` driver](../../builders/drivers/remote.md)
and [TLS authentication](#tls-authentication):

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          driver: remote
          endpoint: tcp://oneprovider:1234
          append: |
            - endpoint: tcp://graviton2:1234
              platforms: linux/arm64
            - endpoint: tcp://linuxone:1234
              platforms: linux/s390x
        env:
          BUILDER_NODE_0_AUTH_TLS_CACERT: ${{ secrets.ONEPROVIDER_CA }}
          BUILDER_NODE_0_AUTH_TLS_CERT: ${{ secrets.ONEPROVIDER_CERT }}
          BUILDER_NODE_0_AUTH_TLS_KEY: ${{ secrets.ONEPROVIDER_KEY }}
          BUILDER_NODE_1_AUTH_TLS_CACERT: ${{ secrets.GRAVITON2_CA }}
          BUILDER_NODE_1_AUTH_TLS_CERT: ${{ secrets.GRAVITON2_CERT }}
          BUILDER_NODE_1_AUTH_TLS_KEY: ${{ secrets.GRAVITON2_KEY }}
          BUILDER_NODE_2_AUTH_TLS_CACERT: ${{ secrets.LINUXONE_CA }}
          BUILDER_NODE_2_AUTH_TLS_CERT: ${{ secrets.LINUXONE_CERT }}
          BUILDER_NODE_2_AUTH_TLS_KEY: ${{ secrets.LINUXONE_KEY }}
```

## Authentication for remote builders

The following examples show how to handle authentication for remote builders,
using SSH or TLS.

### SSH authentication

To be able to connect to an SSH endpoint using the [`docker-container` driver](../../builders/drivers/docker-container.md),
you have to set up the SSH private key and configuration on the GitHub Runner:

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Set up SSH
        uses: MrSquaare/ssh-setup-action@2d028b70b5e397cf8314c6eaea229a6c3e34977a # v3.1.0
        with:
          host: graviton2
          private-key: ${{ secrets.SSH_PRIVATE_KEY }}
          private-key-name: aws_graviton2
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          endpoint: ssh://me@graviton2
```

### TLS authentication

You can also [set up a remote BuildKit instance](../../builders/drivers/remote.md#example-remote-buildkit-in-docker-container)
using the remote driver. To ease the integration in your workflow, you can use
an environment variables that sets up authentication using the BuildKit client
certificates for the `tcp://`:

- `BUILDER_NODE_<idx>_AUTH_TLS_CACERT`
- `BUILDER_NODE_<idx>_AUTH_TLS_CERT`
- `BUILDER_NODE_<idx>_AUTH_TLS_KEY`

The `<idx>` placeholder is the position of the node in the list of nodes.

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          driver: remote
          endpoint: tcp://graviton2:1234
        env:
          BUILDER_NODE_0_AUTH_TLS_CACERT: ${{ secrets.GRAVITON2_CA }}
          BUILDER_NODE_0_AUTH_TLS_CERT: ${{ secrets.GRAVITON2_CERT }}
          BUILDER_NODE_0_AUTH_TLS_KEY: ${{ secrets.GRAVITON2_KEY }}
```

## Standalone mode

If you don't have the Docker CLI installed on the GitHub Runner, the Buildx
binary gets invoked directly, instead of calling it as a Docker CLI plugin. This
can be useful if you want to use the `kubernetes` driver in your self-hosted
runner:

```yaml
name: ci

on:
  push:

jobs:
  buildx:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@{{% param "checkout_action_version" %}}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          driver: kubernetes
      
      - name: Build
        run: |
          buildx build .
```

## Isolated builders

The following example shows how you can select different builders for different
jobs.

An example scenario where this might be useful is when you are using a monorepo,
and you want to pinpoint different packages to specific builders. For example,
some packages may be particularly resource-intensive to build and require more
compute. Or they require a builder equipped with a particular capability or
hardware.

For more information about remote builder, see [`remote` driver](../../builders/drivers/remote.md)
and the [append builder nodes example](#append-additional-nodes-to-the-builder).

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up builder1
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        id: builder1
      
      - name: Set up builder2
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        id: builder2
      
      - name: Build against builder1
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          builder: ${{ steps.builder1.outputs.name }}
          target: mytarget1
      
      - name: Build against builder2
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          builder: ${{ steps.builder2.outputs.name }}
          target: mytarget2
```


---

# Copy image between registries with GitHub Actions

*Sección: Build*

[Multi-platform images](../../building/multi-platform.md) built using Buildx can
be copied from one registry to another using the [`buildx imagetools create` command](/reference/cli/docker/buildx/imagetools/create/):

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            user/app:latest
            user/app:1.0.0

      - name: Push image to GHCR
        run: |
          docker buildx imagetools create \
            --tag ghcr.io/user/app:latest \
            --tag ghcr.io/user/app:1.0.0 \
            user/app:latest
```


---

# Export to Docker with GitHub Actions

*Sección: Build*

You may want your build result to be available in the Docker client through
`docker images` to be able to use it in another step of your workflow:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
      
      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          load: true
          tags: myimage:latest
      
      - name: Inspect
        run: |
          docker image inspect myimage:latest
```


---

# Docker GitHub Builder

*Sección: Build*

Docker GitHub Builder is a set of [reusable workflows](https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows)
in the [`docker/github-builder` repository](https://github.com/docker/github-builder)
for building container images and local artifacts with [BuildKit](../../../buildkit/index.md).
This section explains what the workflows solve, how they differ from wiring
together individual GitHub Actions in each repository, and when to use
[`build.yml`](build.md) or [`bake.yml`](bake.md).

If you compose a build job from `docker/login-action`, `docker/setup-buildx-action`,
`docker/metadata-action`, and either `docker/build-push-action` or
`docker/bake-action`, your repository owns every detail of how the build runs.
That approach works, but it also means every repository has to maintain its own
runner selection, [cache setup](../cache.md), [Provenance settings](../attestations.md),
signing behavior, and [multi-platform manifest handling](../multi-platform.md).
Docker GitHub Builder moves that implementation into Docker-maintained reusable
workflows, so your workflow only decides when to build and which inputs to pass.

The difference is easiest to see in the job definition. A conventional workflow
spells out each action step:

```yaml
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        
      - name: Docker meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        id: meta
        with:
          images: name/app

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha
```

With Docker GitHub Builder, the same build is a reusable workflow call:

```yaml
jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: image
      push: ${{ github.event_name != 'pull_request' }}
      meta-images: name/app
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

This model gives you a build pipeline that is maintained in the Docker
organization, uses a pinned [BuildKit](../../../buildkit/index.md) environment,
distributes [multi-platform builds](../../../building/multi-platform.md) across
runners when that helps, and emits signed [SLSA provenance](../../../metadata/attestations/slsa-provenance.md)
that records both the source commit and the builder identity.

That tradeoff is intentional. You keep control of when the build runs and which
inputs it uses, but the build implementation itself lives in the
Docker-maintained workflow rather than in per-repository job steps.

Use [`build.yml`](build.md) when your repository builds from a Dockerfile and
the familiar `build-push-action` inputs map cleanly to your workflow. Use
[`bake.yml`](bake.md) when your repository already describes builds in a
[Bake definition](../../../bake/index.md), or when you want Bake targets,
overrides, and variables to stay as the source of truth.

Both workflows support image output, local output, cache export to the
[GitHub Actions cache backend](../../../cache/backends/gha.md),
[SBOM generation](../../../metadata/attestations/sbom.md), and signing. The
Bake workflow adds Bake definition validation and builds one target per workflow
call.

{{% sectionlinks %}}


---

# Docker GitHub Builder architecture

*Sección: Build*

Docker GitHub Builder separates repository orchestration from build
implementation. A consuming repository decides when a build runs, which
permissions and secrets are granted, and which inputs are passed. The reusable
workflow in [`docker/github-builder` repository](https://github.com/docker/github-builder)
owns the build implementation itself. That split keeps repository workflows
short while centralizing BuildKit, caching, provenance, SBOM generation,
signing, and multi-platform assembly in one Docker-maintained path.

![GitHub Builder overview](./images/architecture-overview.png)

## Core architecture

A caller workflow invokes either [`build.yml`](build.md) or [`bake.yml`](bake.md).
[`build.yml`](build.md) is the entrypoint for Dockerfile-oriented builds.
[`bake.yml`](bake.md) is the entrypoint for Bake-oriented builds, where the
Bake definition remains the source of truth for targets and overrides. In both
cases the caller still owns repository policy, including triggers, branch
conditions, permissions, secrets, target selection, metadata inputs, and the
choice between image output and local output.

Inside the reusable workflow, the first phase prepares the build. It validates
the incoming inputs, resolves the runner config, and expands a multi-platform
request into one job per platform. The execution model is easiest to picture as
a matrix where `linux/amd64` runs on `ubuntu-24.04` and `linux/arm64` runs on
`ubuntu-24.04-arm`. Each platform job builds independently, then the workflow
finalizes the result into one caller-facing output contract.

```yaml
requested platforms:
  linux/amd64,linux/arm64

conceptual platform jobs:
  linux/amd64 -> ubuntu-24.04
  linux/arm64 -> ubuntu-24.04-arm
```

### Runner selection

The `runner` input accepts either a single GitHub-hosted Linux runner label or a
newline-delimited platform mapping.

The default value is a platform mapping that uses GitHub-hosted Ubuntu runners:

```yaml
runner: |
  default=ubuntu-24.04
  linux/arm=ubuntu-24.04-arm
  linux/arm64=ubuntu-24.04-arm
```

In the platform job, the runner label resolves to a single value:

```yaml
runner: ubuntu-24.04
```

A mapping must define a `default` runner. Other keys are platform prefixes, and
the most specific matching prefix wins. For example, `linux/arm` matches
variants such as `linux/arm/v7`, while `linux/arm64` is a separate prefix:

In the following example, `linux` matches Linux platforms that do not match a
longer prefix. The `default` key is still required because it is the fallback
when no platform prefix matches.

```yaml
runner: |
  default=ubuntu-24.04
  linux=ubuntu-24.04
  linux/arm=ubuntu-24.04-arm
  linux/arm64=ubuntu-24.04-arm
```

The reusable workflows require GitHub-hosted Linux runners. The legacy `auto`,
`amd64`, and `arm64` values are still accepted for compatibility, but emit
deprecation warnings. Use an explicit runner label or platform mapping instead.

## Execution path

![GitHub Builder execution flow](./images/execution-flow.png)

The execution path stays short on purpose. The consuming repository calls the
reusable workflow. The reusable workflow prepares the build, runs the
per-platform jobs, and finalizes the result. For image output, finalization
produces a registry image and multi-platform manifest. For local output,
finalization merges the per-platform files and can upload the merged result as
a GitHub artifact. The caller does not need to reconstruct how Buildx,
BuildKit, caching, or manifest assembly were wired together.

## The two reusable entrypoints

[`build.yml`](build.md) is the better fit when the build is already expressed as
a Dockerfile-oriented workflow. It lines up naturally with concepts such as
`context`, `file`, `target`, `build-args`, `labels`, `annotations`, and
`platforms`. This is the entrypoint that feels closest to
`docker/build-push-action`, except the workflow implementation is centralized.

[`bake.yml`](bake.md) is the better fit when the repository already uses Bake
as the build definition. It preserves the Bake model, including target
resolution, `files`, `set`, and `vars`, while still routing execution through
the same Docker-maintained build path. One important architectural detail is
that the Bake workflow is centered on one target per workflow call, which keeps
provenance, digest handling, and final manifest assembly scoped to one build
unit at a time.

## Output model

The reusable workflows expose a stable set of caller-facing outputs so
downstream jobs can consume results without understanding the internal job
graph. In practice, the main values are `digest`, `meta-json`, `artifact-name`,
`output-type`, and `signed`. That contract matters because it keeps promotion,
publishing, or follow-on automation decoupled from the mechanics of runner
selection and per-platform assembly.

## Examples

### Dockerfile-oriented image build

The following example shows the shape of a multi-platform image build driven
by [`build.yml`](build.md).

```yaml
name: ci

on:
  push:
    branches:
      - "main"
    tags:
      - "v*"
  pull_request:

permissions:
  contents: read

jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read
      id-token: write
    with:
      output: image
      push: ${{ github.event_name != 'pull_request' }}
      platforms: linux/amd64,linux/arm64
      meta-images: name/app
      meta-tags: |
        type=ref,event=branch
        type=ref,event=pr
        type=semver,pattern={{version}}
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

This call is small because the reusable workflow absorbs the heavy lifting. The
repository decides when the build should run and which inputs it wants, while
the shared implementation handles Buildx setup, BuildKit configuration,
platform fan-out, metadata generation, provenance, SBOM generation, signing,
and final manifest creation.

### Bake-oriented local output

The following example shows the shape of a Bake call that exports local output
and uploads the merged artifact.

```yaml
name: ci

on:
  pull_request:

permissions:
  contents: read

jobs:
  bake:
    uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read
      id-token: write
    with:
      output: local
      target: binaries
      artifact-upload: true
      artifact-name: bake-output
```

This form is useful when the repository already keeps its build definition in
Bake and wants to preserve that source of truth. The workflow injects the local
output behavior into the Bake run, executes the target per platform when
needed, and merges the result into one caller-facing artifact.

## Why this architecture works

### Performance

The performance story comes from native platform fan-out, shared BuildKit
configuration, and centralized cache handling. Multi-platform work can be
spread across matching GitHub-hosted runners instead of forcing every
architecture through one build machine. That reduces emulation pressure,
shortens the critical path for cross-platform builds, and gives every
consuming repository the same optimized build baseline.

### Security

The security model comes from putting the build implementation in
Docker-maintained reusable workflows instead of ad hoc job steps in each
consumer repository. The caller still controls permissions and secrets, but
the build logic itself is centrally reviewed and versioned. The project also
treats provenance, SBOM generation, and signing as first-class concerns,
which strengthens the trust boundary between repository orchestration and
artifact production.

### Isolation and reliability

The reliability story comes from separation of concerns. The consuming
repository orchestrates the build. The reusable workflow executes the build.
That reduces CI drift, removes repeated glue code from repositories, and makes
the outcome easier to reason about because the caller sees a stable contract
instead of a large custom job definition.


---

# Bake with Docker GitHub Builder

*Sección: Build*

The [`bake.yml` reusable workflow](https://github.com/docker/github-builder?tab=readme-ov-file#bake-reusable-workflow)
builds from a [Bake definition](../../../bake/index.md) instead of a Dockerfile
input set. This page shows how to call the workflow for a target, how to pass
Bake overrides and variables, and how to export local output when a Bake file
is already the source of truth for your build.

## Build and push a Bake target

The following workflow builds the `image` target from `docker-bake.hcl` and
publishes the result with tags generated from [metadata inputs](../manage-tags-labels.md):

```yaml
name: ci

on:
  push:
    branches:
      - "main"
    tags:
      - "v*"
  pull_request:

permissions:
  contents: read

jobs:
  bake:
    uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: image
      push: ${{ github.event_name != 'pull_request' }}
      target: image
      meta-images: name/app
      meta-tags: |
        type=ref,event=branch
        type=ref,event=pr
        type=semver,pattern={{version}}
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

Bake workflows build one target per workflow call. Groups and multi-target
builds aren't supported because [SLSA provenance](../attestations.md), digest
handling, and manifest creation are scoped to a single target.

The workflow validates the definition before the build starts and resolves
the target from the files you pass in `files`. Runner selection uses the same
`runner` input as the Build workflow. Set a single GitHub-hosted Linux runner
label or a platform mapping when the default mapping is not enough. For details,
see [runner selection](architecture.md#runner-selection).

## Override target values and variables

Because the workflow delegates the build to Bake, you can keep using `set` and
`vars` for target-specific overrides:

```yaml
name: ci

on:
  push:
    branches:
      - "main"

permissions:
  contents: read

jobs:
  bake:
    uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: image
      push: true
      target: image
      vars: |
        IMAGE_TAG=${{ github.sha }}
      set: |
        *.args.BUILD_RUN_ID=${{ github.run_id }}
        *.platform=linux/amd64,linux/arm64
      cache: true
      cache-scope: image
      meta-images: name/app
      meta-tags: |
        type=sha
      set-meta-annotations: true
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

This form fits repositories that already use Bake groups, target inheritance,
and variable expansion. The reusable workflow takes care of Buildx setup,
[GitHub Actions cache export](../../../cache/backends/gha.md),
[Provenance defaults](../../../metadata/attestations/slsa-provenance.md),
signing behavior, and the final multi-platform manifest. Metadata labels and
annotations can be merged into the Bake definition without adding a separate
metadata step to your workflow.

## Export local output from Bake

If the target should export files instead of publishing an image, switch the
workflow output to `local` and upload the artifact:

```yaml
name: ci

on:
  pull_request:

permissions:
  contents: read

jobs:
  bake:
    uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: local
      target: binaries
      artifact-upload: true
      artifact-name: bake-output
```

With `output: local`, the workflow injects the matching local output override
into the Bake run and merges the uploaded artifacts after the per-platform
builds finish. If you need a manual Bake pattern that stays in a normal job,
see [Multi-platform image](../multi-platform.md). If your build does not need a
Bake definition, use [build.yml](build.md) instead.


---

# Build with Docker GitHub Builder

*Sección: Build*

The [`build.yml` reusable workflow](https://github.com/docker/github-builder?tab=readme-ov-file#build-reusable-workflow)
builds from a Dockerfile and packages the same core tasks that many repositories
wire together by hand. This page shows how to call the workflow, publish
[multi-platform images](../../../building/multi-platform.md), and export local
build artifacts without rebuilding the job structure in every repository.

## Build and push an image

The following workflow builds from the repository Dockerfile, pushes on branch
and tag events, and uses metadata inputs to generate tags:

```yaml
name: ci

on:
  push:
    branches:
      - "main"
    tags:
      - "v*"
  pull_request:

permissions:
  contents: read

jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: image
      push: ${{ github.event_name != 'pull_request' }}
      platforms: linux/amd64,linux/arm64
      meta-images: name/app
      meta-tags: |
        type=ref,event=branch
        type=ref,event=pr
        type=semver,pattern={{version}}
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

When you set `output: image`, `meta-images` is required because the workflow
creates image names and [manifest tags](../manage-tags-labels.md) from that
input. `distribute: true` is the default, so a multi-platform build can fan out
across native GitHub-hosted runners instead of forcing the whole build onto one
machine. The default `runner` mapping sends Linux Arm platforms to
`ubuntu-24.04-arm` and uses `ubuntu-24.04` for other platforms. To change that
mapping, see [runner selection](architecture.md#runner-selection). `sign: auto`
is also the default, which means the workflow signs
[attestation manifests](../attestations.md) when the image is pushed.

## Export local output as an artifact

The same workflow can export files instead of publishing an image. This is
useful when you want compiled assets, an unpacked root filesystem, or another
local exporter result as part of CI:

```yaml
name: ci

on:
  pull_request:

permissions:
  contents: read

jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: local
      artifact-upload: true
      artifact-name: build-output
      platforms: linux/amd64,linux/arm64
```

With `output: local`, the workflow exports files to the runner filesystem and
merges per-platform artifacts in the finalize phase. When
`artifact-upload: true` is set, the merged result is uploaded as a GitHub
artifact, and `sign: auto` signs the uploaded artifacts. `push` is ignored for
local output, so there is no registry requirement in this form.

## Add cache, Dockerfile inputs, and metadata labels

You can tune the Dockerfile build in the same job call. This example sets a
custom Dockerfile path, a target stage, GitHub Actions cache, and metadata
labels:

```yaml
name: ci

on:
  push:
    branches:
      - "main"

permissions:
  contents: read

jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read # to fetch the repository content
      id-token: write # for signing attestation(s) with GitHub OIDC Token
    with:
      output: image
      push: true
      context: .
      file: ./docker/Dockerfile
      target: runtime
      build-args: |
        NODE_ENV=production
        VERSION=${{ github.sha }}
      cache: true
      cache-scope: myapp
      meta-images: name/app
      meta-tags: |
        type=sha
      set-meta-labels: true
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

This is a Dockerfile build, so the inputs map closely to
`docker/build-push-action`. The difference is that the reusable workflow owns
Buildx setup, [BuildKit](../../../buildkit/index.md) configuration,
[SLSA provenance](../../../metadata/attestations/slsa-provenance.md) mode,
[GitHub Actions cache backend](../../../cache/backends/gha.md) wiring, signing,
and manifest creation. If you need more background on metadata or platform
distribution, see [Manage tags and labels](../manage-tags-labels.md) and
[Multi-platform image](../multi-platform.md).


---

# Local registry with GitHub Actions

*Sección: Build*

For testing purposes you may need to create a [local registry](https://hub.docker.com/_/registry)
to push images into:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    services:
      registry:
        image: registry:3
        ports:
          - 5000:5000
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          driver-opts: network=host
      
      - name: Build and push to local registry
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: localhost:5000/name/app:latest
      
      - name: Inspect
        run: |
          docker buildx imagetools inspect localhost:5000/name/app:latest
```


---

# Manage tags and labels with GitHub Actions

*Sección: Build*

If you want an "automatic" tag management and [OCI Image Format Specification](https://github.com/opencontainers/image-spec/blob/master/annotations.md)
for labels, you can do it in a dedicated setup step. The following workflow
will use the [Docker Metadata Action](https://github.com/docker/metadata-action)
to handle tags and labels based on GitHub Actions events and Git metadata:

```yaml
name: ci

on:
  schedule:
    - cron: "0 10 * * *"
  push:
    branches:
      - "**"
    tags:
      - "v*.*.*"
  pull_request:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Docker meta
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          # list of Docker images to use as base name for tags
          images: |
            name/app
            ghcr.io/username/app
          # generate Docker tags based on the following events/attributes
          tags: |
            type=schedule
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=semver,pattern={{major}}
            type=sha

      - name: Login to Docker Hub
        if: github.event_name != 'pull_request'
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GHCR
        if: github.event_name != 'pull_request'
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
```


---

# Multi-platform image with GitHub Actions

*Sección: Build*

You can build [multi-platform images](../../building/multi-platform.md) using
the `platforms` option, as shown in the following example:

> [!NOTE]
>
> - For a list of available platforms, see the [Docker Setup Buildx](https://github.com/marketplace/actions/docker-setup-buildx)
>   action.
> - If you want support for more platforms, you can use QEMU with the [Docker Setup QEMU](https://github.com/docker/setup-qemu-action)
>   action.

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          platforms: linux/amd64,linux/arm64
          push: true
          tags: user/app:latest
```

## Build and load multi-platform images

The default Docker setup for GitHub Actions runners supports building and pushing multi-platform images to registries. However, it does not support loading multi-platform images to the local image store of the runner after building them. To load a multi-platform image locally, you need to enable the containerd image store option for the Docker Engine.

There is no way to configure the default Docker setup in the GitHub Actions
runners directly, but you can use `docker/setup-docker-action` to customize the
Docker Engine and CLI settings for a job.

The following example workflow enables the containerd image store, builds a
multi-platform image, and loads the results into the GitHub runner's local
image store.

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker
        uses: docker/setup-docker-action@{{% param "setup_docker_action_version" %}}
        with:
          daemon-config: |
            {
              "debug": true,
              "features": {
                "containerd-snapshotter": true
              }
            }

      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          platforms: linux/amd64,linux/arm64
          load: true
          tags: user/app:latest
```

## Distribute build across multiple runners

Building multiple platforms on the same runner can significantly extend build
times, particularly when dealing with complex Dockerfiles or a high number of
target platforms. If you want to split platform builds across multiple runners
without maintaining a custom matrix and merge job, use the
[Docker GitHub Builder](github-builder/index.md). The reusable workflows
compute the per-platform matrix, run each platform on its own runner, and
create the final manifest for you.

The following workflow uses the [`build.yml` reusable workflow](github-builder/build.md)
to distribute a multi-platform Dockerfile build:

```yaml
name: ci

on:
  push:

permissions:
  contents: read

jobs:
  build:
    uses: docker/github-builder/.github/workflows/build.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read
      id-token: write
    with:
      output: image
      push: true
      platforms: linux/amd64,linux/arm64
      meta-images: user/app
      meta-tags: |
        type=ref,event=branch
        type=ref,event=pr
        type=semver,pattern={{version}}
        type=semver,pattern={{major}}.{{minor}}
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```

With `distribute: true`, which is the default, the workflow splits the build
into one platform per runner and assembles the final multi-platform image in
its finalize phase. The default `runner` mapping sends Linux Arm platforms to
`ubuntu-24.04-arm` and uses `ubuntu-24.04` for other platforms. To customize
the mapping, see [runner selection](github-builder/architecture.md#runner-selection).
If you need to control the Docker build inputs directly, see
[Build with Docker GitHub Builder build.yml](github-builder/build.md).

### With Bake

You can use the [`bake.yml` reusable workflow](github-builder/bake.md) for the
same pattern when your build is defined in a Bake file. The workflow reads the
target platforms from the Bake definition, distributes the per-platform builds,
and publishes the final manifest without a separate prepare or merge job.

```hcl
variable "DEFAULT_TAG" {
  default = "app:local"
}

// Special target: https://github.com/docker/metadata-action#bake-definition
target "docker-metadata-action" {
  tags = ["${DEFAULT_TAG}"]
}

// Default target if none specified
group "default" {
  targets = ["image-local"]
}

target "image" {
  inherits = ["docker-metadata-action"]
}

target "image-local" {
  inherits = ["image"]
  output = ["type=docker"]
}

target "image-all" {
  inherits = ["image"]
  platforms = [
    "linux/amd64",
    "linux/arm/v6",
    "linux/arm/v7",
    "linux/arm64"
  ]
}
```

```yaml
name: ci

on:
  push:

permissions:
  contents: read

jobs:
  bake:
    uses: docker/github-builder/.github/workflows/bake.yml@{{% param "github_builder_version" %}}
    permissions:
      contents: read
      id-token: write
    with:
      output: image
      push: true
      target: image-all
      meta-images: user/app
      meta-tags: |
        type=ref,event=branch
        type=sha
    secrets:
      registry-auths: |
        - registry: docker.io
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
```


---

# Named contexts with GitHub Actions

*Sección: Build*

You can define [additional build contexts](/reference/cli/docker/buildx/build/#build-context),
and access them in your Dockerfile with `FROM name` or `--from=name`. When
Dockerfile defines a stage with the same name it's overwritten.

This can be useful with GitHub Actions to reuse results from other builds or pin
an image to a specific tag in your workflow.

## Pin image to a tag

Replace `alpine:latest` with a pinned one:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN echo "Hello World"
```

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          build-contexts: |
            alpine=docker-image://alpine:{{% param "example_alpine_version" %}}
          tags: myimage:latest
```

## Use image in subsequent steps

By default, the [Docker Setup Buildx](https://github.com/marketplace/actions/docker-setup-buildx)
action uses `docker-container` as a build driver, so built Docker images aren't
loaded automatically.

With named contexts you can reuse the built image:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN echo "Hello World"
```

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          driver: docker

      - name: Build base image
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          context: "{{defaultContext}}:base"
          load: true
          tags: my-base-image:latest

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          build-contexts: |
            alpine=docker-image://my-base-image:latest
          tags: myimage:latest
```

## Using with a container builder

As shown in the previous section we are not using the default
[`docker-container` driver](../../builders/drivers/docker-container.md) for building with
named contexts. That's because this driver can't load an image from the Docker
store as it's isolated. To solve this problem you can use a [local registry](local-registry.md)
to push your base image in your workflow:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN echo "Hello World"
```

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    services:
      registry:
        image: registry:3
        ports:
          - 5000:5000
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          # network=host driver-opt needed to push to local registry
          driver-opts: network=host

      - name: Build base image
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          context: "{{defaultContext}}:base"
          tags: localhost:5000/my-base-image:latest
          push: true

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          build-contexts: |
            alpine=docker-image://localhost:5000/my-base-image:latest
          tags: myimage:latest
```


---

# Push to multiple registries with GitHub Actions

*Sección: Build*

The following workflow will connect you to Docker Hub and GitHub Container
Registry, and push the image to both registries:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Login to GitHub Container Registry
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
            user/app:latest
            user/app:1.0.0
            ghcr.io/user/app:latest
            ghcr.io/user/app:1.0.0
```


---

# Reproducible builds with GitHub Actions

*Sección: Build*

`SOURCE_DATE_EPOCH` is a [standardized environment variable][source_date_epoch]
for instructing build tools to produce a reproducible output.
Setting the environment variable for a build makes the timestamps in the
image index, config, and file metadata reflect the specified Unix time.

[source_date_epoch]: https://reproducible-builds.org/docs/source-date-epoch/

To set the environment variable in GitHub Actions,
use the built-in `env` property on the build step.

## Unix epoch timestamps

The following example sets the `SOURCE_DATE_EPOCH` variable to 0, Unix epoch.

{{< tabs group="action" >}}
{{< tab name="`docker/build-push-action`" >}}

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          tags: user/app:latest
        env:
          SOURCE_DATE_EPOCH: 0
```

{{< /tab >}}
{{< tab name="`docker/bake-action`" >}}

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        env:
          SOURCE_DATE_EPOCH: 0
```

{{< /tab >}}
{{< /tabs >}}

## Git commit timestamps

The following example sets `SOURCE_DATE_EPOCH` to the Git commit timestamp.

{{< tabs group="action" >}}
{{< tab name="`docker/build-push-action`" >}}

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Get Git commit timestamps
        run: echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          tags: user/app:latest
        env:
          SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
```

{{< /tab >}}
{{< tab name="`docker/bake-action`" >}}

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Get Git commit timestamps
        run: echo "TIMESTAMP=$(git log -1 --pretty=%ct)" >> $GITHUB_ENV

      - name: Build
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        env:
          SOURCE_DATE_EPOCH: ${{ env.TIMESTAMP }}
```

{{< /tab >}}
{{< /tabs >}}

## Additional information

For more information about the `SOURCE_DATE_EPOCH` support in BuildKit,
see [BuildKit documentation](https://github.com/moby/buildkit/blob/master/docs/build-repro.md#source_date_epoch).


---

# Using secrets with GitHub Actions

*Sección: Build*

A build secret is sensitive information, such as a password or API token, consumed as part of the build process.
Docker Build supports two forms of secrets:

- [Secret mounts](#secret-mounts) add secrets as files in the build container
  (under `/run/secrets` by default).
- [SSH mounts](#ssh-mounts) add SSH agent sockets or keys into the build container.

This page shows how to use secrets with GitHub Actions.
For an introduction to secrets in general, see [Build secrets](../../building/secrets.md).

## Secret mounts

In the following example uses and exposes the [`GITHUB_TOKEN` secret](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#about-the-github_token-secret)
as provided by GitHub in your workflow.

First, create a `Dockerfile` that uses the secret:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN --mount=type=secret,id=github_token,env=GITHUB_TOKEN ...
```

In this example, the secret name is `github_token`. The following workflow
exposes this secret using the `secrets` input:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          platforms: linux/amd64,linux/arm64
          tags: user/app:latest
          secrets: |
            "github_token=${{ secrets.GITHUB_TOKEN }}"
```

> [!NOTE]
> Secrets are mounted as files in the build container.
> By default, they're available at `/run/secrets/<id>`.
> You can also use the `env` option to load a secret into an environment variable,
> or the `target` option to customize the mount path.
> For details on secret mounts, see [Build secrets](../../building/secrets.md).

### Secret sources

The `docker/build-push-action` inputs for secret mounts define where the secret
value comes from. The Dockerfile `RUN --mount=type=secret` options define how
the build step consumes the secret.

| Action input                           | Source                             | Equivalent Buildx option                 |
| -------------------------------------- | ---------------------------------- | ---------------------------------------- |
| `secrets: MY_SECRET=value`             | Inline value from the workflow     | `--secret id=MY_SECRET,src=<temp-file>`  |
| `secret-envs: MY_SECRET=MY_ENV_VAR`    | Environment variable on the runner | `--secret id=MY_SECRET,env=MY_ENV_VAR`   |
| `secret-files: MY_SECRET=./secret.txt` | File on the runner                 | `--secret id=MY_SECRET,src=./secret.txt` |

For example, `RUN --mount=type=secret,id=MY_SECRET` mounts the secret as a file
at `/run/secrets/MY_SECRET`. To expose the same secret as an environment
variable for a `RUN` instruction, use the `env` option in the Dockerfile:
`RUN --mount=type=secret,id=MY_SECRET,env=MY_SECRET`.

### Using environment variables as secret sources

The `secret-envs` input reads secrets from environment variables on the GitHub
Actions runner. Use it when a previous workflow step sets an environment
variable, or when you want to map a runner environment variable to a different
secret ID for the build.

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@{{% param "checkout_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
        with:
          context: .
          secret-envs: |
            sentry_token=SENTRY_AUTH_TOKEN
          tags: user/app:latest
```

In your Dockerfile, mount the secret and expose it as an environment variable
for the command that needs it:

```dockerfile
# syntax=docker/dockerfile:1
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci

COPY . .

RUN --mount=type=secret,id=sentry_token,env=SENTRY_AUTH_TOKEN \
    npm run build
```

### Using secret files

The `secret-files` input lets you mount existing files as secrets in your build.
This is useful when you need to use credential files that are generated during your workflow,
or when you need to mount configuration files like `.npmrc` or `.pypirc` that are already in the expected format.

The key difference between `secrets`, `secret-envs`, and `secret-files`:

- `secrets`: Pass secret values as strings from the workflow.
- `secret-envs`: Read secret values from environment variables on the runner.
- `secret-files`: Mount existing files from the runner's filesystem.

#### Example: Using .npmrc for private npm packages

If your build needs to install packages from a private npm registry,
you can create an `.npmrc` file and mount it as a secret:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@{{% param "checkout_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Create .npmrc file
        run: |
          echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > .npmrc

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          context: .
          secret-files: |
            npmrc=./.npmrc
          tags: user/app:latest
```

In your Dockerfile, mount the secret file to the expected location:

```dockerfile
# syntax=docker/dockerfile:1
FROM node:20-alpine

WORKDIR /app

COPY package*.json ./

RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
    npm ci

COPY . .

RUN npm run build
```

If a `RUN` instruction uses a non-root user, set `uid`, `gid`, or `mode` on the
secret mount so the user can read the mounted file:

```dockerfile
RUN --mount=type=secret,id=npmrc,target=/home/node/.npmrc,uid=1000,gid=1000 \
    npm ci
```

#### Example: Using dynamically generated credentials

You can generate credential files from multiple secrets and mount them:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@{{% param "checkout_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Create credentials file
        run: |
          cat <<EOF > aws-credentials
          [default]
          aws_access_key_id = ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_access_key = ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          EOF

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          context: .
          secret-files: |
            aws=./aws-credentials
          tags: user/app:latest
```

In your Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine

RUN apk add --no-cache aws-cli

RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
    aws s3 cp s3://my-private-bucket/data.tar.gz /tmp/
```

### Multi-line secrets

If you're using [GitHub secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets)
and need to handle multi-line value, you will need to place the key-value pair
between quotes:

```yaml
secrets: |
  "MYSECRET=${{ secrets.GPG_KEY }}"
  GIT_AUTH_TOKEN=abcdefghi,jklmno=0123456789
  "MYSECRET=aaaaaaaa
  bbbbbbb
  ccccccccc"
  FOO=bar
  "EMPTYLINE=aaaa

  bbbb
  ccc"
  "JSON_SECRET={""key1"":""value1"",""key2"":""value2""}"
```

| Key              | Value                               |
| ---------------- | ----------------------------------- |
| `MYSECRET`       | `***********************`           |
| `GIT_AUTH_TOKEN` | `abcdefghi,jklmno=0123456789`       |
| `MYSECRET`       | `aaaaaaaa\nbbbbbbb\nccccccccc`      |
| `FOO`            | `bar`                               |
| `EMPTYLINE`      | `aaaa\n\nbbbb\nccc`                 |
| `JSON_SECRET`    | `{"key1":"value1","key2":"value2"}` |

> [!NOTE]
>
> Double escapes are needed for quote signs.

## SSH mounts

SSH mounts let you authenticate with SSH servers.
For example to perform a `git clone`,
or to fetch application packages from a private repository.

The following Dockerfile example uses an SSH mount
to fetch Go modules from a private GitHub repository.

```dockerfile {collapse=1}
# syntax=docker/dockerfile:1

ARG GO_VERSION="{{% param example_go_version %}}"

FROM golang:${GO_VERSION}-alpine AS base
ENV CGO_ENABLED=0
ENV GOPRIVATE="github.com/foo/*"
RUN apk add --no-cache file git rsync openssh-client
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
WORKDIR /src

FROM base AS vendor
# this step configure git and checks the ssh key is loaded
RUN --mount=type=ssh <<EOT
  set -e
  echo "Setting Git SSH protocol"
  git config --global url."git@github.com:".insteadOf "https://github.com/"
  (
    set +e
    ssh -T git@github.com
    if [ ! "$?" = "1" ]; then
      echo "No GitHub SSH key loaded exiting..."
      exit 1
    fi
  )
EOT
# this one download go modules
RUN --mount=type=bind,target=. \
    --mount=type=cache,target=/go/pkg/mod \
    --mount=type=ssh \
    go mod download -x

FROM vendor AS build
RUN --mount=type=bind,target=. \
    --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache \
    go build ...
```

To build this Dockerfile, you must specify an SSH mount that the builder can
use in the steps with `--mount=type=ssh`.

The following GitHub Action workflow uses the `MrSquaare/ssh-setup-action`
third-party action to bootstrap SSH setup on the GitHub runner. The action
creates a private key defined by the GitHub Action secret `SSH_GITHUB_PPK` and
adds it to the SSH agent socket file at `SSH_AUTH_SOCK`. The SSH mount in the
build step assume `SSH_AUTH_SOCK` by default, so there's no need to specify the
ID or path for the SSH agent socket explicitly.

{{< tabs >}}
{{< tab name="`docker/build-push-action`" >}}

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up SSH
        uses: MrSquaare/ssh-setup-action@2d028b70b5e397cf8314c6eaea229a6c3e34977a # v3.1.0
        with:
          host: github.com
          private-key: ${{ secrets.SSH_GITHUB_PPK }}
          private-key-name: github-ppk

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          ssh: default
          push: true
          tags: user/app:latest
```

{{< /tab >}}
{{< tab name="`docker/bake-action`" >}}

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Set up SSH
        uses: MrSquaare/ssh-setup-action@2d028b70b5e397cf8314c6eaea229a6c3e34977a # v3.1.0
        with:
          host: github.com
          private-key: ${{ secrets.SSH_GITHUB_PPK }}
          private-key-name: github-ppk

      - name: Build
        uses: docker/bake-action@{{% param "bake_action_version" %}}
        with:
          set: |
            *.ssh=default
```

{{< /tab >}}
{{< /tabs >}}


---

# Share built image between jobs with GitHub Actions

*Sección: Build*

As each job is isolated in its own runner, you can't use your built image
between jobs, except if you're using [self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners)
or [Docker Build Cloud](/build-cloud).
However, you can [pass data between jobs](https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts#passing-data-between-jobs-in-a-workflow)
in a workflow using the [actions/upload-artifact](https://github.com/actions/upload-artifact)
and [actions/download-artifact](https://github.com/actions/download-artifact)
actions:

> [!NOTE]
>
> This workflow supports only single-platform images because the Docker exporter
> doesn't support manifest lists. For multi-platform images, push the image to a
> registry. If a later job rebuilds the image before pushing it, configure a
> [shared cache backend](cache.md) to reuse the earlier build results. See also
> [Multi-platform image with GitHub Actions](multi-platform.md).

```yaml
name: ci

on:
  push:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and export
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          tags: myimage:latest
          outputs: type=docker,dest=${{ runner.temp }}/myimage.tar

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: myimage
          path: ${{ runner.temp }}/myimage.tar

  use:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: myimage
          path: ${{ runner.temp }}

      - name: Load image
        run: |
          docker load --input ${{ runner.temp }}/myimage.tar
          docker image ls -a
```


---

# Test before push with GitHub Actions

*Sección: Build*

In some cases, you might want to validate that the image works as expected
before pushing it. The following workflow implements several steps to achieve
this:

1. Build and export the image to Docker
2. Test your image
3. Multi-platform build and push the image

```yaml
name: ci

on:
  push:

env:
  TEST_TAG: user/app:test
  LATEST_TAG: user/app:latest

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and export to Docker
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          load: true
          tags: ${{ env.TEST_TAG }}

      - name: Test
        run: |
          docker run --rm ${{ env.TEST_TAG }}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ env.LATEST_TAG }}
```

> [!NOTE]
>
> The `linux/amd64` image is only built once in this workflow. The image is
> built once, and the following steps use the internal cache from the first
> `Build and push` step. The second `Build and push` step only builds
> `linux/arm64`.


---

# Update Docker Hub description with GitHub Actions

*Sección: Build*

You can update the Docker Hub repository description using a third party action
called [Docker Hub Description](https://github.com/peter-evans/dockerhub-description)
with this action:

```yaml
name: ci

on:
  push:

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Set up QEMU
        uses: docker/setup-qemu-action@{{% param "setup_qemu_action_version" %}}

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          push: true
          tags: user/app:latest

      - name: Update repo description
        uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4.0.0
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
          repository: user/app
```


---

# Core concepts

*Sección: Build*




---

# Build context

*Sección: Build*

The `docker build` and `docker buildx build` commands build Docker images from
a [Dockerfile](dockerfile.md) and a context.

## What is a build context?

The build context is the set of files that your build can access.
The positional argument that you pass to the build command specifies the
context that you want to use for the build:

```console
$ docker build [OPTIONS] PATH | URL | -
                         ^^^^^^^^^^^^^^
```

You can pass any of the following inputs as the context for a build:

- The relative or absolute path to a local directory
- A remote URL of a Git repository, tarball, or plain-text file
- A plain-text file or tarball piped to the `docker build` command through standard input

### Filesystem contexts

When your build context is a local directory, a remote Git repository, or a tar
file, then that becomes the set of files that the builder can access during the
build. Build instructions such as `COPY` and `ADD` can refer to any of the
files and directories in the context.

A filesystem build context is processed recursively:

- When you specify a local directory or a tarball, all subdirectories are included
- When you specify a remote Git repository, the repository and all submodules are included

For more information about the different types of filesystem contexts that you
can use with your builds, see:

- [Local files](#local-context)
- [Git repositories](#git-repositories)
- [Remote tarballs](#remote-tarballs)

### Text file contexts

When your build context is a plain-text file, the builder interprets the file
as a Dockerfile. With this approach, the build doesn't use a filesystem context.

For more information, see [empty build context](#empty-context).

## Local context

To use a local build context, you can specify a relative or absolute filepath
to the `docker build` command. The following example shows a build command that
uses the current directory (`.`) as a build context:

```console
$ docker build .
...
#16 [internal] load build context
#16 sha256:23ca2f94460dcbaf5b3c3edbaaa933281a4e0ea3d92fe295193e4df44dc68f85
#16 transferring context: 13.16MB 2.2s done
...
```

This makes files and directories in the current working directory available to
the builder. The builder loads the files it needs from the build context when
needed.

You can also use local tarballs as build context, by piping the tarball
contents to the `docker build` command. See [Tarballs](#local-tarballs).

### Local directories

Consider the following directory structure:

```text
.
├── index.ts
├── src/
├── Dockerfile
├── package.json
└── package-lock.json
```

Dockerfile instructions can reference and include these files in the build if
you pass this directory as a context.

```dockerfile
# syntax=docker/dockerfile:1
FROM node:latest
WORKDIR /src
COPY package.json package-lock.json .
RUN npm ci
COPY index.ts src .
```

```console
$ docker build .
```

### Local context with Dockerfile from stdin

Use the following syntax to build an image using files on your local
filesystem, while using a Dockerfile from stdin.

```console
$ docker build -f- <PATH>
```

The syntax uses the -f (or --file) option to specify the Dockerfile to use, and
it uses a hyphen (-) as filename to instruct Docker to read the Dockerfile from
stdin.

The following example uses the current directory (.) as the build context, and
builds an image using a Dockerfile passed through stdin using a here-document.

```bash
# create a directory to work in
mkdir example
cd example

# create an example file
touch somefile.txt

# build an image using the current directory as context
# and a Dockerfile passed through stdin
docker build -t myimage:latest -f- . <<EOF
FROM busybox
COPY somefile.txt ./
RUN cat /somefile.txt
EOF
```

### Local tarballs

When you pipe a tarball to the build command, the build uses the contents of
the tarball as a filesystem context.

For example, given the following project directory:

```text
.
├── Dockerfile
├── Makefile
├── README.md
├── main.c
├── scripts
├── src
└── test.Dockerfile
```

You can create a tarball of the directory and pipe it to the build for use as
a context:

```console
$ tar czf foo.tar.gz *
$ docker build - < foo.tar.gz
```

The build resolves the Dockerfile from the tarball context. You can use the
`--file` flag to specify the name and location of the Dockerfile relative to
the root of the tarball. The following command builds using `test.Dockerfile`
in the tarball:

```console
$ docker build --file test.Dockerfile - < foo.tar.gz
```

## Remote context

You can specify the address of a remote Git repository, tarball, or plain-text
file as your build context.

- For Git repositories, the builder automatically clones the repository. See
  [Git repositories](#git-repositories).
- For tarballs, the builder downloads and extracts the contents of the tarball.
  See [Tarballs](#remote-tarballs).

If the remote tarball is a text file, the builder receives no [filesystem
context](#filesystem-contexts), and instead assumes that the remote
file is a Dockerfile. See [Empty build context](#empty-context).

### Git repositories

When you pass a URL pointing to the location of a Git repository as an argument
to `docker build`, the builder uses the repository as the build context.

The builder performs a shallow clone of the repository, downloading only
the HEAD commit, not the entire history.

The builder recursively clones the repository and any submodules it contains.

```console
$ docker build https://github.com/user/myrepo.git
```

By default, the builder clones the latest commit on the default branch of the
repository that you specify.

#### URL fragments

You can append URL fragments to the Git repository address to make the builder
clone a specific branch, tag, and subdirectory of a repository.

The format of the URL fragment is `#ref:dir`, where:

- `ref` is the name of the branch, tag, or commit hash
- `dir` is a subdirectory inside the repository

For example, the following command uses the `container` branch,
and the `docker` subdirectory in that branch, as the build context:

```console
$ docker build https://github.com/user/myrepo.git#container:docker
```

The following table represents all the valid suffixes with their build
contexts:

| Build Syntax Suffix            | Commit Used                   | Build Context Used |
| ------------------------------ | ----------------------------- | ------------------ |
| `myrepo.git`                   | `refs/heads/<default branch>` | `/`                |
| `myrepo.git#mytag`             | `refs/tags/mytag`             | `/`                |
| `myrepo.git#mybranch`          | `refs/heads/mybranch`         | `/`                |
| `myrepo.git#pull/42/head`      | `refs/pull/42/head`           | `/`                |
| `myrepo.git#:myfolder`         | `refs/heads/<default branch>` | `/myfolder`        |
| `myrepo.git#master:myfolder`   | `refs/heads/master`           | `/myfolder`        |
| `myrepo.git#mytag:myfolder`    | `refs/tags/mytag`             | `/myfolder`        |
| `myrepo.git#mybranch:myfolder` | `refs/heads/mybranch`         | `/myfolder`        |

When you use a commit hash as the `ref` in the URL fragment, use the full,
40-character string SHA-1 hash of the commit. A short hash, for example a hash
truncated to 7 characters, is not supported.

```bash
# ✅ The following works:
docker build github.com/docker/buildx#d4f088e689b41353d74f1a0bfcd6d7c0b213aed2
# ❌ The following doesn't work because the commit hash is truncated:
docker build github.com/docker/buildx#d4f088e
```

#### URL queries

{{< summary-bar feature_name="Build URL Queries" >}}

URL queries are more structured and recommended over [URL fragments](#url-fragments):

```console
$ docker buildx build 'https://github.com/user/myrepo.git?branch=container&subdir=docker'
```

| Build syntax suffix                          | Commit used                   | Build context used |
| -------------------------------------------- | ----------------------------- | ------------------ |
| `myrepo.git`                                 | `refs/heads/<default branch>` | `/`                |
| `myrepo.git?tag=mytag`                       | `refs/tags/mytag`             | `/`                |
| `myrepo.git?branch=mybranch`                 | `refs/heads/mybranch`         | `/`                |
| `myrepo.git?ref=pull/42/head`                | `refs/pull/42/head`           | `/`                |
| `myrepo.git?subdir=myfolder`                 | `refs/heads/<default branch>` | `/myfolder`        |
| `myrepo.git?branch=master&subdir=myfolder`   | `refs/heads/master`           | `/myfolder`        |
| `myrepo.git?tag=mytag&subdir=myfolder`       | `refs/tags/mytag`             | `/myfolder`        |
| `myrepo.git?branch=mybranch&subdir=myfolder` | `refs/heads/mybranch`         | `/myfolder`        |

A commit hash can be specified as a `checksum` (alias `commit`) query, along with
`tag`, `branch`, or `ref` queries to verify that the reference resolves to the
expected commit:

```console
$ docker buildx build 'https://github.com/moby/buildkit.git?tag=v0.21.1&checksum=66735c67'
```

If it doesn't match, the build fails:

```console
$ docker buildx build 'https://github.com/user/myrepo.git?tag=v0.1.0&commit=deadbeef'
...
#3 [internal] load git source https://github.com/user/myrepo.git?tag=v0.1.0-rc1&commit=deadbeef
#3 0.484 bb41e835b6c3523c7c45b248cf4b45e7f862bc42       refs/tags/v0.1.0
#3 ERROR: expected checksum to match deadbeef, got bb41e835b6c3523c7c45b248cf4b45e7f862bc42
```

> [!NOTE]
>
> Short commit hash is supported with `checksum` (alias `commit`) query but for
> `ref`, only the full hash of the commit is supported.

#### Keep `.git` directory

By default, BuildKit doesn't keep the `.git` directory when using Git contexts.
You can configure BuildKit to keep the directory by setting the
[`BUILDKIT_CONTEXT_KEEP_GIT_DIR` build argument](dockerfile.md#buildkit-built-in-build-args).
This can be useful to if you want to retrieve Git information during your build:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
WORKDIR /src
RUN --mount=target=. \
  make REVISION=$(git rev-parse HEAD) build
```

```console
$ docker build \
  --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
  https://github.com/user/myrepo.git#main
```

#### Private repositories

When you specify a Git context that's also a private repository, the builder
needs you to provide the necessary authentication credentials. You can use
either SSH or token-based authentication.

Buildx automatically detects and uses SSH credentials if the Git context you
specify is an SSH or Git address. By default, this uses `$SSH_AUTH_SOCK`.
You can configure the SSH credentials to use with the
[`--ssh` flag](/reference/cli/docker/buildx/build/#ssh).

```console
$ docker buildx build --ssh default git@github.com:user/private.git
```

If you want to use token-based authentication instead, you can pass the token
using the
[`--secret` flag](/reference/cli/docker/buildx/build/#secret).

```console
$ GIT_AUTH_TOKEN=<token> docker buildx build \
  --secret id=GIT_AUTH_TOKEN \
  https://github.com/user/private.git
```

> [!NOTE]
>
> Don't use `--build-arg` for secrets.

### Remote context with Dockerfile from stdin

Use the following syntax to build an image using files on your local
filesystem, while using a Dockerfile from stdin.

```console
$ docker build -f- <URL>
```

The syntax uses the -f (or --file) option to specify the Dockerfile to use, and
it uses a hyphen (-) as filename to instruct Docker to read the Dockerfile from
stdin.

This can be useful in situations where you want to build an image from a
repository that doesn't contain a Dockerfile. Or if you want to build with a
custom Dockerfile, without maintaining your own fork of the repository.

The following example builds an image using a Dockerfile from stdin, and adds
the `hello.c` file from the [hello-world](https://github.com/docker-library/hello-world)
repository on GitHub.

```bash
docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF
FROM busybox
COPY hello.c ./
EOF
```

### Remote tarballs

If you pass the URL to a remote tarball, the URL itself is sent to the builder.

```console
$ docker build http://server/context.tar.gz
#1 [internal] load remote build context
#1 DONE 0.2s

#2 copy /context /
#2 DONE 0.1s
...
```

The download operation will be performed on the host where the BuildKit daemon
is running. Note that if you're using a remote Docker context or a remote
builder, that's not necessarily the same machine as where you issue the build
command. BuildKit fetches the `context.tar.gz` and uses it as the build
context. Tarball contexts must be tar archives conforming to the standard `tar`
Unix format and can be compressed with any one of the `xz`, `bzip2`, `gzip` or
`identity` (no compression) formats.

## Empty context

When you use a text file as the build context, the builder interprets the file
as a Dockerfile. Using a text file as context means that the build has no
filesystem context.

You can build with an empty build context when your Dockerfile doesn't depend
on any local files.

### How to build without a context

You can pass the text file using a standard input stream, or by pointing at the
URL of a remote text file.

{{< tabs >}}
{{< tab name="Unix pipe" >}}

```console
$ docker build - < Dockerfile
```

{{< /tab >}}
{{< tab name="PowerShell" >}}

```powershell
Get-Content Dockerfile | docker build -
```

{{< /tab >}}
{{< tab name="Heredocs" >}}

```bash
docker build -t myimage:latest - <<EOF
FROM busybox
RUN echo "hello world"
EOF
```

{{< /tab >}}
{{< tab name="Remote file" >}}

```console
$ docker build https://raw.githubusercontent.com/dvdksn/clockbox/main/Dockerfile
```

{{< /tab >}}
{{< /tabs >}}

When you build without a filesystem context, Dockerfile instructions such as
`COPY` can't refer to local files:

```console
$ ls
main.c
$ docker build -<<< $'FROM scratch\nCOPY main.c .'
[+] Building 0.0s (4/4) FINISHED
 => [internal] load build definition from Dockerfile       0.0s
 => => transferring dockerfile: 64B                        0.0s
 => [internal] load .dockerignore                          0.0s
 => => transferring context: 2B                            0.0s
 => [internal] load build context                          0.0s
 => => transferring context: 2B                            0.0s
 => ERROR [1/1] COPY main.c .                              0.0s
------
 > [1/1] COPY main.c .:
------
Dockerfile:2
--------------------
   1 |     FROM scratch
   2 | >>> COPY main.c .
   3 |
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 7ab2bb61-0c28-432e-abf5-a4c3440bc6b6::4lgfpdf54n5uqxnv9v6ymg7ih: "/main.c": not found
```

## .dockerignore files

You can use a `.dockerignore` file to exclude files or directories from the
build context.

```text
# .dockerignore
node_modules
bar
```

This helps avoid sending unwanted files and directories to the builder,
improving build speed, especially when using a remote builder.

### Filename and location

When you run a build command, the build client looks for a file named
`.dockerignore` in the root directory of the context. If this file exists, the
files and directories that match patterns in the files are removed from the
build context before it's sent to the builder.

If you use multiple Dockerfiles, you can use different ignore-files for each
Dockerfile. You do so using a special naming convention for the ignore-files.
Place your ignore-file in the same directory as the Dockerfile, and prefix the
ignore-file with the name of the Dockerfile, as shown in the following example.

```text
.
├── index.ts
├── src/
├── docker
│   ├── build.Dockerfile
│   ├── build.Dockerfile.dockerignore
│   ├── lint.Dockerfile
│   ├── lint.Dockerfile.dockerignore
│   ├── test.Dockerfile
│   └── test.Dockerfile.dockerignore
├── package.json
└── package-lock.json
```

A Dockerfile-specific ignore-file takes precedence over the `.dockerignore`
file at the root of the build context if both exist.

### Syntax

The `.dockerignore` file is a newline-separated list of patterns similar to the
file globs of Unix shells. Leading and trailing slashes in ignore patterns are
disregarded. The following patterns all exclude a file or directory named `bar`
in the subdirectory `foo` under the root of the build context:

- `/foo/bar/`
- `/foo/bar`
- `foo/bar/`
- `foo/bar`

If a line in `.dockerignore` file starts with `#` in column 1, then this line
is considered as a comment and is ignored before interpreted by the CLI.

```gitignore
#/this/is/a/comment
```

If you're interested in learning the precise details of the `.dockerignore`
pattern matching logic, check out the
[moby/patternmatcher repository](https://github.com/moby/patternmatcher/tree/main/ignorefile)
on GitHub, which contains the source code.

#### Matching

The following code snippet shows an example `.dockerignore` file.

```text
# comment
*/temp*
*/*/temp*
temp?
```
<!-- vale off -->

This file causes the following build behavior:

| Rule        | Behavior                                                                                                                                                                                                      |
| :---------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `# comment` | Ignored.                                                                                                                                                                                                      |
| `*/temp*`   | Exclude files and directories whose names start with `temp` in any immediate subdirectory of the root. For example, the plain file `/somedir/temporary.txt` is excluded, as is the directory `/somedir/temp`. |
| `*/*/temp*` | Exclude files and directories starting with `temp` from any subdirectory that is two levels below the root. For example, `/somedir/subdir/temporary.txt` is excluded.                                         |
| `temp?`     | Exclude files and directories in the root directory whose names are a one-character extension of `temp`. For example, `/tempa` and `/tempb` are excluded.                                                     |

<!-- vale on -->

Matching is done using Go's
[`filepath.Match` function](https://golang.org/pkg/path/filepath#Match) rules.
A preprocessing step uses Go's
[`filepath.Clean` function](https://golang.org/pkg/path/filepath/#Clean)
to trim whitespace and remove `.` and `..`.
Lines that are blank after preprocessing are ignored.

> [!NOTE]
>
> For historical reasons, the pattern `.` is ignored.

Beyond Go's `filepath.Match` rules, Docker also supports a special wildcard
string `**` that matches any number of directories (including zero). For
example, `**/*.go` excludes all files that end with `.go` found anywhere in the
build context.

You can use the `.dockerignore` file to exclude the `Dockerfile` and
`.dockerignore` files. These files are still sent to the builder as they're
needed for running the build. But you can't copy the files into the image using
`ADD`, `COPY`, or bind mounts.

#### Negating matches

You can prepend lines with a `!` (exclamation mark) to make exceptions to
exclusions. The following is an example `.dockerignore` file that uses this
mechanism:

```text
*.md
!README.md
```

All markdown files right under the context directory _except_ `README.md` are
excluded from the context. Note that markdown files under subdirectories are
still included.

The placement of `!` exception rules influences the behavior: the last line of
the `.dockerignore` that matches a particular file determines whether it's
included or excluded. Consider the following example:

```text
*.md
!README*.md
README-secret.md
```

No markdown files are included in the context except README files other than
`README-secret.md`.

Now consider this example:

```text
*.md
README-secret.md
!README*.md
```

All of the README files are included. The middle line has no effect because
`!README*.md` matches `README-secret.md` and comes last.

## Named contexts

In addition to the default build context (the positional argument to the
`docker build` command), you can also pass additional named contexts to builds.

Named contexts are specified using the `--build-context` flag, followed by a
name-value pair. This lets you include files and directories from multiple
sources during the build, while keeping them logically separated.

```console
$ docker build --build-context docs=./docs .
```

In this example:

- The named `docs` context points to the `./docs` directory.
- The default context (`.`) points to the current working directory.

### Using named contexts in a Dockerfile

Dockerfile instructions can reference named contexts as if they are stages in a
multi-stage build.

For example, the following Dockerfile:

1. Uses a `COPY` instruction to copy files from the default context into the
   current build stage.
2. Bind mounts the files in a named context to process the files as part of the
   build.

```dockerfile
# syntax=docker/dockerfile:1
FROM buildbase
WORKDIR /app

# Copy all files from the default context into /app/src in the build container
COPY . /app/src
RUN make bin

# Mount the files from the named "docs" context to build the documentation
RUN --mount=from=docs,target=/app/docs \
    make manpages
```

### Use cases for named contexts

Using named contexts allows for greater flexibility and efficiency when
building Docker images. Here are some scenarios where using named contexts can
be useful:

#### Example: combine local and remote sources

You can define separate named contexts for different types of sources. For
example, consider a project where the application source code is local, but the
deployment scripts are stored in a Git repository:

```console
$ docker build --build-context scripts=https://github.com/user/deployment-scripts.git .
```

In the Dockerfile, you can use these contexts independently:

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine:latest

# Copy application code from the main context
COPY . /opt/app

# Run deployment scripts using the remote "scripts" context
RUN --mount=from=scripts,target=/scripts /scripts/main.sh
```

#### Example: dynamic builds with custom dependencies

In some scenarios, you might need to dynamically inject configuration files or
dependencies into the build from external sources. Named contexts make this
straightforward by allowing you to mount different configurations without
modifying the default build context.

```console
$ docker build --build-context config=./configs/prod .
```

Example Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1
FROM nginx:alpine

# Use the "config" context for environment-specific configurations
COPY --from=config nginx.conf /etc/nginx/nginx.conf
```

#### Example: pin or override images

You can refer to named contexts in a Dockerfile the same way you can refer to
an image. That means you can change an image reference in your Dockerfile by
overriding it with a named context. For example, given the following
Dockerfile:

```dockerfile
FROM alpine:{{% param example_alpine_version %}}
```

If you want to force image reference to resolve to a different version, without
changing the Dockerfile, you can pass a context with the same name to the
build. For example:

```console
docker buildx build --build-context alpine:{{% param example_alpine_version %}}=docker-image://alpine:edge .
```

The `docker-image://` prefix marks the context as an image reference. The
reference can be a local image or an image in your registry.

### Named contexts with Bake

[Bake](../bake/index.md) is a tool built into `docker build` that
lets you manage your build configuration with a configuration file. Bake fully
supports named contexts.

To define named contexts in a Bake file:

```hcl {title=docker-bake.hcl}
target "app" {
  contexts = {
    docs = "./docs"
  }
}
```

This is equivalent to the following CLI invocation:

```console
$ docker build --build-context docs=./docs .
```

#### Linking targets with named contexts

In addition to making complex builds more manageable, Bake also provides
additional features on top of what you can do with `docker build` on the CLI.
You can use named contexts to create build pipelines, where one target depends
on and builds on top of another. For example, consider a Docker build setup
where you have two Dockerfiles:

- `base.Dockerfile`: for building a base image
- `app.Dockerfile`: for building an application image

The `app.Dockerfile` uses the image produced by `base.Dockerfile` as it's base
image:

```dockerfile {title=app.Dockerfile}
FROM mybaseimage
```

Normally, you would have to build the base image first, and then either load it
to Docker Engine's local image store or push it to a registry. With Bake, you
can reference other targets directly, creating a dependency between the `app`
target and the `base` target.

```hcl {title=docker-bake.hcl}
target "base" {
  dockerfile = "base.Dockerfile"
}

target "app" {
  dockerfile = "app.Dockerfile"
  contexts = {
    # the target: prefix indicates that 'base' is a Bake target
    mybaseimage = "target:base"
  }
}
```

With this configuration, references to `mybaseimage` in `app.Dockerfile` use
the results from building the `base` target. Building the `app` target will
also trigger a rebuild of `mybaseimage`, if necessary:

```console
$ docker buildx bake app
```

### Further reading

For more information about working with named contexts, see:

- [`--build-context` CLI reference](/reference/cli/docker/buildx/build/#build-context)
- [Using Bake with additional contexts](../bake/contexts.md)


---

# Dockerfile overview

*Sección: Build*

<!-- vale Docker.We = NO -->

## Dockerfile

It all starts with a Dockerfile.

Docker builds images by reading the instructions from a Dockerfile. A
Dockerfile is a text file containing instructions for building your source
code. The Dockerfile instruction syntax is defined by the specification
reference in the [Dockerfile reference](dockerfile.md).

Here are the most common types of instructions:

| Instruction                                               | Description                                                                                                                                                                                              |
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`FROM <image>`](dockerfile.md#from)           | Defines a base for your image.                                                                                                                                                                           |
| [`RUN <command>`](dockerfile.md#run)           | Executes any commands in a new layer on top of the current image and commits the result. `RUN` also has a shell form for running commands.                                                               |
| [`WORKDIR <directory>`](dockerfile.md#workdir) | Sets the working directory for any `RUN`, `CMD`, `ENTRYPOINT`, `COPY`, and `ADD` instructions that follow it in the Dockerfile.                                                                          |
| [`COPY <src> <dest>`](dockerfile.md#copy)      | Copies new files or directories from `<src>` and adds them to the filesystem of the container at the path `<dest>`.                                                                                      |
| [`CMD <command>`](dockerfile.md#cmd)           | Lets you define the default program that is run once you start the container based on this image. Each Dockerfile only has one `CMD`, and only the last `CMD` instance is respected when multiple exist. |

Dockerfiles are crucial inputs for image builds and can facilitate automated,
multi-layer image builds based on your unique configurations. Dockerfiles can
start simple and grow with your needs to support more complex scenarios.

### Filename

The default filename to use for a Dockerfile is `Dockerfile`, without a file
extension. Using the default name allows you to run the `docker build` command
without having to specify additional command flags.

Some projects may need distinct Dockerfiles for specific purposes. A common
convention is to name these `<something>.Dockerfile`. You can specify the
Dockerfile filename using the `--file` flag for the `docker build` command.
Refer to the
[`docker build` CLI reference](/reference/cli/docker/buildx/build/#file)
to learn about the `--file` flag.

> [!NOTE]
>
> We recommend using the default (`Dockerfile`) for your project's primary
> Dockerfile.

## Docker images

Docker images consist of layers. Each layer is the result of a build
instruction in the Dockerfile. Layers are stacked sequentially, and each one is
a delta representing the changes applied to the previous layer.

### Example

Here's what a typical workflow for building applications with Docker looks like.

The following example code shows a small "Hello World" application written in
Python, using the Flask framework.

```python
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"
```

In order to ship and deploy this application without Docker Build, you would
need to make sure that:

- The required runtime dependencies are installed on the server
- The Python code gets uploaded to the server's filesystem
- The server starts your application, using the necessary parameters

The following Dockerfile creates a container image, which has all the
dependencies installed and that automatically starts your application.

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:22.04

# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip
RUN pip install flask==3.0.*

# install app
COPY hello.py /

# final configuration
ENV FLASK_APP=hello
EXPOSE 8000
CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]
```

Here's a breakdown of what this Dockerfile does:

- [Dockerfile syntax](#dockerfile-syntax)
- [Base image](#base-image)
- [Environment setup](#environment-setup)
- [Comments](#comments)
- [Installing dependencies](#installing-dependencies)
- [Copying files](#copying-files)
- [Setting environment variables](#setting-environment-variables)
- [Exposed ports](#exposed-ports)
- [Starting the application](#starting-the-application)

### Dockerfile syntax

The first line to add to a Dockerfile is a [`# syntax` parser directive](dockerfile.md#syntax).
While optional, this directive instructs the Docker builder what syntax to use
when parsing the Dockerfile, and allows older Docker versions with [BuildKit enabled](../buildkit/index.md#getting-started)
to use a specific [Dockerfile frontend](../buildkit/frontend.md) before
starting the build. [Parser directives](dockerfile.md#parser-directives)
must appear before any other comment, whitespace, or Dockerfile instruction in
your Dockerfile, and should be the first line in Dockerfiles.

```dockerfile
# syntax=docker/dockerfile:1
```

> [!TIP]
>
> We recommend using `docker/dockerfile:1`, which always points to the latest
> release of the version 1 syntax. BuildKit automatically checks for updates of
> the syntax before building, making sure you are using the most current version.

### Base image

The line following the syntax directive defines what base image to use:

```dockerfile
FROM ubuntu:22.04
```

The [`FROM` instruction](dockerfile.md#from) sets your base
image to the 22.04 release of Ubuntu. All instructions that follow are executed
in this base image: an Ubuntu environment. The notation `ubuntu:22.04`, follows
the `name:tag` standard for naming Docker images. When you build images, you
use this notation to name your images. There are many public images you can
leverage in your projects, by importing them into your build steps using the
Dockerfile `FROM` instruction.

[Docker Hub](https://hub.docker.com/search?badges=official)
contains a large set of official images that you can use for this purpose.

### Environment setup

The following line executes a build command inside the base image.

```dockerfile
# install app dependencies
RUN apt-get update && apt-get install -y python3 python3-pip
```

This [`RUN` instruction](dockerfile.md#run) executes a
shell in Ubuntu that updates the APT package index and installs Python tools in
the container.

### Comments

Note the `# install app dependencies` line. This is a comment. Comments in
Dockerfiles begin with the `#` symbol. As your Dockerfile evolves, comments can
be instrumental to document how your Dockerfile works for any future readers
and editors of the file, including your future self.

> [!NOTE]
>
> You might've noticed that comments are denoted using the same symbol as the
> [syntax directive](#dockerfile-syntax) on the first line of the file.
> The symbol is only interpreted as a directive if the pattern matches a
> directive and appears at the beginning of the Dockerfile. Otherwise, it's
> treated as a comment.

### Installing dependencies

The second `RUN` instruction installs the `flask` dependency required by the
Python application.

```dockerfile
RUN pip install flask==3.0.*
```

A prerequisite for this instruction is that `pip` is installed into the build
container. The first `RUN` command installs `pip`, which ensures that we can
use the command to install the flask web framework.

### Copying files

The next instruction uses the
[`COPY` instruction](dockerfile.md#copy) to copy the
`hello.py` file from the local build context into the root directory of our image.

```dockerfile
COPY hello.py /
```

A [build context](context.md) is the set of files that you can access
in Dockerfile instructions such as `COPY` and `ADD`.

After the `COPY` instruction, the `hello.py` file is added to the filesystem
of the build container.

### Setting environment variables

If your application uses environment variables, you can set environment variables
in your Docker build using the [`ENV` instruction](dockerfile.md#env).

```dockerfile
ENV FLASK_APP=hello
```

This sets a Linux environment variable we'll need later. Flask, the framework
used in this example, uses this variable to start the application. Without this,
flask wouldn't know where to find our application to be able to run it.

### Exposed ports

The [`EXPOSE` instruction](dockerfile.md#expose) marks that
our final image has a service listening on port `8000`.

```dockerfile
EXPOSE 8000
```

This instruction isn't required, but it is a good practice and helps tools and
team members understand what this application is doing.

### Starting the application

Finally, [`CMD` instruction](dockerfile.md#cmd) sets the
command that is run when the user starts a container based on this image.

```dockerfile
CMD ["flask", "run", "--host", "0.0.0.0", "--port", "8000"]
```

This command starts the flask development server listening on all addresses
on port `8000`. The example here uses the "exec form" version of `CMD`.
It's also possible to use the "shell form":

```dockerfile
CMD flask run --host 0.0.0.0 --port 8000
```

There are subtle differences between these two versions,
for example in how they trap signals like `SIGTERM` and `SIGKILL`.
For more information about these differences, see
[Shell and exec form](dockerfile.md#shell-and-exec-form)

## Building

To build a container image using the Dockerfile example from the
[previous section](#example), you use the `docker build` command:

```console
$ docker build -t test:latest .
```

The `-t test:latest` option specifies the name and tag of the image.

The single dot (`.`) at the end of the command sets the
[build context](context.md) to the current directory. This means that the
build expects to find the Dockerfile and the `hello.py` file in the directory
where the command is invoked. If those files aren't there, the build fails.

After the image has been built, you can run the application as a container with
`docker run`, specifying the image name:

```console
$ docker run -p 127.0.0.1:8000:8000 test:latest
```

This publishes the container's port 8000 to `http://localhost:8000` on the
Docker host.

> [!TIP]
>
> To improve linting, code navigation, and vulnerability scanning of your Dockerfiles in Visual Studio Code
> see the [Docker DX](https://marketplace.visualstudio.com/items?itemName=docker.docker) extension.


---

# Docker Build Overview

*Sección: Build*

Docker Build implements a client-server architecture, where:

- Client: Buildx is the client and the user interface for running and managing builds.
- Server: BuildKit is the server, or builder, that handles the build execution.

When you invoke a build, the Buildx client sends a build request to the
BuildKit backend. BuildKit resolves the build instructions and executes the
build steps. The build output is either sent back to the client or uploaded to
a registry, such as Docker Hub.

Buildx and BuildKit are both installed with Docker Desktop and Docker Engine
out-of-the-box. When you invoke the `docker build` command, you're using Buildx
to run a build using the default BuildKit bundled with Docker.

## Buildx

Buildx is the CLI tool that you use to run builds. The `docker build` command
is a wrapper around Buildx. When you invoke `docker build`, Buildx interprets
the build options and sends a build request to the BuildKit backend.

The Buildx client can do more than just run builds. You can also use Buildx to
create and manage BuildKit backends, referred to as builders. It also supports
features for managing images in registries, and for running multiple builds
concurrently.

Docker Buildx is installed by default with Docker Desktop. You can also build
the CLI plugin from source, or grab a binary from the GitHub repository and
install it manually. See [Buildx README](https://github.com/docker/buildx#manual-download)
on GitHub for more information.

> [!NOTE]
> While `docker build` invokes Buildx under the hood, there are subtle
> differences between this command and the canonical `docker buildx build`.
> For details, see [Difference between `docker build` and `docker buildx build`](../builders/index.md#difference-between-docker-build-and-docker-buildx-build).

## BuildKit

BuildKit is the daemon process that executes the build workloads.

A build execution starts with the invocation of a `docker build` command.
Buildx interprets your build command and sends a build request to the BuildKit
backend. The build request includes:

- The Dockerfile
- Build arguments
- Export options
- Caching options

BuildKit resolves the build instructions and executes the build steps. While
BuildKit is executing the build, Buildx monitors the build status and prints
the progress to the terminal.

If the build requires resources from the client, such as local files or build
secrets, BuildKit requests the resources that it needs from Buildx.

This is one way in which BuildKit is more efficient compared to the legacy
builder used in earlier versions of Docker. BuildKit only requests the
resources that the build needs when they're needed. The legacy builder, in
comparison, always takes a copy of the local filesystem.

Examples of resources that BuildKit can request from Buildx include:

- Local filesystem build contexts
- Build secrets
- SSH sockets
- Registry authentication tokens

For more information about BuildKit, see [BuildKit](../buildkit/index.md).


---

# Debugging

*Sección: Build*




---

# OpenTelemetry support

*Sección: Build*

Both Buildx and BuildKit support [OpenTelemetry](https://opentelemetry.io/).

To capture the trace to [Jaeger](https://github.com/jaegertracing/jaeger),
set `JAEGER_TRACE` environment variable to the collection address using a
`driver-opt`.

First create a Jaeger container:

```console
$ docker run -d --name jaeger -p "6831:6831/udp" -p "16686:16686" --restart unless-stopped jaegertracing/all-in-one
```

Then [create a `docker-container` builder](../builders/drivers/docker-container.md)
that will use the Jaeger instance via the `JAEGER_TRACE` environment variable:

```console
$ docker buildx create --use \
  --name mybuilder \
  --driver docker-container \
  --driver-opt "network=host" \
  --driver-opt "env.JAEGER_TRACE=localhost:6831"
```

Boot and [inspect `mybuilder`](/reference/cli/docker/buildx/inspect/):

```console
$ docker buildx inspect --bootstrap
```

Buildx commands should be traced at `http://127.0.0.1:16686/`:

![OpenTelemetry Buildx Bake](../images/opentelemetry.png)


---

# Exporters overview

*Sección: Build*

Exporters save your build results to a specified output type. You specify the
exporter to use with the
[`--output` CLI option](/reference/cli/docker/buildx/build/#output).
Buildx supports the following exporters:

- `image`: exports the build result to a container image.
- `registry`: exports the build result into a container image, and pushes it to
  the specified registry.
- `local`: exports the build root filesystem into a local directory.
- `tar`: packs the build root filesystem into a local tarball.
- `oci`: exports the build result to the local filesystem in the
  [OCI image layout](https://github.com/opencontainers/image-spec/blob/v1.0.1/image-layout.md)
  format.
- `docker`: exports the build result to the local filesystem in the
  [Docker Image Specification v1.2.0](https://github.com/moby/moby/blob/v25.0.0/image/spec/v1.2.md)
  format.
- `cacheonly`: doesn't export a build output, but runs the build and creates a
  cache.

## Using exporters

To specify an exporter, use the following command syntax:

```console
$ docker buildx build --tag <registry>/<image> \
  --output type=<TYPE> .
```

Most common use cases don't require that you specify which exporter to use
explicitly. You only need to specify the exporter if you intend to customize
the output, or if you want to save it to disk. The `--load` and `--push`
options allow Buildx to infer the exporter settings to use.

For example, if you use the `--push` option in combination with `--tag`, Buildx
automatically uses the `image` exporter, and configures the exporter to push the
results to the specified registry.

To get the full flexibility out of the various exporters BuildKit has to offer,
you use the `--output` flag that lets you configure exporter options.

## Use cases

Each exporter type is designed for different use cases. The following sections
describe some common scenarios, and how you can use exporters to generate the
output that you need.

### Load to image store

Buildx is often used to build container images that can be loaded to an image
store. That's where the `docker` exporter comes in. The following example shows
how to build an image using the `docker` exporter, and have that image loaded to
the local image store, using the `--output` option:

```console
$ docker buildx build \
  --output type=docker,name=<registry>/<image> .
```

Buildx CLI will automatically use the `docker` exporter and load it to the image
store if you supply the `--tag` and `--load` options:

```console
$ docker buildx build --tag <registry>/<image> --load .
```

Building images using the `docker` driver are automatically loaded to the local
image store.

Images loaded to the image store are available to `docker run` immediately
after the build finishes, and you'll see them in the list of images when you run
the `docker images` command.

#### Load results from Docker Build Cloud

Builds that use the [cloud driver](../builders/drivers/cloud.md) run
on remote Docker Build Cloud workers. You can still load an image into Docker
Engine so that it's available to `docker run` and `docker images` without first
pushing it to a registry.

The [target Docker context](../../engine/manage-resources/contexts.md)
determines which Docker Engine image store receives the image. A local context
loads it into a local image store. A remote context loads it into the remote
Docker daemon's image store.

When you don't specify an output, Buildx leaves an untagged build result in the
cloud build cache and doesn't load it into Docker Engine. If you use `--tag`,
Buildx automatically loads the image when the build targets a single platform
and runs on one cloud node. Use `--load` to request loading explicitly. The
`--load` flag is shorthand for `--output type=docker`.

To leave a tagged result in the build cache, use `--output type=cacheonly`.
Setting `default-load=false` doesn't turn off automatic loading for a tagged
cloud build with no explicit output.

Buildx uses the standard exporter path when direct loading isn't available.
This includes multi-node or multi-platform builds, requests for more than one
distinct image output, outputs targeting different Docker contexts, and
outputs written to a file, standard output, or a directory. The standard path
also applies if the target context doesn't support direct loading.

### Push to registry

To push a built image to a container registry, you can use the `registry` or
`image` exporters.

When you pass the `--push` option to the Buildx CLI, you instruct BuildKit to
push the built image to the specified registry:

```console
$ docker buildx build --tag <registry>/<image> --push .
```

Under the hood, this uses the `image` exporter, and sets the `push` parameter.
It's the same as using the following long-form command using the `--output`
option:

```console
$ docker buildx build \
  --output type=image,name=<registry>/<image>,push=true .
```

You can also use the `registry` exporter, which does the same thing:

```console
$ docker buildx build \
  --output type=registry,name=<registry>/<image> .
```

### Export image layout to file

You can use either the `oci` or `docker` exporters to save the build results to
image layout on your local filesystem. Both of these exporters generate a tar
archive file containing the corresponding image layout. The `dest` parameter
defines the target output path for the tarball.

```console
$ docker buildx build --output type=oci,dest=./image.tar .
[+] Building 0.8s (7/7) FINISHED
 ...
 => exporting to oci image format                                                                     0.0s
 => exporting layers                                                                                  0.0s
 => exporting manifest sha256:c1ef01a0a0ef94a7064d5cbce408075730410060e253ff8525d1e5f7e27bc900        0.0s
 => exporting config sha256:eadab326c1866dd247efb52cb715ba742bd0f05b6a205439f107cf91b3abc853          0.0s
 => sending tarball                                                                                   0.0s
$ mkdir -p out && tar -C out -xf ./image.tar
$ tree out
out
├── blobs
│   └── sha256
│       ├── 9b18e9b68314027565b90ff6189d65942c0f7986da80df008b8431276885218e
│       ├── c78795f3c329dbbbfb14d0d32288dea25c3cd12f31bd0213be694332a70c7f13
│       ├── d1cf38078fa218d15715e2afcf71588ee482352d697532cf316626164699a0e2
│       ├── e84fa1df52d2abdfac52165755d5d1c7621d74eda8e12881f6b0d38a36e01775
│       └── fe9e23793a27fe30374308988283d40047628c73f91f577432a0d05ab0160de7
├── index.json
├── manifest.json
└── oci-layout
```

### Export filesystem

If you don't want to build an image from your build results, but instead export
the filesystem that was built, you can use the `local` and `tar` exporters.

The `local` exporter unpacks the filesystem into a directory structure in the
specified location. The `tar` exporter creates a tarball archive file.

```console
$ docker buildx build --output type=local,dest=<path/to/output> .
```

The `local` exporter is useful in [multi-stage builds](../building/multi-stage.md)
since it allows you to export only a minimal number of build artifacts, such as
self-contained binaries.

### Cache-only export

The `cacheonly` exporter can be used if you just want to run a build, without
exporting any output. This can be useful if, for example, you want to run a test
build. Or, if you want to run the build first, and create exports using
subsequent commands. The `cacheonly` exporter creates a build cache, so any
successive builds are instant.

```console
$ docker buildx build --output type=cacheonly
```

If you don't specify an exporter, and you don't provide short-hand options like
`--load` that automatically selects the appropriate exporter, Buildx defaults to
using the `cacheonly` exporter. Except if you build using the `docker` driver,
in which case you use the `docker` exporter.

Buildx logs a warning message when using `cacheonly` as a default:

```console
$ docker buildx build .
WARNING: No output specified with docker-container driver.
         Build result will only remain in the build cache.
         To push result image into registry use --push or
         to load image into docker use --load
```

## Multiple exporters

{{< summary-bar feature_name="Build multiple exporters" >}}

You can use multiple exporters for any given build by specifying the `--output`
flag multiple times. This requires **both Buildx and BuildKit** version 0.13.0
or later.

The following example runs a single build, using three
different exporters:

- The `registry` exporter to push the image to a registry
- The `local` exporter to extract the build results to the local filesystem
- The `--load` flag (a shorthand for the `docker` exporter) to load the results to the local image store.

```console
$ docker buildx build \
  --output type=registry,tag=<registry>/<image> \
  --output type=local,dest=<path/to/output> \
  --load .
```

## Configuration options

This section describes some configuration options available for exporters.

The options described here are common for at least two or more exporter types.
Additionally, the different exporters types support specific parameters as well.
See the detailed page about each exporter for more information about which
configuration parameters apply.

The common parameters described here are:

- [Compression](#compression)
- [OCI media type](#oci-media-types)

### Compression

When you export a compressed output, you can configure the exact compression
algorithm and level to use. While the default values provide a good
out-of-the-box experience, you can tweak the parameters to optimize for
storage versus compute costs. Changing the compression parameters can reduce storage
space required, and improve image download times, but will increase build times.

To select the compression algorithm, you can use the `compression` option. For
example, to build an `image` with `compression=zstd`:

```console
$ docker buildx build \
  --output type=image,name=<registry>/<image>,push=true,compression=zstd .
```

Use the `compression-level=<value>` option alongside the `compression` parameter
to choose a compression level for the algorithms which support it:

- 0-9 for `gzip` and `estargz`
- 0-22 for `zstd`

As a general rule, the higher the number, the smaller the resulting file will
be, and the longer the compression will take to run.

Use the `force-compression=true` option to force re-compressing layers imported
from a previous image, if the requested compression algorithm is different from
the previous compression algorithm.

> [!NOTE]
>
> The `gzip` and `estargz` compression methods use the [`compress/gzip` package](https://pkg.go.dev/compress/gzip),
> while `zstd` uses the [`github.com/klauspost/compress/zstd` package](https://github.com/klauspost/compress/tree/master/zstd).

#### zstd compression levels

When you specify `compression=zstd`, the `compression-level` parameter accepts
values from 0 to 22. BuildKit maps these values to four internal compression
levels:

| compression-level | Internal level | Approximate zstd level | Description                           |
| ----------------- | -------------- | ---------------------- | ------------------------------------- |
| 0-2               | Fastest        | ~1                     | Fastest compression, larger file size |
| 3-6 (default)     | Default        | ~3                     | Balanced compression and speed        |
| 7-8               | Better         | ~7                     | Better compression, slower            |
| 9-22              | Best           | ~11                    | Best compression, slowest             |

For example, setting `compression-level=5` and `compression-level=6` produces
the same compression output, since both map to the "Default" internal level.

### OCI media types

The `image`, `registry`, `oci` and `docker` exporters create container images.
These exporters support both Docker media types (default) and OCI media types

To export images with OCI media types set, use the `oci-mediatypes` property.

```console
$ docker buildx build \
  --output type=image,name=<registry>/<image>,push=true,oci-mediatypes=true .
```

## What's next

Read about each of the exporters to learn about how they work and how to use
them:

- [Image and registry exporters](image-registry.md)
- [OCI and Docker exporters](oci-docker.md).
- [Local and tar exporters](local-tar.md)


---

# Image and registry exporters

*Sección: Build*

The `image` exporter outputs the build result into a container image format. The
`registry` exporter is identical, but it automatically pushes the result by
setting `push=true`.

## Synopsis

Build a container image using the `image` and `registry` exporters:

```console
$ docker buildx build --output type=image[,parameters] .
$ docker buildx build --output type=registry[,parameters] .
```

The following table describes the available parameters that you can pass to
`--output` for `type=image`:

| Parameter              | Type                                   | Default | Description                                                                                                                                                                                                                         |
| ---------------------- | -------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`                 | String                                 |         | Image name. To specify multiple names, use a comma-separated list.                                                                                                                                    |
| `push`                 | `true`,`false`                         | `false` | Push after creating the image.                                                                                                                                                                                                      |
| `push-by-digest`       | `true`,`false`                         | `false` | Push image without name.                                                                                                                                                                                                            |
| `registry.insecure`    | `true`,`false`                         | `false` | Allow pushing to insecure registry.                                                                                                                                                                                                 |
| `dangling-name-prefix` | `<value>`                              |         | Name image with `prefix@<digest>`, used for anonymous images                                                                                                                                                                        |
| `name-canonical`       | `true`,`false`                         |         | Add additional canonical name `name@<digest>`                                                                                                                                                                                       |
| `compression`          | `uncompressed`,`gzip`,`estargz`,`zstd` | `gzip`  | Compression type, see [compression][1]                                                                                                                                                                                              |
| `compression-level`    | `0..22`                                |         | Compression level, see [compression][1]                                                                                                                                                                                             |
| `force-compression`    | `true`,`false`                         | `false` | Forcefully apply compression, see [compression][1]                                                                                                                                                                                  |
| `rewrite-timestamp`    | `true`,`false`                         | `false` | Rewrite the file timestamps to the `SOURCE_DATE_EPOCH` value. See [build reproducibility][4] for how to specify the `SOURCE_DATE_EPOCH` value.                                                                                      |
| `oci-mediatypes`       | `true`,`false`                         | `false` | Use OCI media types in exporter manifests, see [OCI Media types][2]                                                                                                                                                                 |
| `oci-artifact`         | `true`,`false`                         | `false` | Attestations are formatted as OCI artifacts, see [OCI Media types][2]                                                                                                                                                               |
| `unpack`               | `true`,`false`                         | `false` | Unpack image after creation (for use with containerd)                                                                                                                                                                               |
| `store`                | `true`,`false`                         | `true`  | Store the result images to the worker's (for example, containerd) image store, and ensures that the image has all blobs in the content store. Ignored if the worker doesn't have image store (when using OCI workers, for example). |
| `annotation.<key>`     | String                                 |         | Attach an annotation with the respective `key` and `value` to the built image,see [annotations][3]                                                                                                                                  |

[1]: index.md#compression
[2]: index.md#oci-media-types
[3]: #annotations
[4]: https://github.com/moby/buildkit/blob/master/docs/build-repro.md
[5]: ../metadata/attestations/index.md#attestations-as-oci-artifacts

The `name` parameter is a CSV value inside the `--output` value. To specify
multiple image names, quote the complete `name` field:

```console
$ docker buildx build \
    --output 'type=image,"name=registry.example.com/myapp:1.0,registry.example.com/myapp:latest",push=true' .
```

To assign multiple names with CLI flags instead, repeat the
[`--tag` flag](/reference/cli/docker/buildx/build/#tag).

## Annotations

These exporters support adding OCI annotation using `annotation` parameter,
followed by the annotation name using dot notation. The following example sets
the `org.opencontainers.image.title` annotation:

```console
$ docker buildx build \
    --output "type=<type>,name=<registry>/<image>,annotation.org.opencontainers.image.title=<title>" .
```

For more information about annotations, see
[BuildKit documentation](https://github.com/moby/buildkit/blob/master/docs/annotations.md).

## Further reading

For more information on the `image` or `registry` exporters, see the
[BuildKit README](https://github.com/moby/buildkit/blob/master/README.md#imageregistry).


---

# Local and tar exporters

*Sección: Build*

The `local` and `tar` exporters output the root filesystem of the build result
into a local directory. They're useful for producing artifacts that aren't
container images.

- `local` exports files and directories.
- `tar` exports the same, but bundles the export into a tarball.

## Synopsis

Build a container image using the `local` exporter:

```console
$ docker buildx build --output type=local[,parameters] .
$ docker buildx build --output type=tar[,parameters] .
```

The following table describes the available parameters:

| Parameter        | Type    | Default | Description                                                                       |
| ---------------- | ------- | ------- | --------------------------------------------------------------------------------- |
| `dest`           | String  |         | Path to copy files to                                                             |
| `platform-split` | Boolean | `true`  | `local` exporter only. Split multi-platform outputs into platform subdirectories. |

## Multi-platform builds with local exporter

The `platform-split` parameter controls how multi-platform build outputs are
organized.

Consider this Dockerfile that creates platform-specific files:

```dockerfile
FROM busybox AS build
ARG TARGETOS
ARG TARGETARCH
RUN mkdir /out && echo foo > /out/hello-$TARGETOS-$TARGETARCH

FROM scratch
COPY --from=build /out /
```

### Split by platform (default)

By default, the local exporter creates a separate subdirectory for each
platform:

```console
$ docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --output type=local,dest=./output \
  .
```

This produces the following directory structure:

```text
output/
├── linux_amd64/
│   └── hello-linux-amd64
└── linux_arm64/
    └── hello-linux-arm64
```

### Merge all platforms

To merge files from all platforms into the same directory, set
`platform-split=false`:

```console
$ docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --output type=local,dest=./output,platform-split=false \
  .
```

This produces a flat directory structure:

```text
output/
├── hello-linux-amd64
└── hello-linux-arm64
```

Files from all platforms merge into a single directory. If multiple platforms
produce files with identical names, the export fails with an error.

### Single-platform builds

Single-platform builds export directly to the destination directory without
creating a platform subdirectory:

```console
$ docker buildx build \
  --platform linux/amd64 \
  --output type=local,dest=./output \
  .
```

This produces:

```text
output/
└── hello-linux-amd64
```

To include the platform subdirectory even for single-platform builds, explicitly
set `platform-split=true`:

```console
$ docker buildx build \
  --platform linux/amd64 \
  --output type=local,dest=./output,platform-split=true \
  .
```

This produces:

```text
output/
└── linux_amd64/
    └── hello-linux-amd64
```

## Further reading

For more information on the `local` or `tar` exporters, see the
[BuildKit README](https://github.com/moby/buildkit/blob/master/README.md#local-directory).


---

# OCI and Docker exporters

*Sección: Build*

The `oci` exporter outputs the build result into an
[OCI image layout](https://github.com/opencontainers/image-spec/blob/main/image-layout.md)
tarball. The `docker` exporter behaves the same way, except it exports a Docker
image layout instead.

The [`docker` driver](../builders/drivers/docker.md) doesn't support these exporters. You
must use `docker-container` or some other driver if you want to generate these
outputs.

## Synopsis

Build a container image using the `oci` and `docker` exporters:

```console
$ docker buildx build --output type=oci[,parameters] .
```

```console
$ docker buildx build --output type=docker[,parameters] .
```

The following table describes the available parameters:

| Parameter           | Type                                   | Default | Description                                                                                                                           |
| ------------------- | -------------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `name`              | String                                 |         | Specify image name(s)                                                                                                                 |
| `dest`              | String                                 |         | Path                                                                                                                                  |
| `tar`               | `true`,`false`                         | `true`  | Bundle the output into a tarball layout                                                                                               |
| `compression`       | `uncompressed`,`gzip`,`estargz`,`zstd` | `gzip`  | Compression type, see [compression][1]                                                                                                |
| `compression-level` | `0..22`                                |         | Compression level, see [compression][1]                                                                                               |
| `force-compression` | `true`,`false`                         | `false` | Forcefully apply compression, see [compression][1]                                                                                    |
| `oci-mediatypes`    | `true`,`false`                         |         | Use OCI media types in exporter manifests. Defaults to `true` for `type=oci`, and `false` for `type=docker`. See [OCI Media types][2] |
| `annotation.<key>`  | String                                 |         | Attach an annotation with the respective `key` and `value` to the built image,see [annotations][3]                                    |
| `rewrite-timestamp` | `true`,`false`                         | `false` | Rewrite the file timestamps to the `SOURCE_DATE_EPOCH` value. See [build reproducibility][4] for how to specify the `SOURCE_DATE_EPOCH` value. |

[1]: index.md#compression
[2]: index.md#oci-media-types
[3]: #annotations
[4]: https://github.com/moby/buildkit/blob/master/docs/build-repro.md

## Annotations

These exporters support adding OCI annotation using `annotation` parameter,
followed by the annotation name using dot notation. The following example sets
the `org.opencontainers.image.title` annotation:

```console
$ docker buildx build \
    --output "type=<type>,name=<registry>/<image>,annotation.org.opencontainers.image.title=<title>" .
```

For more information about annotations, see
[BuildKit documentation](https://github.com/moby/buildkit/blob/master/docs/annotations.md).

## Further reading

For more information on the `oci` or `docker` exporters, see the
[BuildKit README](https://github.com/moby/buildkit/blob/master/README.md#docker-tarball).


---

# Metadata

*Sección: Build*




---

# Annotations

*Sección: Build*

<!-- vale Docker.Spacing = NO -->

Annotations provide descriptive metadata for images. Use annotations to record
arbitrary information and attach it to your image, which helps consumers and
tools understand the origin, contents, and how to use the image.

Annotations are similar to, and in some sense overlap with, [labels]. Both
serve the same purpose: to attach metadata to a resource. As a general principle,
you can think of the difference between annotations and labels as follows:

- Annotations describe OCI image components, such as [manifests], [indexes],
  and [descriptors].
- Labels describe Docker resources, such as images, containers, networks, and
  volumes.

The OCI image [specification] defines the format of annotations, as well as a set
of pre-defined annotation keys. Adhering to the specified standards ensures
that metadata about images can be surfaced automatically and consistently, by
tools like Docker Scout.

Annotations are not to be confused with [attestations]:

- Attestations contain information about how an image was built and what it contains.
  An attestation is attached as a separate manifest on the image index.
  Attestations are not standardized by the Open Container Initiative.
- Annotations contain arbitrary metadata about an image.
  Annotations attach to the image [config] as labels,
  or on the image index or manifest as properties.

## Add annotations

You can add annotations to an image at build-time, or when creating the image
manifest or index.

> [!NOTE]
>
> The Docker Engine image store doesn't support loading images with
> annotations. To build with annotations, make sure to push the image directly
> to a registry, using the `--push` CLI flag or the
> [registry exporter](../exporters/image-registry.md).

To specify annotations on the command line, use the `--annotation` flag for the
`docker build` command:

```console
$ docker build --push --annotation "foo=bar" .
```

If you're using [Bake](../bake/index.md), you can use the `annotations`
attribute to specify annotations for a given target:

```hcl
target "default" {
  output = ["type=registry"]
  annotations = ["foo=bar"]
}
```

For examples on how to add annotations to images built with GitHub Actions, see
[Add image annotations with GitHub Actions](../ci/github-actions/annotations.md)

You can also add annotations to an image created using
`docker buildx imagetools create`. This command only supports adding annotations to an index
or manifest descriptors, see
[CLI reference](/reference/cli/docker/buildx/imagetools/create/#annotation).

## Inspect annotations

To view annotations on an **image index**, use the
`docker buildx imagetools inspect` command. This shows you any annotations for
the index and descriptors
(references to manifests) that the index contains. The following example shows
an `org.opencontainers.image.documentation` annotation on a descriptor, and an
`org.opencontainers.image.authors` annotation on the index.

```console {hl_lines=["10-12","19-21"]}
$ docker buildx imagetools inspect <IMAGE> --raw
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    {
      "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:d20246ef744b1d05a1dd69d0b3fa907db007c07f79fe3e68c17223439be9fefb",
      "size": 911,
      "annotations": {
        "org.opencontainers.image.documentation": "https://foo.example/docs",
      },
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      }
    },
  ],
  "annotations": {
    "org.opencontainers.image.authors": "dvdksn"
  }
}
```

To inspect annotations on a manifest, use the
`docker buildx imagetools inspect` command and specify `<IMAGE>@<DIGEST>`,
where `<DIGEST>` is the digest
of the manifest:

```console {hl_lines="22-25"}
$ docker buildx imagetools inspect <IMAGE>@sha256:d20246ef744b1d05a1dd69d0b3fa907db007c07f79fe3e68c17223439be9fefb --raw
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "digest": "sha256:4368b6959a78b412efa083c5506c4887e251f1484ccc9f0af5c406d8f76ece1d",
    "size": 850
  },
  "layers": [
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:2c03dbb20264f09924f9eab176da44e5421e74a78b09531d3c63448a7baa7c59",
      "size": 3333033
    },
    {
      "mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
      "digest": "sha256:4923ad480d60a548e9b334ca492fa547a3ce8879676685b6718b085de5aaf142",
      "size": 61887305
    }
  ],
  "annotations": {
    "index,manifest:org.opencontainers.image.vendor": "foocorp",
    "org.opencontainers.image.source": "https://git.example/foo.git",
  }
}
```

## Specify annotation level

By default, annotations are added to the image manifest. You can specify which
level (OCI image component) to attach the annotation to by prefixing the
annotation string with a special type declaration:

```console
$ docker build --annotation "<TYPE>:<KEY>=<VALUE>" .
```

The following types are supported:

- `manifest`: annotates manifests.
- `index`: annotates the root index.
- `manifest-descriptor`: annotates manifest descriptors in the index.
- `index-descriptor`:  annotates the index descriptor in the image layout.

For example, to build an image with the annotation `foo=bar` attached to the
image index:

```console
$ docker build --tag <IMAGE> --push --annotation "index:foo=bar" .
```

Note that the build must produce the component that you specify, or else the
build will fail. For example, the following does not work, because the `docker`
exporter does not produce an index:

```console
$ docker build --output type=docker --annotation "index:foo=bar" .
```

Likewise, the following example also does not work, because Buildx creates a
`docker` output by default under some circumstances, such as when provenance
attestations are explicitly disabled:

```console
$ docker build --provenance=false --annotation "index:foo=bar" .
```

It is possible to specify types, separated by a comma, to add the annotation to
more than one level. The following example creates an image with the annotation
`foo=bar` on both the image index and the image manifest:

```console
$ docker build --tag <IMAGE> --push --annotation "index,manifest:foo=bar" .
```

You can also specify a platform qualifier within square brackets in the type
prefix, to annotate only components matching specific OS and architectures. The
following example adds the `foo=bar` annotation only to the `linux/amd64`
manifest:

```console
$ docker build --tag <IMAGE> --push --annotation "manifest[linux/amd64]:foo=bar" .
```

## Related information

Related articles:

- [Add image annotations with GitHub Actions](../ci/github-actions/annotations.md)
- [Annotations OCI specification][specification]

Reference information:

- [`docker buildx build --annotation`](/reference/cli/docker/buildx/build/#annotation)
- [Bake file reference: `annotations`](/manuals/build/bake/reference.md#targetannotations)
- [`docker buildx imagetools create --annotation`](/reference/cli/docker/buildx/imagetools/create/#annotation)

<!-- links -->

[specification]: https://github.com/opencontainers/image-spec/blob/main/annotations.md
[attestations]: attestations/index.md
[config]: https://github.com/opencontainers/image-spec/blob/main/config.md
[descriptors]: https://github.com/opencontainers/image-spec/blob/main/descriptor.md
[indexes]: https://github.com/opencontainers/image-spec/blob/main/image-index.md
[labels]: ../../engine/manage-resources/labels.md
[manifests]: https://github.com/opencontainers/image-spec/blob/main/manifest.md


---

# Build attestations

*Sección: Build*

{{< youtube-embed qOzcycbTs4o >}}

Build attestations describe how an image was built, and what it contains. The
attestations are created at build-time by BuildKit, and become attached to the
final image as metadata.

The purpose of attestations is to make it possible to inspect an image and see
where it comes from, who created it and how, and what it contains. This enables
you to make informed decisions about how an image impacts the supply chain security
of your application. It also enables the use of policy engines for validating
images based on policy rules you've defined.

Two types of build attestations are available:

- Software Bill of Material (SBOM): list of software artifacts that an image
  contains, or that were used to build the image.
- Provenance: how an image was built.

## Purpose of attestations

The use of open source and third-party packages is more widespread than ever
before. Developers share and reuse code because it helps increase productivity,
allowing teams to create better products, faster.

Importing and using code created elsewhere without vetting it introduces a
severe security risk. Even if you do review the software that you consume, new
zero-day vulnerabilities are frequently discovered, requiring development teams
take action to remediate them.

Build attestations make it easier to see the contents of an image, and where it
comes from. Use attestations to analyze and decide whether to use an image, or
to see if images you are already using are exposed to vulnerabilities.

## Creating attestations

BuildKit generates the attestations when building the image. Provenance
attestations with the `mode=min` level are added to images by default. The
attestation records are wrapped in the in-toto JSON format and attached to the
image index in a manifest for the final image.

You can customize attestation behavior using the `--provenance` and `--sbom`
flags:

```bash
# Opt in to SBOM attestations:
docker buildx build --sbom=true .
# Opt in to max-level provenance attestations:
docker buildx build --provenance=mode=max .
# Opt out of provenance attestations:
docker buildx build --provenance=false .
```

You can also disable default provenance attestations by setting the
[`BUILDX_NO_DEFAULT_ATTESTATIONS`](../../building/variables.md#buildx_no_default_attestations)
environment variable. See [Provenance attestation](slsa-provenance.md) for
more details about provenance modes and options.

### Driver and image store support

Attestations attach to an image index. The classic image store doesn't support
image indices, so it can't hold an image with attestations.

The default `docker` driver builds with the BuildKit library bundled into the
Docker daemon, and writes the result to the daemon's image store. If the daemon
still uses the classic image store, the build fails:

```text
ERROR: failed to build: Attestation is not supported for the docker driver.
Switch to a different driver, or turn on the containerd image store, and try again.
```

To build attestations with the `docker` driver, turn on the containerd image
store. See [containerd image store with Docker Desktop](../../../desktop/features/containerd.md)
or [containerd image store with Docker Engine](../../../engine/storage/containerd.md).

| Driver                    | Attestation support                 |
| :------------------------ | :---------------------------------- |
| `docker`                  | Requires the containerd image store |
| `docker-container`        | Supported                           |
| `kubernetes` and `remote` | Supported                           |

The `docker-container`, `kubernetes`, and `remote` drivers run BuildKit outside
the Docker daemon, so they build attestations regardless of which image store
the daemon uses. Pushing the result to a registry with `--push` keeps the
attestations. If you load the result into the daemon with `--load` instead, the
same image store requirement applies.

If you don't want to switch image stores or drivers, opt out of attestations
with `--provenance=false --sbom=false`.

## Storage

BuildKit produces attestations in the [in-toto format](https://github.com/in-toto/attestation),
as defined by the [in-toto framework](https://in-toto.io/),
a standard supported by the Linux Foundation.

Attestations attach to images as a manifest in the image index. The data records
of the attestations are stored as JSON blobs.

Because attestations attach to images as a manifest, it means that you can
inspect the attestations for any image in a registry without having to pull the
whole image.

All BuildKit exporters support attestations. The `local` and `tar` can't save
the attestations to an image manifest, since it's outputting a directory of
files or a tarball, not an image. Instead, these exporters write the
attestations to one or more JSON files in the root directory of the export.

## Example

The following example shows a truncated in-toto JSON representation of an SBOM
attestation.

```json
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://spdx.dev/Document",
  "subject": [
    {
      "name": "pkg:docker/<registry>/<image>@<tag/digest>?platform=<platform>",
      "digest": {
        "sha256": "e8275b2b76280af67e26f068e5d585eb905f8dfd2f1918b3229db98133cb4862"
      }
    }
  ],
  "predicate": {
    "SPDXID": "SPDXRef-DOCUMENT",
    "creationInfo": {
      "created": "2022-12-15T11:47:54.546747383Z",
      "creators": ["Organization: Anchore, Inc", "Tool: syft-v0.60.3"],
      "licenseListVersion": "3.18"
    },
    "dataLicense": "CC0-1.0",
    "documentNamespace": "https://anchore.com/syft/dir/run/src/core-da0f600b-7f0a-4de0-8432-f83703e6bc4f",
    "name": "/run/src/core",
    // list of files that the image contains, e.g.:
    "files": [
      {
        "SPDXID": "SPDXRef-1ac501c94e2f9f81",
        "comment": "layerID: sha256:9b18e9b68314027565b90ff6189d65942c0f7986da80df008b8431276885218e",
        "fileName": "/bin/busybox",
        "licenseConcluded": "NOASSERTION"
      }
    ],
    // list of packages that were identified for this image:
    "packages": [
      {
        "name": "busybox",
        "originator": "Person: Sören Tempel <soeren+alpine@soeren-tempel.net>",
        "sourceInfo": "acquired package info from APK DB: lib/apk/db/installed",
        "versionInfo": "1.35.0-r17",
        "SPDXID": "SPDXRef-980737451f148c56",
        "description": "Size optimized toolbox of many common UNIX utilities",
        "downloadLocation": "https://busybox.net/",
        "licenseConcluded": "GPL-2.0-only",
        "licenseDeclared": "GPL-2.0-only"
        // ...
      }
    ],
    // files-packages relationship
    "relationships": [
      {
        "relatedSpdxElement": "SPDXRef-1ac501c94e2f9f81",
        "relationshipType": "CONTAINS",
        "spdxElementId": "SPDXRef-980737451f148c56"
      },
      ...
    ],
    "spdxVersion": "SPDX-2.2"
  }
}
```

To deep-dive into the specifics about how attestations are stored, see
[Image Attestation Storage (BuildKit)](attestation-storage.md).

## Attestation manifest format

Attestations are stored as manifests, referenced by the image's index. Each
_attestation manifest_ refers to a single _image manifest_ (one
platform-variant of the image). Attestation manifests contain a single layer,
the "value" of the attestation.

The following example shows the structure of an attestation manifest:

```json
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.image.config.v1+json",
    "size": 167,
    "digest": "sha256:916d7437a36dd0e258e64d9c5a373ca5c9618eeb1555e79bd82066e593f9afae"
  },
  "layers": [
    {
      "mediaType": "application/vnd.in-toto+json",
      "size": 1833349,
      "digest": "sha256:3138024b98ed5aa8e3008285a458cd25a987202f2500ce1a9d07d8e1420f5491",
      "annotations": {
        "in-toto.io/predicate-type": "https://spdx.dev/Document"
      }
    }
  ]
}
```

### Attestations as OCI artifacts

You can configure the format of the attestation manifest using the
[`oci-artifact` option](../../exporters/image-registry.md#synopsis)
for the `image` and `registry` exporters. If set to `true`, the structure of
the attestation manifest changes as follows:

- An `artifactType` field is added to the attestation manifest, with a value of `application/vnd.docker.attestation.manifest.v1+json`.
- The `config` field is an [empty descriptor] instead of a "dummy" config.
- A `subject` field is also added, pointing to the image manifest that the attestation refers to.

[empty descriptor]: https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidance-for-an-empty-descriptor

The following example shows an attestation with the OCI artifact format:

```json
{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.manifest.v1+json",
  "artifactType": "application/vnd.docker.attestation.manifest.v1+json",
  "config": {
    "mediaType": "application/vnd.oci.empty.v1+json",
    "size": 2,
    "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
    "data": "e30="
  },
  "layers": [
    {
      "mediaType": "application/vnd.in-toto+json",
      "size": 2208,
      "digest": "sha256:6d2f2c714a6bee3cf9e4d3cb9a966b629efea2dd8556ed81f19bd597b3325286",
      "annotations": {
        "in-toto.io/predicate-type": "https://slsa.dev/provenance/v0.2"
      }
    }
  ],
  "subject": {
    "mediaType": "application/vnd.oci.image.manifest.v1+json",
    "size": 1054,
    "digest": "sha256:bc2046336420a2852ecf915786c20f73c4c1b50d7803aae1fd30c971a7d1cead",
    "platform": {
      "architecture": "amd64",
      "os": "linux"
    }
  }
}
```

## What's next

Learn more about the available attestation types and how to use them:

- [Provenance](slsa-provenance.md)
- [SBOM](sbom.md)


---

# SBOM attestations

*Sección: Build*

SBOM attestations help ensure [software supply chain transparency](/guides/docker-scout/) by verifying the software artifacts an image contains and the artifacts used to create the image. Metadata included in an [SBOM](/guides/docker-scout/) for describing software artifacts may include:

- Name of the artifact
- Version
- License type
- Authors
- Unique package identifier

Indexing the contents of an image during the build has benefits over scanning a final image. When scanning happens as part of the build, you can detect software you used to build the image, which may not show up in the final image.

Docker supports SBOM generation and attestation through an SLSA-compliant build process using BuildKit and attestations. The SBOMs generated by [BuildKit](../../buildkit/index.md) follow the SPDX standard and attach to the final image as a JSON-encoded SPDX document, using the format defined by the [in-toto SPDX predicate](https://github.com/in-toto/attestation/blob/main/spec/predicates/spdx.md). On this page, you’ll learn how to create, manage, and verify SBOM attestations using Docker tooling.

## Create SBOM attestations

To create an SBOM attestation, pass the `--attest type=sbom` option to the
`docker buildx build` command:

```console
$ docker buildx build --tag <namespace>/<image>:<version> \
    --attest type=sbom --push .
```

Alternatively, you can use the shorthand `--sbom=true` option instead of `--attest type=sbom`.

For an example on how to add SBOM attestations with GitHub Actions, see
[Add attestations with GitHub Actions](../../ci/github-actions/attestations.md).

## Verify SBOM attestations

Always validate the generated SBOM for your image before you push your image to a registry.

To validate, you can build the image using the `local` exporter.
Building with the `local` exporter saves the build result to your local filesystem instead of creating an image.
Attestations are written to a JSON file in the root directory of your export.

```console
$ docker buildx build \
  --sbom=true \
  --output type=local,dest=out .
```

The SBOM file appears in the root directory of the output, named `sbom.spdx.json`:

```console
$ ls -1 ./out | grep sbom
sbom.spdx.json
```

## Arguments

By default, BuildKit only scans the final stage of an image. The resulting SBOM
doesn't include build-time dependencies installed in earlier stages, or that
exist in the build context. This may cause you to overlook vulnerabilities in
those dependencies, which could impact the security of your final build
artifacts.

For instance, you might use [multi-stage builds](../../building/multi-stage.md),
with a `FROM scratch` stanza for your final stage to achieve a smaller image size.

```dockerfile
FROM alpine AS build
# build the software ...

FROM scratch
COPY --from=build /path/to/bin /bin
ENTRYPOINT [ "/bin" ]
```

Scanning the resulting image built using this Dockerfile example would not
reveal build-time dependencies used in the `build` stage.

To include build-time dependencies from your Dockerfile, you can set the build
arguments `BUILDKIT_SBOM_SCAN_CONTEXT` and `BUILDKIT_SBOM_SCAN_STAGE`. This
expands the scanning scope to include the build context and additional stages.

You can set the arguments as global arguments (after declaring the Dockerfile
syntax directive, before the first `FROM` command) or individually in each
stage. If set globally, the value propagates to each stage in the Dockerfile.

The `BUILDKIT_SBOM_SCAN_CONTEXT` and `BUILDKIT_SBOM_SCAN_STAGE` build arguments
are special values. You can't perform variable substitution using these
arguments, and you can't set them using environment variables from within the
Dockerfile. The only way to set these values is using explicit `ARG` command in
the Dockerfile.

### Scan build context

To scan the build context, set the `BUILDKIT_SBOM_SCAN_CONTEXT` to `true`.

```dockerfile
# syntax=docker/dockerfile:1
ARG BUILDKIT_SBOM_SCAN_CONTEXT=true
FROM alpine AS build
# ...
```

You can use the `--build-arg` CLI option to override the value specified in the
Dockerfile.

```console
$ docker buildx build --tag <image>:<version> \
    --attest type=sbom \
    --build-arg BUILDKIT_SBOM_SCAN_CONTEXT=false .
```

Note that passing the option as a CLI argument only, without having declared it
using `ARG` in the Dockerfile, will have no effect. You must specify the `ARG`
in the Dockerfile, whereby you can override the context scanning behavior using
`--build-arg`.

### Scan stages

To scan more than just the final stage, set the `BUILDKIT_SBOM_SCAN_STAGE`
argument to true, either globally or in the specific stages that you want to
scan. The following table demonstrates the different possible settings for this
argument.

| Value                               | Description                                            |
| ----------------------------------- | ------------------------------------------------------ |
| `BUILDKIT_SBOM_SCAN_STAGE=true`     | Enables scanning for the current stage                 |
| `BUILDKIT_SBOM_SCAN_STAGE=false`    | Disables scanning for the current stage                |
| `BUILDKIT_SBOM_SCAN_STAGE=base,bin` | Enables scanning for the stages named `base` and `bin` |

Only stages that are built will be scanned. Stages that aren't dependencies of
the target stage won't be built, or scanned.

The following Dockerfile example uses multi-stage builds to build a static website with
[Hugo](https://gohugo.io/).

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine as hugo
ARG BUILDKIT_SBOM_SCAN_STAGE=true
WORKDIR /src
COPY <<config.yml ./
title: My Hugo website
config.yml
RUN apk add --upgrade hugo && hugo

FROM scratch
COPY --from=hugo /src/public /
```

Setting `ARG BUILDKIT_SBOM_SCAN_STAGE=true` in the `hugo` stage ensures that the final SBOM
includes the information that Alpine Linux and Hugo were used to create the website.

Building this image with the `local` exporter creates two JSON files:

```console
$ docker buildx build \
  --sbom=true \
  --output type=local,dest=out .
$ ls -1 out | grep sbom
sbom-hugo.spdx.json
sbom.spdx.json
```

## Inspecting SBOMs

To explore created SBOMs exported through the `image` exporter, you can use
[`imagetools inspect`](/reference/cli/docker/buildx/imagetools/inspect/).

Using the `--format` option, you can specify a template for the output. All
SBOM-related data is available under the `.SBOM` attribute. For example, to get
the raw contents of an SBOM in SPDX format:

```console
$ docker buildx imagetools inspect <namespace>/<image>:<version> \
    --format "{{ json .SBOM.SPDX }}"
{
  "SPDXID": "SPDXRef-DOCUMENT",
  ...
}
```

> [!TIP]
>
> If the image is multi-platform, you can check the SBOM for a platform-specific index using `--format '{{ json (index .SBOM "linux/amd64").SPDX }}'`.

You can also construct more complex expressions using the full functionality
of Go templates. For example, you can list all the installed packages and their
version identifiers:

```console
$ docker buildx imagetools inspect <namespace>/<image>:<version> \
    --format "{{ range .SBOM.SPDX.packages }}{{ .name }}@{{ .versionInfo }}{{ println }}{{ end }}"
adduser@3.118ubuntu2
apt@2.0.9
base-files@11ubuntu5.6
base-passwd@3.5.47
...
```

## SBOM generator

BuildKit generates the SBOM using a scanner plugin. By default, it uses the
[BuildKit Syft scanner](https://github.com/docker/buildkit-syft-scanner)
plugin. This plugin is built on top of
[Anchore's Syft](https://github.com/anchore/syft),
an open source tool for generating an SBOM.

You can select a different plugin to use with the `generator` option, specifying
an image that implements the
[BuildKit SBOM scanner protocol](https://github.com/moby/buildkit/blob/master/docs/attestations/sbom-protocol.md).

```console
$ docker buildx build --attest type=sbom,generator=<image> .
```

> [!TIP]
>
> The Docker Scout SBOM generator is available. See
> [Docker Scout SBOMs](../../../scout/how-tos/view-create-sboms.md).

## SBOM attestation example

The following JSON example shows what an SBOM attestation might look like.

```json
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://spdx.dev/Document",
  "subject": [
    {
      "name": "pkg:docker/<registry>/<image>@<tag/digest>?platform=<platform>",
      "digest": {
        "sha256": "e8275b2b76280af67e26f068e5d585eb905f8dfd2f1918b3229db98133cb4862"
      }
    }
  ],
  "predicate": {
    "SPDXID": "SPDXRef-DOCUMENT",
    "creationInfo": {
      "created": "2022-12-16T15:27:25.517047753Z",
      "creators": ["Organization: Anchore, Inc", "Tool: syft-v0.60.3"],
      "licenseListVersion": "3.18"
    },
    "dataLicense": "CC0-1.0",
    "documentNamespace": "https://anchore.com/syft/dir/run/src/core/sbom-cba61a72-fa95-4b60-b63f-03169eac25ca",
    "name": "/run/src/core/sbom",
    "packages": [
      {
        "SPDXID": "SPDXRef-b074348b8f56ea64",
        "downloadLocation": "NOASSERTION",
        "externalRefs": [
          {
            "referenceCategory": "SECURITY",
            "referenceLocator": "cpe:2.3:a:org:repo:\\(devel\\):*:*:*:*:*:*:*",
            "referenceType": "cpe23Type"
          },
          {
            "referenceCategory": "PACKAGE_MANAGER",
            "referenceLocator": "pkg:golang/github.com/org/repo@(devel)",
            "referenceType": "purl"
          }
        ],
        "filesAnalyzed": false,
        "licenseConcluded": "NONE",
        "licenseDeclared": "NONE",
        "name": "github.com/org/repo",
        "sourceInfo": "acquired package info from go module information: bin/server",
        "versionInfo": "(devel)"
      },
      {
        "SPDXID": "SPDXRef-1b96f57f8fed62d8",
        "checksums": [
          {
            "algorithm": "SHA256",
            "checksumValue": "0c13f1f3c1636491f716c2027c301f21f9dbed7c4a2185461ba94e3e58443408"
          }
        ],
        "downloadLocation": "NOASSERTION",
        "externalRefs": [
          {
            "referenceCategory": "SECURITY",
            "referenceLocator": "cpe:2.3:a:go-chi:chi\\/v5:v5.0.0:*:*:*:*:*:*:*",
            "referenceType": "cpe23Type"
          },
          {
            "referenceCategory": "SECURITY",
            "referenceLocator": "cpe:2.3:a:go_chi:chi\\/v5:v5.0.0:*:*:*:*:*:*:*",
            "referenceType": "cpe23Type"
          },
          {
            "referenceCategory": "SECURITY",
            "referenceLocator": "cpe:2.3:a:go:chi\\/v5:v5.0.0:*:*:*:*:*:*:*",
            "referenceType": "cpe23Type"
          },
          {
            "referenceCategory": "PACKAGE_MANAGER",
            "referenceLocator": "pkg:golang/github.com/go-chi/chi/v5@v5.0.0",
            "referenceType": "purl"
          }
        ],
        "filesAnalyzed": false,
        "licenseConcluded": "NONE",
        "licenseDeclared": "NONE",
        "name": "github.com/go-chi/chi/v5",
        "sourceInfo": "acquired package info from go module information: bin/server",
        "versionInfo": "v5.0.0"
      }
    ],
    "relationships": [
      {
        "relatedSpdxElement": "SPDXRef-1b96f57f8fed62d8",
        "relationshipType": "CONTAINS",
        "spdxElementId": "SPDXRef-043f7360d3c66bc31ba45388f16423aa58693289126421b71d884145f8837fe1"
      },
      {
        "relatedSpdxElement": "SPDXRef-b074348b8f56ea64",
        "relationshipType": "CONTAINS",
        "spdxElementId": "SPDXRef-043f7360d3c66bc31ba45388f16423aa58693289126421b71d884145f8837fe1"
      }
    ],
    "spdxVersion": "SPDX-2.2"
  }
}
```


---

# Provenance attestations

*Sección: Build*

The provenance attestations include facts about the build process, including
details such as:

- Build timestamps
- Build parameters and environment
- Version control metadata
- Source code details
- Materials (files, scripts) consumed during the build

By default, provenance attestations follow the
[SLSA provenance schema, version 0.2](https://slsa.dev/spec/v0.2/provenance#schema).
You can optionally enable [SLSA Provenance v1](https://slsa.dev/spec/v1.1/provenance#schema)
using [the `version` parameter](#version).

For more information about how BuildKit populates these provenance properties, refer to
[SLSA definitions](slsa-definitions.md).

## Create provenance attestations

To create a provenance attestation, pass the `--attest type=provenance` option
to the `docker buildx build` command:

```console
$ docker buildx build --tag <namespace>/<image>:<version> \
    --attest type=provenance,mode=[min,max],version=[v0.2,v1] .
```

Alternatively, you can use the shorthand `--provenance=true` option instead of `--attest type=provenance`.
To specify the `mode` or `version` parameters using the shorthand option, use:
`--provenance=mode=max,version=v1`.

For an example on how to add provenance attestations with GitHub Actions, see
[Add attestations with GitHub Actions](../../ci/github-actions/attestations.md).

## Mode

You can use the `mode` parameter to define the level of detail to be included in
the provenance attestation. Supported values are `mode=min` (default) and
`mode=max`.

### Min

In `min` mode, the provenance attestations include a minimal set of information,
such as:

- Build timestamps
- The frontend used
- Build materials
- Source repository and revision
- Build platform
- Reproducibility

Values of build arguments, the identities of secrets, and rich layer metadata are
not included in `mode=min`. The `min`-level provenance is safe to use for all
builds, as it doesn't leak information from any part of the build environment.

The following JSON example shows the information included in a provenance
attestations created using the `min` mode:

```json
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://slsa.dev/provenance/v0.2",
  "subject": [
    {
      "name": "pkg:docker/<registry>/<image>@<tag/digest>?platform=<platform>",
      "digest": {
        "sha256": "e8275b2b76280af67e26f068e5d585eb905f8dfd2f1918b3229db98133cb4862"
      }
    }
  ],
  "predicate": {
    "builder": { "id": "" },
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/docker/dockerfile@1",
        "digest": {
          "sha256": "9ba7531bd80fb0a858632727cf7a112fbfd19b17e94c4e84ced81e24ef1a0dbc"
        }
      },
      {
        "uri": "pkg:docker/golang@1.19.4-alpine?platform=linux%2Farm64",
        "digest": {
          "sha256": "a9b24b67dc83b3383d22a14941c2b2b2ca6a103d805cac6820fd1355943beaf1"
        }
      }
    ],
    "invocation": {
      "configSource": { "entryPoint": "Dockerfile" },
      "parameters": {
        "frontend": "gateway.v0",
        "args": {
          "cmdline": "docker/dockerfile:1",
          "source": "docker/dockerfile:1",
          "target": "binaries"
        },
        "locals": [{ "name": "context" }, { "name": "dockerfile" }]
      },
      "environment": { "platform": "linux/arm64" }
    },
    "metadata": {
      "buildInvocationID": "c4a87v0sxhliuewig10gnsb6v",
      "buildStartedOn": "2022-12-16T08:26:28.651359794Z",
      "buildFinishedOn": "2022-12-16T08:26:29.625483253Z",
      "reproducible": false,
      "completeness": {
        "parameters": true,
        "environment": true,
        "materials": false
      },
      "https://mobyproject.org/buildkit@v1#metadata": {
        "vcs": {
          "revision": "a9ba846486420e07d30db1107411ac3697ecab68",
          "source": "git@github.com:<org>/<repo>.git"
        }
      }
    }
  }
}
```

### Max

The `max` mode includes all of the information included in the `min` mode, as
well as:

- The LLB definition of the build. These show the exact steps taken to produce
  the image.
- Information about the Dockerfile, including a full base64-encoded version of
  the file.
- Source maps describing the relationship between build steps and image layers.

When possible, you should prefer `mode=max` as it contains significantly more
detailed information for analysis.

> [!WARNING]
>
> Note that `mode=max` exposes the values of
> [build arguments](/reference/cli/docker/buildx/build/#build-arg).
>
> If you're misusing build arguments to pass credentials, authentication
> tokens, or other secrets, you should refactor your build to pass the secrets using
> [secret mounts](/reference/cli/docker/buildx/build/#secret) instead.
> Secret mounts don't leak outside of the build and are never included in provenance attestations.

## Version

The `version` parameter lets you specify which SLSA provenance schema version
to use. Supported values are `version=v0.2` (default) and `version=v1`.

To use SLSA Provenance v1:

```console
$ docker buildx build --tag <namespace>/<image>:<version> \
    --attest type=provenance,mode=max,version=v1 .
```

For more information about SLSA Provenance v1, see the
[SLSA specification](https://slsa.dev/spec/v1.1/provenance). To see the
difference between SLSA v0.2 and v1 provenance attestations, refer to
[SLSA definitions](./slsa-definitions.md)

## Inspecting Provenance

To explore created Provenance exported through the `image` exporter, you can
use [`imagetools inspect`](/reference/cli/docker/buildx/imagetools/inspect/).

Using the `--format` option, you can specify a template for the output. All
provenance-related data is available under the `.Provenance` attribute. For
example, to get the raw contents of the Provenance in the SLSA format:

```console
$ docker buildx imagetools inspect <namespace>/<image>:<version> \
    --format "{{ json .Provenance.SLSA }}"
{
  "buildType": "https://mobyproject.org/buildkit@v1",
  ...
}
```

You can also construct more complex expressions using the full functionality of
Go templates. For example, for provenance generated with `mode=max`, you can
extract the full source code of the Dockerfile used to build the image:

```console
$ docker buildx imagetools inspect <namespace>/<image>:<version> \
    --format '{{ range (index .Provenance.SLSA.metadata "https://mobyproject.org/buildkit@v1#metadata").source.infos }}{{ if eq .filename "Dockerfile" }}{{ .data }}{{ end }}{{ end }}' | base64 -d
FROM ubuntu:24.04
RUN apt-get update
...
```

## Provenance attestation example

<!-- TODO: add a link to the definitions page, imported from moby/buildkit -->

The following example shows what a JSON representation of a provenance
attestation with `mode=max` looks like:

```json
{
  "_type": "https://in-toto.io/Statement/v0.1",
  "predicateType": "https://slsa.dev/provenance/v0.2",
  "subject": [
    {
      "name": "pkg:docker/<registry>/<image>@<tag/digest>?platform=<platform>",
      "digest": {
        "sha256": "e8275b2b76280af67e26f068e5d585eb905f8dfd2f1918b3229db98133cb4862"
      }
    }
  ],
  "predicate": {
    "builder": { "id": "" },
    "buildType": "https://mobyproject.org/buildkit@v1",
    "materials": [
      {
        "uri": "pkg:docker/docker/dockerfile@1",
        "digest": {
          "sha256": "9ba7531bd80fb0a858632727cf7a112fbfd19b17e94c4e84ced81e24ef1a0dbc"
        }
      },
      {
        "uri": "pkg:docker/golang@1.19.4-alpine?platform=linux%2Farm64",
        "digest": {
          "sha256": "a9b24b67dc83b3383d22a14941c2b2b2ca6a103d805cac6820fd1355943beaf1"
        }
      }
    ],
    "buildConfig": {
      "llbDefinition": [
        {
          "id": "step4",
          "op": {
            "Op": {
              "exec": {
                "meta": {
                  "args": ["/bin/sh", "-c", "go mod download -x"],
                  "env": [
                    "PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                    "GOLANG_VERSION=1.19.4",
                    "GOPATH=/go",
                    "CGO_ENABLED=0"
                  ],
                  "cwd": "/src"
                },
                "mounts": [
                  { "input": 0, "dest": "/", "output": 0 },
                  {
                    "input": -1,
                    "dest": "/go/pkg/mod",
                    "output": -1,
                    "mountType": 3,
                    "cacheOpt": { "ID": "//go/pkg/mod" }
                  },
                  {
                    "input": 1,
                    "selector": "/go.mod",
                    "dest": "/src/go.mod",
                    "output": -1,
                    "readonly": true
                  },
                  {
                    "input": 1,
                    "selector": "/go.sum",
                    "dest": "/src/go.sum",
                    "output": -1,
                    "readonly": true
                  }
                ]
              }
            },
            "platform": { "Architecture": "arm64", "OS": "linux" },
            "constraints": {}
          },
          "inputs": ["step3:0", "step1:0"]
        }
      ]
    },
    "metadata": {
      "buildInvocationID": "edf52vxjyf9b6o5qd7vgx0gru",
      "buildStartedOn": "2022-12-15T15:38:13.391980297Z",
      "buildFinishedOn": "2022-12-15T15:38:14.274565297Z",
      "reproducible": false,
      "completeness": {
        "parameters": true,
        "environment": true,
        "materials": false
      },
      "https://mobyproject.org/buildkit@v1#metadata": {
        "vcs": {
          "revision": "a9ba846486420e07d30db1107411ac3697ecab68-dirty",
          "source": "git@github.com:<org>/<repo>.git"
        },
        "source": {
          "locations": {
            "step4": {
              "locations": [
                {
                  "ranges": [
                    { "start": { "line": 5 }, "end": { "line": 5 } },
                    { "start": { "line": 6 }, "end": { "line": 6 } },
                    { "start": { "line": 7 }, "end": { "line": 7 } },
                    { "start": { "line": 8 }, "end": { "line": 8 } }
                  ]
                }
              ]
            }
          },
          "infos": [
            {
              "filename": "Dockerfile",
              "data": "RlJPTSBhbHBpbmU6bGF0ZXN0Cg==",
              "llbDefinition": [
                {
                  "id": "step0",
                  "op": {
                    "Op": {
                      "source": {
                        "identifier": "local://dockerfile",
                        "attrs": {
                          "local.differ": "none",
                          "local.followpaths": "[\"Dockerfile\",\"Dockerfile.dockerignore\",\"dockerfile\"]",
                          "local.session": "s4j58ngehdal1b5hn7msiqaqe",
                          "local.sharedkeyhint": "dockerfile"
                        }
                      }
                    },
                    "constraints": {}
                  }
                },
                { "id": "step1", "op": { "Op": null }, "inputs": ["step0:0"] }
              ]
            }
          ]
        },
        "layers": {
          "step2:0": [
            [
              {
                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                "digest": "sha256:261da4162673b93e5c0e7700a3718d40bcc086dbf24b1ec9b54bca0b82300626",
                "size": 3259190
              },
              {
                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                "digest": "sha256:bc729abf26b5aade3c4426d388b5ea6907fe357dec915ac323bb2fa592d6288f",
                "size": 286218
              },
              {
                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                "digest": "sha256:7f1d6579712341e8062db43195deb2d84f63b0f2d1ed7c3d2074891085ea1b56",
                "size": 116878653
              },
              {
                "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
                "digest": "sha256:652874aefa1343799c619d092ab9280b25f96d97939d5d796437e7288f5599c9",
                "size": 156
              }
            ]
          ]
        }
      }
    }
  }
}
```


---

# Validating build inputs with policies

*Sección: Build*

Building with Docker often involves downloading remote resources. These
external dependencies, such as Docker images, Git repositories, remote files,
and other artifacts, are called build inputs.

For example:

- Pulling images from a registry
- Cloning a source code repository
- Fetching files from a server over HTTPS

When consuming build inputs, it's a good idea to verify the contents are what
you expect them to be. One way to do this is to use the `--checksum` option for
the `ADD` Dockerfile instruction. This lets you verify the SHA256 checksum of a
remote resource when pulling it into a build:

```dockerfile
ADD --checksum=sha256:c0ff3312345… https://example.com/archive.tar.gz /
```

If the remote `archive.tar.gz` file does not match the checksum that the
Dockerfile expects, the build fails.

Checksums verify that content matches what you expect, but only for the `ADD`
instruction. They don't tell you anything about where the content came from or
how it was produced. You can't use checksums to enforce constraints like
"images must be signed" or "dependencies must come from approved sources."

Build policies solve this problem. They let you define rules that validate all
your build inputs, enforcing requirements like provenance attestations,
approved registries, and signed Git tags across your entire build process.

## Prerequisites

Build policies is currently an experimental feature. To try it out, you'll
need:

- Buildx 0.31.0 or later - Check your version: `docker buildx version`
- BuildKit 0.27.0 or later - Verify with: `docker buildx inspect --bootstrap`

If you're using Docker Desktop, ensure you're on a version that includes these
updates.

## Build policies

Buildx version 0.31.0 added support for build policies. Build policies are
rules for securing your Docker build supply chain, and help protect against
upstream compromises, malicious dependencies, and unauthorized modifications to
your build inputs.

Build policies let you enforce extended verifications on inputs used to build
your projects, such as:

- Docker images must use digest references (not tags alone)
- Images must have provenance attestations and cosign signatures
- Git tags are signed by maintainers with a PGP public key
- All remote artifacts must use HTTPS and include a checksum for verification

Build policies are defined in a declarative policy language, called Rego,
created for the [Open Policy Agent (OPA)](https://www.openpolicyagent.org/).
The following example shows a minimal build policy in Rego.

```rego {title="Dockerfile.rego"}
package docker

default allow := false

# Allow any local inputs for this build
# For example: a local build context, or a local Dockerfile
allow if input.local

# Allow images, but only if they have provenance attestations
allow if {
    input.image.hasProvenance
}

decision := {"allow": allow}
```

If the Dockerfile associated with this policy references an image with no
provenance attestation in a `FROM` instruction, the policy would be violated
and the build would fail.

## How policies work

When you run `docker buildx build`, Buildx:

1. Resolves all build inputs (images, Git repos, HTTP downloads)
2. Looks for a policy file matching your Dockerfile name (e.g.,
   `Dockerfile.rego`)
3. Evaluates each input against the policy before the build starts
4. Allows the build to proceed only if all inputs pass the policy

Policies are written in Rego (Open Policy Agent's policy language). You don't
need to be a Rego expert - the [Introduction](intro.md) tutorial teaches you
everything needed.

Policy files live alongside your Dockerfile:

```text
project/
├── Dockerfile
├── Dockerfile.rego
└── src/
```

No additional configuration is needed - Buildx automatically finds and loads
the policy when you build.

## Use cases

Build policies help you enforce security and compliance requirements on your
Docker builds. Common scenarios where policies provide value:

### Enforce base image standards

Require all production Dockerfiles to use specific, approved base images with
digest references. Prevent developers from using arbitrary images that haven't
been vetted by your security team.

### Validate third-party dependencies

When your build downloads files, libraries, or tools from the internet, verify
they come from trusted sources and match expected checksums or signatures. This
protects against supply chain attacks where an upstream dependency is
compromised.

### Ensure signed releases

Require that all dependencies have valid signatures from trusted parties.

- Check GPG signatures for Git repositories you clone in your builds
- Verify provenance attestation signatures with Sigstore

### Meet compliance requirements

Some regulatory frameworks require evidence that you validate your build
inputs. Build policies give you an auditable, declarative way to demonstrate
you're checking dependencies against security standards.

### Separate development and production rules

Apply stricter validation for production builds while allowing more flexibility
during development. The same policy file can contain conditional rules based on
build context or target.

## Get started

Ready to start writing policies? The [Introduction](intro.md) tutorial walks
you through creating your first policy and teaches the Rego basics you need.

For practical usage guidance, see [Using build policies](usage.md).

For practical examples you can copy and adapt, see the [Example
policies](examples.md) library.


---

# Built-in functions

*Sección: Build*

Buildx provides built-in functions, in addition to the [Rego
built-ins](#rego-built-in-functions), to extend Rego policies with
Docker-specific operations like loading local files, verifying Git signatures,
and pinning image digests.

## Rego built-in functions

The functions [documented on this page](#buildx-built-in-functions) are
Buildx-specific functions, distinct from [Rego's standard built-in
functions](https://www.openpolicyagent.org/docs/policy-language#built-in-functions)

Buildx also supports standard Rego built-in functions, but only a subset. To
see the exact list of supported functions, refer to the Buildx [source
code](https://github.com/docker/buildx/blob/master/policy/builtins.go).

## Buildx built-in functions

Buildx provides the following custom built-in functions for policy development:

- [`print`](#print)
- [`load_json`](#load_json)
- [`verify_git_signature`](#verify_git_signature)
- [`pin_image`](#pin_image)

### `print`

Outputs debug information during policy evaluation.

Parameters:

- Any number of values to print

Returns: The values (pass-through)

Example:

```rego
allow if {
    input.image.repo == "alpine"
    print("Allowing alpine image:", input.image.tag)
}
```

Debug output appears when building with `--progress=plain`.

### `load_json`

Loads and parses JSON data from local files in the build context.

Parameters:

- `filename` (string) - Path to JSON file relative to policy directory

Returns: Parsed JSON data as Rego value

Example:

```rego
# Load approved versions from external file
approved_versions = load_json("versions.json")

allow if {
    input.image.repo == "alpine"
    some version in approved_versions.alpine
    input.image.tag == version
}
```

File structure:

```text
project/
├── Dockerfile
├── Dockerfile.rego
└── versions.json
```

versions.json:

```json
{
  "alpine": ["3.19", "3.20"],
  "golang": ["1.21", "1.22"]
}
```

The JSON file must be in the same directory as the policy or in a
subdirectory accessible from the policy location.

### `verify_git_signature`

Verifies PGP signatures on Git commits or tags.

Parameters:

- `git_object` (object) - Either `input.git.commit` or `input.git.tag`
- `keyfile` (string) - Path to PGP public key file (relative to policy
  directory)

Returns: Boolean - `true` if signature is valid, `false` otherwise

Example:

```rego
# Require signed Git tags
allow if {
    input.git.tagName != ""
    verify_git_signature(input.git.tag, "maintainer.asc")
}

# Require signed commits
allow if {
    input.git.commit
    verify_git_signature(input.git.commit, "keys/team.asc")
}
```

Directory structure:

```text
project/
├── Dockerfile.rego
└── maintainer.asc          # PGP public key
```

Or with subdirectory:

```text
project/
├── Dockerfile.rego
└── keys/
    ├── maintainer.asc
    └── team.asc
```

Obtaining public keys:

```console
$ gpg --export --armor user@example.com > maintainer.asc
```

### `pin_image`

Pins an image to a specific digest, overriding the tag-based reference. Use
this to force builds to use specific image versions.

Parameters:

- `image_object` (object) - Must be `input.image` (the current image being
  evaluated)
- `digest` (string) - Target digest in format `sha256:...`

Returns: Boolean - `true` if pinning succeeds

Example:

```rego
# Pin alpine 3.19 to specific digest
alpine_3_19_digest = "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412"

allow if {
    input.image.repo == "alpine"
    input.image.tag == "3.19"
    pin_image(input.image, alpine_3_19_digest)
}
```

Automatic digest replacement:

```rego
# Replace old digests with patched versions
replace_map = {
  "3.22.0": "3.22.2",
  "3.22.1": "3.22.2",
}

alpine_digests = {
  "3.22.0": "sha256:8a1f59ffb675680d47db6337b49d22281a139e9d709335b492be023728e11715",
  "3.22.2": "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412",
}

allow if {
    input.image.repo == "alpine"
    some old_version, new_version in replace_map
    input.image.checksum == alpine_digests[old_version]
    print("Replacing", old_version, "with", new_version)
    pin_image(input.image, alpine_digests[new_version])
}
```

This pattern automatically upgrades old image versions to patched releases.

## Next steps

- Browse complete examples: [Example policies](examples.md)
- Learn policy development workflow: [Using build policies](usage.md)
- Reference input fields: [Input reference](inputs.md)


---

# Debugging build policies

*Sección: Build*

When policies don't work as expected, use the tools available to inspect policy
evaluation and understand what's happening. This guide covers the debugging
techniques and common gotchas.

## Quick reference

Essential debugging commands:

```console
# See complete input data during builds (recommended)
$ docker buildx build --progress=plain --policy log-level=debug .

# See policy checks and decisions
$ docker buildx build --progress=plain .

# Explore input structure for different sources
$ docker buildx policy eval --print .
$ docker buildx policy eval --print https://github.com/org/repo.git
$ docker buildx policy eval --print docker-image://alpine:3.19

# Test if policy allows a source
$ docker buildx policy eval .
```

## Policy output with `--progress=plain`

To see policy evaluation during builds, use `--progress=plain`:

```console
$ docker buildx build --progress=plain .
```

This shows all policy checks, decisions, and `print()` output. Without
`--progress=plain`, policy evaluation is silent unless there's an error.

```plaintext
#1 loading policies Dockerfile.rego
#1 0.010 checking policy for source docker-image://alpine:3.19 (linux/arm64)
#1 0.011 Dockerfile.rego:8: image: {"ref":"alpine:3.19","repo":"alpine","tag":"3.19"}
#1 0.012 policy decision for source docker-image://alpine:3.19: ALLOW
```

If a policy denies a source, you'll see:

```text
#1 0.012 policy decision for source docker-image://nginx:latest: DENY
ERROR: source "docker-image://nginx:latest" not allowed by policy
```

## Debug logging

For detailed debugging, add `--policy log-level=debug` to see the full input
JSON, unresolved fields, and policy responses:

```console
$ docker buildx build --progress=plain --policy log-level=debug .
```

This shows significantly more information than the default level, including the
complete input structure for each source without needing `print()` statements
in your policy.

Complete input JSON:

```text
#1 0.007 policy input: {
#1 0.007   "env": {
#1 0.007     "filename": "."
#1 0.007   },
#1 0.007   "image": {
#1 0.007     "ref": "docker.io/library/alpine:3.19",
#1 0.007     "host": "docker.io",
#1 0.007     "repo": "alpine",
#1 0.007     "fullRepo": "docker.io/library/alpine",
#1 0.007     "tag": "3.19",
#1 0.007     "platform": "linux/arm64",
#1 0.007     "os": "linux",
#1 0.007     "arch": "arm64"
#1 0.007   }
#1 0.007 }
```

Unresolved fields:

```text
#1 0.007 unknowns for policy evaluation: [input.image.checksum input.image.labels input.image.user input.image.volumes input.image.workingDir input.image.env input.image.hasProvenance input.image.signatures]
```

Policy response:

```text
#1 0.008 policy response: map[allow:true]
```

This detailed output is invaluable for understanding exactly what data your
policy receives and which fields are not yet resolved. Use debug logging when
developing policies to avoid needing extensive `print()` statements.

## Conditional debugging with print()

While `--policy log-level=debug` shows all input data automatically, the
`print()` function is useful for debugging specific rule logic and conditional
flows:

```rego
allow if {
    input.image
    print("Checking image:", input.image.repo, "isCanonical:", input.image.isCanonical)
    input.image.repo == "alpine"
    input.image.isCanonical
}
```

Use `print()` to debug conditional logic within rules or track which rules are
evaluating. For general input inspection during development, use `--policy
log-level=debug` instead - it requires no policy modifications.

> [!NOTE]
> Print statements only execute when their containing rule evaluates. A rule
> like `allow if { input.image; print(...) }` only prints for image inputs,
> not for Git repos, HTTP downloads, or local files.

## Common issues

### Full repository path or repository name

Symptom: Policy checking repository names doesn't match as expected.

Cause: Docker Hub images use `input.image.repo` for the short name
(`"alpine"`) but `input.image.fullRepo` includes the full path
(`"docker.io/library/alpine"`).

Solution:

```rego
# Match just the repo name (works for Docker Hub and other registries)
allow if {
    input.image
    input.image.repo == "alpine"
}

# Or match the full repository path
allow if {
    input.image
    input.image.fullRepo == "docker.io/library/alpine"
}
```

### Policy evaluation happens multiple times

Symptom: Build output shows the same source evaluated multiple times.

Cause: BuildKit may evaluate policies at different stages (reference
resolution, actual pull) or for different platforms.

This is normal behavior. Policies should be idempotent (produce same result
each time for the same input).

### Fields missing with `policy eval --print`

Symptom: `docker buildx policy eval --print` doesn't show expected fields
like `hasProvenance`, `labels`, or `checksum`.

Cause: `--print` shows only reference information by default, without
fetching from registries.

Solution: Use `--fields` to fetch specific metadata fields:

```console
$ docker buildx policy eval --print --fields image.labels docker-image://alpine:3.19
```

See [Using build policies](usage.md#testing-policies-with-policy-eval) for
details.

## Next steps

- See complete field reference: [Input reference](inputs.md)
- Review example policies: [Examples](examples.md)
- Learn policy usage patterns: [Using build policies](usage.md)


---

# Policy templates and examples

*Sección: Build*

This page provides complete, working policy examples you can copy and adapt.
The examples are organized into two sections: getting started policies for
quick adoption, and production templates for comprehensive security.

If you're new to policies, start with the tutorials:
[Introduction](intro.md), [Image validation](validate-images.md), and [Git
validation](validate-git.md). Those pages teach individual techniques. This
page shows complete policies combining those techniques.

## How to use these examples

1. Copy the policy code into a `Dockerfile.rego` file next to your
   Dockerfile
2. Customize any todo comments with your specific values
3. Test by running `docker build .` and verifying the policy works as
   expected
4. Refine based on your team's needs

### Using examples with bake

These policies work with both `docker buildx build` and `docker buildx bake`.
For bake, place the policy alongside your Dockerfile and it loads
automatically. To use additional policies:

```hcl
target "default" {
  dockerfile = "Dockerfile"
  policy = ["extra.rego"]
}
```

See the [Usage guide](usage.md) for complete bake integration details.

## Getting started

These policies work immediately with minimal or no customization. Use them to
adopt policies quickly and demonstrate value to your team.

### Development-friendly baseline

A permissive policy that allows typical development workflows while blocking
obvious security issues.

```rego
package docker

default allow := false

allow if input.local
allow if input.git

# Allow common public registries
allow if {
  input.image.host == "docker.io"  # Docker Hub
}

allow if {
  input.image.host == "ghcr.io"  # GitHub Container Registry
}

allow if {
  input.image.host == "dhi.io"  # Docker Hardened Images
}

# Require HTTPS for all downloads
allow if {
  input.http.schema == "https"
}

decision := {"allow": allow}
```

This policy allows local and Git contexts, images from Docker Hub, GitHub
Container Registry, and [Docker Hardened Images](/dhi/), and `ADD` downloads
over HTTPS. It blocks HTTP downloads and non-standard registries.

When to use: Starting point for teams new to policies. Provides basic security
without disrupting development workflows.

### Registry allowlist

Control which registries your builds can pull images from.

```rego
package docker

default allow := false

allow if input.local

# TODO: Add your internal registry hostname
allowed_registries := ["docker.io", "ghcr.io", "dhi.io", "registry.company.com"]

allow if {
  input.image.host in allowed_registries
}

# Allow mirrored DHI images from Docker Hub (DHI Enterprise users)
# TODO: Replace with your organization namespace
allow if {
  input.image.host == "docker.io"
  startswith(input.image.repo, "myorg/dhi-")
}

deny_msg contains msg if {
  not allow
  input.image
  msg := sprintf("registry %s is not in the allowlist", [input.image.host])
}

decision := {"allow": allow, "deny_msg": deny_msg}
```

This policy restricts image pulls to approved registries. Customize and add
your internal registry to the list. If you have a DHI Enterprise subscription
and have mirrored Docker Hardened Images to Docker Hub, add a rule to allow
images from your organization's namespace.

When to use: Enforce corporate policies about approved image sources. Prevents
developers from using arbitrary public registries.

### Pin base images to digests

Require digest references for reproducible builds.

```rego
package docker

default allow := false

allow if input.local

# Require digest references for all images
allow if {
  input.image.isCanonical
}

deny_msg contains msg if {
  not allow
  input.image
  msg := sprintf("image %s must use digest reference (e.g., @sha256:...)", [input.image.ref])
}

decision := {"allow": allow, "deny_msg": deny_msg}
```

This policy requires images use digest references like
`alpine@sha256:abc123...` instead of tags like `alpine:3.19`. Digests are
immutable - the same digest always resolves to the same image content.

When to use: Ensure build reproducibility. Prevents builds from breaking when
upstream tags are updated. Required for compliance in some environments.

### Control external dependencies

Pin specific versions of dependencies downloaded during builds.

```rego
package docker

default allow := false

allow if input.local

# Allow any image (add restrictions as needed)
allow if input.image

# TODO: Add your allowed Git repositories and tags
allowed_repos := {
  "https://github.com/moby/buildkit.git": ["v0.26.1", "v0.27.0"],
}
# Only allow Git input from allowed_repos
allow if {
  some repo, versions in allowed_repos
  input.git.remote == repo
  input.git.tagName in versions
}

# TODO: Add your allowed downloads
allow if {
  input.http.url == "https://example.com/app-v1.0.tar.gz"
}

decision := {"allow": allow}
```

This policy creates allowlists for external dependencies. Add your Git
repositories with approved version tags, and URLs.

When to use: Control which external dependencies can be used in builds.
Prevents builds from pulling arbitrary versions or unverified downloads.

## Production templates

These templates demonstrate comprehensive security patterns. They require
customization but show best practices for production environments.

### Image attestation and provenance

Require images have provenance attestations from trusted builders.

```rego
package docker

default allow := false

allow if input.local

# TODO: Add your repository names
allowed_repos := ["myorg/backend", "myorg/frontend", "myorg/worker"]

# Production images need full attestations
allow if {
  some repo in allowed_repos
  input.image.repo == repo
  input.image.hasProvenance
  some sig in input.image.signatures
  trusted_github_builder(sig, repo)
}

# Helper to validate GitHub Actions build from main branch
trusted_github_builder(sig, repo) if {
  sig.signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
  sig.signer.issuer == "https://token.actions.githubusercontent.com"
  startswith(sig.signer.buildSignerURI, sprintf("https://github.com/myorg/%s/.github/workflows/", [repo]))
  sig.signer.sourceRepositoryRef == "refs/heads/main"
  sig.signer.runnerEnvironment == "github-hosted"
}

# Allow Docker Hardened Images with built-in attestations
allow if {
  input.image.host == "dhi.io"
  input.image.isCanonical
  input.image.hasProvenance
}

# Allow official base images with digests
allow if {
  input.image.repo == "alpine"
  input.image.host == "docker.io"
  input.image.isCanonical
}

decision := {"allow": allow}
```

This template validates that your application images have provenance
attestations, and were built by GitHub Actions from your main branch. Docker
Hardened Images are allowed when using digests since they include comprehensive
attestations by default. Other base images must use digests.

Customize:

- Replace `allowed_repos` with your image names
- Update the organization name in `trusted_github_builder()`
- Add rules for other base images you use

When to use: Enforce supply chain security for production deployments. Ensures
images are built by trusted CI/CD pipelines with auditable provenance.

### Signed Git releases

Enforce signed tags from trusted maintainers for Git dependencies.

```rego
package docker

default allow := false

allow if input.local

allow if input.image

# TODO: Replace with your repository URL
is_buildkit if {
    input.git.remote == "https://github.com/moby/buildkit.git"
}

is_version_tag if {
    is_buildkit
    regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}

# Version tags must be signed
allow if {
    is_version_tag
    input.git.tagName != ""
    verify_git_signature(input.git.tag, "maintainers.asc")
}

# Allow unsigned refs for development
allow if {
    is_buildkit
    not is_version_tag
}

decision := {"allow": allow}
```

This template requires production release tags to be signed by trusted
maintainers. Development branches and commits can be unsigned.

Setup:

1. Export maintainer PGP public keys to `maintainers.asc`:
   ```console
   $ gpg --export --armor user1@example.com user2@example.com > maintainers.asc
   ```
2. Place `maintainers.asc` in the same directory as your policy file

Customize:

- Replace the repository URL in `is_buildkit`
- Update the maintainers in the PGP keyring file
- Adjust the version tag regex pattern if needed

When to use: Validate that production dependencies come from signed releases.
Protects against compromised releases or unauthorized updates.

### Multi-registry policy

Apply different validation rules for internal and external registries.

```rego
package docker

default allow := false

allow if input.local

# TODO: Replace with your internal registry hostname
internal_registry := "registry.company.com"

# Internal registry: basic validation
allow if {
  input.image.host == internal_registry
}

# External registries: strict validation
allow if {
  input.image.host != internal_registry
  input.image.host != ""
  input.image.isCanonical
  input.image.hasProvenance
}

# Docker Hub: allowlist specific images
allow if {
  input.image.host == "docker.io"
  # TODO: Add your approved base images
  input.image.repo in ["alpine", "golang", "node"]
  input.image.isCanonical
}

# Docker Hardened Images: trusted by default with built-in attestations
allow if {
  input.image.host == "dhi.io"
  input.image.isCanonical
}

decision := {"allow": allow}
```

This template defines a trust boundary between internal and external image
sources. Internal images require minimal validation, while external images need
digests and provenance. Docker Hardened Images from `dhi.io` are treated as
trusted since they include comprehensive attestations and security guarantees.

Customize:

- Set your internal registry hostname
- Add your approved Docker Hub base images
- Adjust validation requirements based on your security policies

When to use: Organizations with internal registries that need different rules
for internal and external sources. Balances security with practical workflow
needs.

### Multi-environment policy

Apply different rules based on the build target or stage. For example,

```rego
package docker

default allow := false

allow if input.local

# TODO: Define your environment detection logic
is_production if {
  input.env.target == "production"
}

is_development if {
  input.env.target == "development"
}

# Production: strict rules - only digest images with provenance
allow if {
  is_production
  input.image.isCanonical
  input.image.hasProvenance
}

# Development: permissive rules - any image
allow if {
  is_development
  input.image
}

# Staging inherits production rules (default target detection)
allow if {
  not is_production
  not is_development
  input.image.isCanonical
}

decision := {"allow": allow}
```

This template uses build targets to apply different validation levels.
Production requires attestations and digests, development is permissive, and
staging uses moderate rules.

Customize:

- Update environment detection logic (target names, build args, etc.)
- Adjust validation requirements for each environment
- Add more environments as needed

When to use: Teams with separate build configurations for different deployment
stages. Allows flexibility in development while enforcing strict rules for
production.

### Complete dependency pinning

Pin all external dependencies to specific versions across all input types.

```rego
package docker

default allow := false

allow if input.local

# TODO: Add your pinned images with exact digests
# Docker Hub images use docker.io as host
allowed_dockerhub := {
  "alpine": "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412",
  "golang": "sha256:abc123...",
}

allow if {
  input.image.host == "docker.io"
  some repo, digest in allowed_dockerhub
  input.image.repo == repo
  input.image.checksum == digest
}

# TODO: Add your pinned DHI images
allowed_dhi := {
  "python": "sha256:def456...",
  "node": "sha256:ghi789...",
}

allow if {
  input.image.host == "dhi.io"
  some repo, digest in allowed_dhi
  input.image.repo == repo
  input.image.checksum == digest
}

# TODO: Add your pinned Git dependencies
allowed_git := {
  "https://github.com/moby/buildkit.git": {
    "tag": "v0.26.1",
    "commit": "abc123...",
  },
}

allow if {
  some url, version in allowed_git
  input.git.remote == url
  input.git.tagName == version.tag
  input.git.commitChecksum == version.commit
}

# TODO: Add your pinned HTTP downloads
allowed_downloads := {
  "https://releases.example.com/app-v1.0.tar.gz": "sha256:def456...",
}

allow if {
  some url, checksum in allowed_downloads
  input.http.url == url
  input.http.checksum == checksum
}

decision := {"allow": allow}
```

This template pins every external dependency to exact versions with cryptographic
verification. Images use digests, Git repos use commit SHAs, and downloads use
checksums.

Customize:

- Add all your dependencies with exact versions/checksums
- Maintain this file when updating dependencies
- Consider automating updates through CI/CD

When to use: Maximum reproducibility and security. Ensures builds always use
exact versions of all dependencies. Required for high-security or regulated
environments.

### Manual signature verification

Verify image signatures by inspecting signature metadata fields.

```rego
package docker

default allow := false

allow if input.local

# Require valid GitHub Actions signatures
allow if {
    input.image
    input.image.hasProvenance
    some sig in input.image.signatures
    valid_github_signature(sig)
}

# Helper function to validate GitHub Actions signature
valid_github_signature(sig) if {
    # Sigstore keyless signing
    sig.signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
    sig.signer.issuer == "https://token.actions.githubusercontent.com"

    # TODO: Replace with your organization
    startswith(sig.signer.buildSignerURI, "https://github.com/myorg/.github/workflows/")
    startswith(sig.signer.sourceRepositoryURI, "https://github.com/myorg/")

    # Verify GitHub hosted runner
    sig.signer.runnerEnvironment == "github-hosted"

    # Require timestamp
    count(sig.timestamps) > 0
}

decision := {"allow": allow}
```

This policy validates that images were built by GitHub Actions using Sigstore
keyless signing.

Customize:

- Replace `myorg` with your GitHub organization
- Adjust workflow path restrictions
- Add additional signature field checks as needed

When to use: Enforce that images are built by CI/CD with verifiable signatures,
not manually pushed by developers.

## Next steps

- Write unit tests for your policies: [Test build policies](testing.md)
- Review [Built-in functions](built-ins.md) for signature verification and
  attestation checking
- Check the [Input reference](inputs.md) for all available fields you can
  validate
- Read the tutorials for detailed explanations:
  [Introduction](intro.md), [Image validation](validate-images.md), [Git
  validation](validate-git.md)


---

# Input reference

*Sección: Build*

When Buildx evaluates policies, it provides information about build inputs
through the `input` object. The structure of `input` depends on the type of
resource your Dockerfile references.

## Input types

Build inputs correspond to Dockerfile instructions:

| Dockerfile instruction                  | Input type | Access pattern |
| --------------------------------------- | ---------- | -------------- |
| `FROM alpine:latest`                    | Image      | `input.image`  |
| `COPY --from=builder /app /app`         | Image      | `input.image`  |
| `ADD https://example.com/file.tar.gz /` | HTTP       | `input.http`   |
| `ADD git@github.com:user/repo.git /src` | Git        | `input.git`    |
| Build context (`.`)                     | Local      | `input.local`  |

Each input type has specific fields available for policy evaluation.

## HTTP inputs

HTTP inputs represent files downloaded over HTTP or HTTPS using the `ADD`
instruction.

### Example Dockerfile

```dockerfile
FROM alpine
ADD --checksum=sha256:abc123... https://example.com/app.tar.gz /app.tar.gz
```

### Available fields

#### `input.http.url`

The complete URL of the resource.

```rego
allow if {
    input.http.url == "https://example.com/app.tar.gz"
}
```

#### `input.http.schema`

The URL scheme (`http` or `https`).

```rego
# Require HTTPS for all downloads
allow if {
    input.http.schema == "https"
}
```

#### `input.http.host`

The hostname from the URL.

```rego
# Allow downloads from approved domains
allow if {
    input.http.host == "cdn.example.com"
}
```

#### `input.http.path`

The path component of the URL.

```rego
allow if {
    startswith(input.http.path, "/releases/")
}
```

#### `input.http.checksum`

The checksum specified with `ADD --checksum=...`, if present. Empty string if
no checksum was provided.

```rego
# Require checksums for all downloads
allow if {
    input.http.checksum != ""
}
```

#### `input.http.hasAuth`

Boolean indicating if the request includes authentication (HTTP basic auth or
bearer token).

```rego
# Require authentication for internal servers
allow if {
    input.http.host == "internal.company.com"
    input.http.hasAuth
}
```

## Image inputs

Image inputs represent container images from `FROM` instructions or
`COPY --from` references.

### Example Dockerfile

```dockerfile
FROM alpine:3.19@sha256:abc123...
COPY --from=builder:latest /app /app
```

### Available fields

#### `input.image.ref`

The complete image reference as written in the Dockerfile.

```rego
allow if {
    input.image.ref == "alpine:3.19@sha256:abc123..."
}
```

#### `input.image.host`

The registry hostname. Docker Hub images use `"docker.io"`.

```rego
# Only allow Docker Hub images
allow if {
    input.image.host == "docker.io"
}

# Only allow images from GitHub Container Registry
allow if {
    input.image.host == "ghcr.io"
}
```

#### `input.image.repo`

The repository name without the registry host.

```rego
allow if {
    input.image.repo == "library/alpine"
}
```

#### `input.image.fullRepo`

The full repository path including registry host.

```rego
allow if {
    input.image.fullRepo == "docker.io/library/alpine"
}
```

#### `input.image.tag`

The tag portion of the reference. Empty if using a digest reference.

```rego
# Allow only specific tags
allow if {
    input.image.tag == "3.19"
}
```

#### `input.image.isCanonical`

Boolean indicating if the reference uses a digest (`@sha256:...`).

```rego
# Require digest references
allow if {
    input.image.isCanonical
}
```

#### `input.image.checksum`

The SHA256 digest of the image manifest.

```rego
allow if {
    input.image.checksum == "sha256:abc123..."
}
```

#### `input.image.platform`

The target platform for multi-platform images.

```rego
allow if {
    input.image.platform == "linux/amd64"
}
```

#### `input.image.os`

The operating system from the image configuration.

```rego
allow if {
    input.image.os == "linux"
}
```

#### `input.image.arch`

The CPU architecture from the image configuration.

```rego
allow if {
    input.image.arch == "amd64"
}
```

#### `input.image.hasProvenance`

Boolean indicating if the image has provenance attestations.

```rego
# Require provenance for production images
allow if {
    input.image.hasProvenance
}
```

#### `input.image.labels`

A map of image labels from the image configuration.

```rego
# Check for specific labels
allow if {
    input.image.labels["org.opencontainers.image.vendor"] == "Example Corp"
}
```

#### `input.image.signatures`

Array of attestation signatures. Each signature in the array has the following
fields:

- `kind`: Signature kind (e.g., `"docker-github-builder"`, `"self-signed"`)
- `type`: Signature type (e.g., `"bundle-v0.3"`, `"simplesigning-v1"`)
- `timestamps`: Trusted timestamps from transparency logs
- `dockerReference`: Docker image reference
- `isDHI`: Boolean indicating if this is a Docker Hardened Image
- `signer`: Sigstore certificate details

```rego
# Require at least one signature
allow if {
    count(input.image.signatures) > 0
}
```

For Sigstore signatures, the `signer` object provides detailed certificate
information from the signing workflow:

- `certificateIssuer`: Certificate issuer
- `subjectAlternativeName`: Subject alternative name from certificate
- `buildSignerURI`: URI of the build signer
- `buildSignerDigest`: Digest of the build signer
- `runnerEnvironment`: CI/CD runner environment
- `sourceRepositoryURI`: Source repository URL
- `sourceRepositoryDigest`: Source repository digest
- `sourceRepositoryRef`: Source repository ref (branch/tag)
- `sourceRepositoryIdentifier`: Source repository identifier
- `sourceRepositoryOwnerURI`: Repository owner URI
- `buildConfigURI`: Build configuration URI
- `buildTrigger`: What triggered the build
- `runInvocationURI`: CI/CD run invocation URI

```rego
# Require signatures from GitHub Actions
allow if {
    some sig in input.image.signatures
    sig.signer.runnerEnvironment == "github-hosted"
    startswith(sig.signer.sourceRepositoryURI, "https://github.com/myorg/")
}
```

## Git inputs

Git inputs represent Git repositories referenced in `ADD` instructions or used
as build context.

### Example Dockerfile

```dockerfile
ADD git@github.com:moby/buildkit.git#v0.12.0 /src
```

### Available fields

#### `input.git.schema`

The URL scheme (`https`, `http`, `git`, or `ssh`).

```rego
# Require HTTPS for Git clones
allow if {
    input.git.schema == "https"
}
```

#### `input.git.host`

The Git host (e.g., `github.com`, `gitlab.com`).

```rego
allow if {
    input.git.host == "github.com"
}
```

#### `input.git.remote`

The complete Git URL.

```rego
allow if {
    input.git.remote == "https://github.com/moby/buildkit.git"
}
```

#### `input.git.ref`

The Git reference.

```rego
allow if {
    input.git.ref == "refs/heads/master"
}
```

#### `input.git.tagName`

The tag name if the reference is a tag.

```rego
# Only allow version tags
allow if {
    regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}
```

#### `input.git.branch`

The branch name if the reference is a branch.

```rego
allow if {
    input.git.branch == "main"
}
```

#### `input.git.subDir`

The subdirectory path within the repository, if specified.

```rego
# Ensure clones are from the root
allow if {
    input.git.subDir == ""
}
```

#### `input.git.isCommitRef`

Boolean indicating if the reference is a commit SHA (as opposed to a branch or
tag name).

```rego
# Require commit SHAs for production
allow if {
    input.env.target == "production"
    input.git.isCommitRef
}
```

#### `input.git.checksum`

The checksum of the Git reference. For commit references and branches, this is
the commit hash. For annotated tags, this is the tag object hash.

```rego
allow if {
    input.git.checksum == "abc123..."
}
```

#### `input.git.commitChecksum`

The commit hash that the reference points to. For annotated tags, this differs
from `checksum` (which is the tag object hash). For commit references and
branches, this is the same as `checksum`.

```rego
allow if {
    input.git.commitChecksum == "abc123..."
}
```

#### `input.git.isAnnotatedTag`

Boolean indicating if the reference is an annotated tag (as opposed to a
lightweight tag).

```rego
# Require annotated tags
allow if {
    input.git.tagName != ""
    input.git.isAnnotatedTag
}
```

#### `input.git.commit`

Object containing commit metadata:

- `author`: Author name, email, when
- `committer`: Committer name, email, when
- `message`: Commit message
- `pgpSignature`: PGP signature details if signed
- `sshSignature`: SSH signature details if signed

```rego
# Check commit author
allow if {
    input.git.commit.author.email == "maintainer@example.com"
}
```

#### `input.git.tag`

Object containing tag metadata for annotated tags:

- `tagger`: Tagger name, email, when
- `message`: Tag message
- `pgpSignature`: PGP signature details if signed
- `sshSignature`: SSH signature details if signed

```rego
# Require signed tags
allow if {
    input.git.tag.pgpSignature != null
}
```

## Local inputs

Local inputs represent the build context directory.

### Available fields

#### `input.local.name`

The name or path of the local context.

```rego
allow if {
    input.local.name == "."
}
```

Local inputs are typically less restricted than remote inputs, but you can
still write policies to enforce context requirements.

## Environment fields

The `input.env` object provides build configuration information set by user on
invoking the build, not specific to a resource type.

### Available fields

#### `input.env.filename`

The name of the Dockerfile being built.

```rego
# Stricter rules for production Dockerfile
allow if {
    input.env.filename == "Dockerfile"
    input.image.isCanonical
}

# Relaxed rules for development
allow if {
    input.env.filename == "Dockerfile.dev"
}
```

#### `input.env.target`

The build target from multi-stage builds.

```rego
# Require signing only for release builds
allow if {
    input.env.target == "release"
    input.git.tagName != ""
    verify_git_signature(input.git.tag, "maintainer.asc")
}
```

#### `input.env.args`

Build arguments passed with `--build-arg`. Access specific arguments by key.

```rego
# Check build argument values
allow if {
    input.env.args.ENVIRONMENT == "production"
    input.image.hasProvenance
}
```

## Next steps

- See [Built-in functions](built-ins.md) for built-in helper functions to
  check and validate input properties
- Browse [Example policies](examples.md) for common patterns
- Read about [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/)
  for advanced policy logic


---

# Introduction to build policies

*Sección: Build*

Build policies let you validate the inputs to your Docker builds before they
run. This tutorial walks you through creating your first policy, teaching the
Rego basics you need along the way.

## What you'll learn

By the end of this tutorial, you'll understand:

- How to create and organize policy files
- Basic Rego syntax and patterns
- How to write policies that validate URLs, checksums, and images
- How policies evaluate during builds

## Prerequisites

- Buildx version 0.31 or later
- Basic familiarity with Dockerfiles and building images

## How policies work

When you build an image, Buildx resolves all the inputs your
Dockerfile references: base images from `FROM` instructions, files
from `ADD` or `COPY` or build contexts, and Git repositories. Before
running the build, Buildx evaluates your policies against these
inputs. If any input violates a policy, the build fails before any
instructions execute.

Policies are written in Rego, a declarative language designed for expressing
rules and constraints. You don't need to know Rego to get started - this
tutorial teaches you what you need.

## Create your first policy

Create a new directory for this tutorial and add a Dockerfile:

```console
$ mkdir policy-tutorial
$ cd policy-tutorial
```

Create a `Dockerfile` that downloads a file with `ADD`:

```dockerfile
FROM scratch
ADD https://example.com/index.html /index.html
```

Now create a policy file. Policies use the `.rego` extension and live alongside
your Dockerfile. Create `Dockerfile.rego`:

```rego {title="Dockerfile.rego"}
package docker

default allow := false

allow if input.local
allow if {
  input.http.host == "example.com"
}

decision := {"allow": allow}
```

Save this file as `Dockerfile.rego` in the same directory as your Dockerfile.

Let's break down what this policy does:

- `package docker` - All build policies must start with this package declaration
- `default allow := false` - This example uses a deny-by-default rule: if inputs do not match an `allow` rule, the policy check fails
- `allow if input.local` - The first rule allows any local files (your build context)
- `allow if { input.http.host == "example.com" }` - The second rule allows HTTP downloads from `example.com`
- `decision := {"allow": allow}` - The final decision object tells Buildx whether to allow or deny the input

This policy says: "Only allow local files and HTTP downloads from
`example.com`". Rego evaluates all the policy rules to figure out the return
value for the `decision` variable, for each build input. The evaluations happen
in parallel and on-demand; the order of the policy rules has no significance.

### About `input.local`

You'll see `allow if input.local` in nearly every policy. This rule allows
local file access, which includes your build context (typically, the `.`
directory) and importantly, the Dockerfile itself. Without this rule, Buildx
can't read your Dockerfile to start the build.

Even builds that don't reference any files from the build context often need
`input.local` because the Dockerfile is a local file. The policy evaluates
before the build starts, and denying local access means denying access to the
Dockerfile.

In rare cases, you might want stricter local file policies - for example, in CI
builds where the build context uses a Git URL as a context directly. In these
cases, you may want to deny local sources to prevent untracked files or changes
from making their way into your build.

## Automatic policy loading

Buildx automatically loads policies that match your Dockerfile name. When you
build with `Dockerfile`, Buildx looks for `Dockerfile.rego` in the same
directory. For a file named `app.Dockerfile`, it looks for
`app.Dockerfile.rego`.

This automatic loading means you don't need any command-line flags in most
cases - create the policy file and build.

The policy file must be in the same directory as the Dockerfile. If Buildx
can't find a matching policy, the build proceeds without policy evaluation
(unless you use `--policy strict=true`).

For more control over policy loading, see the [Usage guide](usage.md).

## Run a build with your policy

Build the image with policy evaluation enabled:

```console
$ docker build .
```

The build succeeds because the URL in your Dockerfile matches the policy. Now
try changing the URL in your Dockerfile to something else:

```dockerfile
FROM scratch
ADD https://api.github.com/users/octocat /user.json
```

Build again:

```console
$ docker build .
```

This time the build fails with a policy violation. The `api.github.com`
hostname doesn't match the rule in your policy, so Buildx rejects it before
running any build steps.

## Debugging policy failures

If your build fails with a policy violation, use `--progress=plain` to see
exactly what went wrong:

```console
$ docker buildx build --progress=plain .
```

This shows all policy checks, the input data for each source, and allow/deny
decisions. For complete debugging guidance, see [Debugging](debugging.md).

## Add helpful error messages

When a policy denies an input, users see a generic error message. You can
provide custom messages that explain why the build was denied:

```rego {title="Dockerfile.rego"}
package docker

default allow := false

allow if input.local
allow if {
  input.http.host == "example.com"
  input.http.schema == "https"
}

deny_msg contains msg if {
  not allow
  input.http
  msg := "only HTTPS downloads from example.com are allowed"
}

decision := {"allow": allow, "deny_msg": deny_msg}
```

Now when a build is denied, users see your custom message explaining what went
wrong:

```console
$ docker buildx build .
Policy: only HTTPS downloads from example.com are allowed
ERROR: failed to build: ... source not allowed by policy
```

The `deny_msg` rule uses `contains` to add messages to a set. You can add
multiple deny messages for different failure conditions to help users understand
exactly what needs to change.

## Understand Rego rules

Rego policies are built from rules. A rule defines when something is allowed.
The basic pattern is:

```rego
allow if {
    condition_one
    condition_two
    condition_three
}
```

All conditions must be true for the rule to match. Think of it as an AND
operation - the URL must match AND the checksum must match AND any other
conditions you specify.

You can have multiple `allow` rules in one policy. If any rule matches, the
input is allowed:

```rego
# Allow downloads from example.com
allow if {
    input.http.host == "example.com"
}

# Also allow downloads from api.github.com
allow if {
    input.http.host == "api.github.com"
}
```

This works like OR - the input can match the first rule OR the second rule.

## Access input fields

The `input` object gives you access to information about build inputs. The
structure depends on the input type:

- `input.http` - Files downloaded with `ADD https://...`
- `input.image` - Container images from `FROM` or `COPY --from`
- `input.git` - Git repositories from `ADD git://...` or build context
- `input.local` - Local file context

Refer to the [Input reference](inputs.md) for all available input fields.

For HTTP downloads, you can access:

| Key                 | Description                        | Example                          |
| ------------------- | ---------------------------------- | -------------------------------- |
| `input.http.url`    | The full URL                       | `https://example.com/index.html` |
| `input.http.schema` | The protocol (HTTP/HTTPS)          | `https`                          |
| `input.http.host`   | The hostname                       | `example.com`                    |
| `input.http.path`   | The URL path, including parameters | `/index.html`                    |

Update your policy to require HTTPS:

```rego
package docker

default allow := false

allow if {
    input.http.host == "example.com"
    input.http.schema == "https"
}

decision := {"allow": allow}
```

Now the policy requires both the hostname to be `example.com` and the protocol
to be HTTPS. HTTP URLs (without TLS) would fail the policy check.

## Pattern matching and strings

Rego provides [built-in functions] for pattern matching. Use `startswith()` to
match URL prefixes:

[built-in functions]: https://www.openpolicyagent.org/docs/policy-language#built-in-functions

```rego
allow if {
    startswith(input.http.url, "https://example.com/")
}
```

This allows any URL that starts with `https://example.com/`.

Use `regex.match()` for complex patterns:

```rego
allow if {
    regex.match(`^https://example\.com/.+\.json$`, input.http.url)
}
```

This matches URLs that:

- Start with `https://example.com/`
- End with `.json`
- Have at least one character between the domain and extension

## Policy file location

Policy files live adjacent to the Dockerfile they validate, using the naming
pattern `<dockerfile-name>.rego`:

```text
project/
├── Dockerfile           # Main Dockerfile
├── Dockerfile.rego      # Policy for Dockerfile
├── lint.Dockerfile      # Linting Dockerfile
└── lint.Dockerfile.rego # Policy for lint.Dockerfile
```

When you build, Buildx automatically loads the corresponding policy file:

```console
$ docker buildx build -f Dockerfile .        # Loads Dockerfile.rego
$ docker buildx build -f lint.Dockerfile .   # Loads lint.Dockerfile.rego
```

## Next steps

You now understand how to write basic build policies for HTTP resources. To
continue learning:

- Apply and test policies: [Using build policies](usage.md)
- Learn [Image validation](validate-images.md) to validate container images
  from `FROM` instructions
- Learn [Git validation](validate-git.md) to validate Git repositories used
  in builds
- See [Example policies](examples.md) for copy-paste-ready policies covering
  common scenarios
- Write unit tests for your policies: [Test build policies](testing.md)
- Debug policy failures: [Debugging](debugging.md)
- Read the [Input reference](inputs.md) for all available input fields
- Check the [Built-in functions](built-ins.md) for signature verification,
  attestations, and other security checks


---

# Test build policies

*Sección: Build*

The [`docker buildx policy test`](/reference/cli/docker/buildx/policy/test/)
command runs unit tests for build policies using OPA's [standard test
framework](https://www.openpolicyagent.org/docs/policy-testing).

```console
$ docker buildx policy test <path>
```

This validates policy logic with mocked inputs.

For testing against real sources (actual image metadata, Git repositories), use
[`docker buildx policy eval`](/reference/cli/docker/buildx/policy/eval/)
instead. You can use the `eval --print` option to resolve input for a specific
source for writing a test case.

## Basic example

Start with a simple policy that only allows `alpine` images:

```rego {title="Dockerfile.rego"}
package docker

default allow = false

allow if {
    input.image.repo == "alpine"
}

decision := {"allow": allow}
```

Create a test file with the `*_test.rego` suffix. Test functions must start
with `test_`:

```rego {title="Dockerfile_test.rego"}
package docker

test_alpine_allowed if {
    decision.allow with input as {"image": {"repo": "alpine"}}
}

test_ubuntu_denied if {
    not decision.allow with input as {"image": {"repo": "ubuntu"}}
}
```

Run the tests:

```console
$ docker buildx policy test .
test_alpine_allowed: PASS (allow=true)
test_ubuntu_denied: PASS (allow=false)
```

`PASS` indicates that the tests defined in `Dockerfile_test.rego` executed
successfully and all assertions were satisfied.

## Command options

Filter tests by name with `--run`:

```console
$ docker buildx policy test --run alpine .
test_alpine_allowed: PASS (allow=true)
```

Test policies with non-default filenames using `--filename`:

```console
$ docker buildx policy test --filename app.Dockerfile .
```

This loads `app.Dockerfile.rego` and runs `*_test.rego` files against it.

## Test output

Passed tests show the allow status and any deny messages:

```console
test_alpine_allowed: PASS (allow=true)
test_ubuntu_denied: PASS (allow=false, deny_msg=only alpine images are allowed)
```

Failed tests show input, decision output, and missing fields:

```console
test_invalid: FAIL (allow=false)
input:
  {
    "image": {}
  }
decision:
  {
    "allow": false,
    "deny_msg": [
      "only alpine images are allowed"
    ]
  }
missing_input: input.image.repo
```

## Test deny messages

To test custom error messages, capture the full decision result and assert on
the `deny_msg` field.

For a policy with deny messages:

```rego {title="Dockerfile.rego"}
package docker

default allow = false

allow if {
    input.image.repo == "alpine"
}

deny_msg contains msg if {
    not allow
    msg := "only alpine images are allowed"
}

decision := {"allow": allow, "deny_msg": deny_msg}
```

Test the deny message:

```rego {title="Dockerfile_test.rego"}
test_deny_message if {
    result := decision with input as {"image": {"repo": "ubuntu"}}
    not result.allow
    "only alpine images are allowed" in result.deny_msg
}
```

## Test patterns

**Test environment-specific rules:**

```rego
test_production_requires_digest if {
    decision.allow with input as {
        "env": {"target": "production"},
        "image": {"isCanonical": true}
    }
}

test_development_allows_tags if {
    decision.allow with input as {
        "env": {"target": "development"},
        "image": {"isCanonical": false}
    }
}
```

**Test multiple registries:**

```rego
test_dockerhub_allowed if {
    decision.allow with input as {
        "image": {
            "ref": "docker.io/library/alpine",
            "host": "docker.io",
            "repo": "alpine"
        }
    }
}

test_ghcr_allowed if {
    decision.allow with input as {
        "image": {
            "ref": "ghcr.io/myorg/myapp",
            "host": "ghcr.io",
            "repo": "myorg/myapp"
        }
    }
}
```

For available input fields, see the [Input reference](inputs.md).

## Organize test files

The test runner discovers all `*_test.rego` files recursively:

```plaintext
build-policies/
├── Dockerfile.rego
├── Dockerfile_test.rego
└── tests/
    ├── registries_test.rego
    ├── signatures_test.rego
    └── environments_test.rego
```

Run all tests:

```console
$ docker buildx policy test .
```

Or test specific files:

```console
$ docker buildx policy test tests/registries_test.rego
```


---

# Using build policies

*Sección: Build*

Build policies validate inputs before builds execute. This guide covers how to
develop policies iteratively and apply them to real builds with `docker buildx
build` and `docker buildx bake`.

## Prerequisites

- Buildx 0.31.0 or later - Check your version: `docker buildx version`
- BuildKit 0.26.0 or later - Verify with: `docker buildx inspect
  --bootstrap`

If you're using Docker Desktop, ensure you're on a version that includes these
updates.

## Policy development workflow

Buildx automatically loads policies that match your Dockerfile name. When you
build with `Dockerfile`, Buildx looks for `Dockerfile.rego` in the same
directory. For a file named `app.Dockerfile`, it looks for
`app.Dockerfile.rego`. See the [Advanced: Policy configuration](#advanced-policy-configuration)
section for configuration options and manual policy loading.

Writing policies is an iterative process:

1. Start with a basic deny-all policy.
2. Build with debug logging to see what inputs your Dockerfile uses.
3. Add rules to allow specific sources based on the debug output.
4. Test and refine.

### Viewing inputs from your Dockerfile

To see the inputs that your Dockerfile references (images, Git repos, HTTP
downloads), build with debug logging:

```console
$ docker buildx build --progress=plain --policy log-level=debug .
```

Example output for an image source:

```text
#1 0.010 checking policy for source docker-image://alpine:3.19 (linux/arm64)
#1 0.011 policy input: {
#1 0.011   "env": {
#1 0.011     "filename": "."
#1 0.011   },
#1 0.011   "image": {
#1 0.011     "ref": "docker.io/library/alpine:3.19",
#1 0.011     "host": "docker.io",
#1 0.011     "repo": "alpine",
#1 0.011     "tag": "3.19",
#1 0.011     "platform": "linux/arm64"
#1 0.011   }
#1 0.011 }
#1 0.011 unknowns for policy evaluation: [input.image.checksum input.image.labels ...]
#1 0.012 policy decision for source docker-image://alpine:3.19: ALLOW
```

This shows the complete input structure, which fields are unresolved, and the
policy decision for each source. See [Input reference](inputs.md) for all
available fields.

### Testing policies with policy eval

Use [`docker buildx policy eval`](/reference/cli/docker/buildx/policy/eval/) to
test whether your policy allows a specific source without running a full build.

Note: `docker buildx policy eval` tests the source specified as the argument.
It doesn't parse your Dockerfile to evaluate all inputs - for that, [build with
--progress=plain](#viewing-inputs-from-your-dockerfile).

Test if your policy allows the local context:

```console
$ docker buildx policy eval .
```

No output means the policy allowed the source. If denied, you see:

```console
ERROR: policy denied
```

Test other sources:

```console
$ docker buildx policy eval https://example.com              # Test HTTP
$ docker buildx policy eval https://github.com/org/repo.git  # Test Git
```

By default, `--print` shows reference information parsed from the source string
(like `repo`, `tag`, `host`) without fetching from registries. To inspect
metadata that requires fetching the source (like `labels`, `checksum`, or
`hasProvenance`), specify which fields to fetch with `--fields`:

```console
$ docker buildx policy eval --print --fields image.labels docker-image://alpine:3.19
```

Multiple fields can be specified as a comma-separated list.

### Iterative development example

Here's a practical workflow for developing policies:

1. Start with basic deny-all policy:

   ```rego {title="Dockerfile.rego"}
   package docker

   default allow := false

   allow if input.local

   decision := {"allow": allow}
   ```

2. Build with debug logging to see what inputs your Dockerfile uses:

   ```console
   $ docker buildx build --progress=plain --policy log-level=debug .
   ```

   The output shows the denied image and its input structure:

   ```text
   #1 0.026 checking policy for source docker-image://docker.io/library/alpine:3.19
   #1 0.027 policy input: {
   #1 0.027   "image": {
   #1 0.027     "repo": "alpine",
   #1 0.027     "tag": "3.19",
   #1 0.027     ...
   #1 0.027   }
   #1 0.027 }
   #1 0.028 policy decision for source docker-image://alpine:3.19: DENY
   #1 ERROR: source "docker-image://alpine:3.19" not allowed by policy
   ```

3. Add a rule allowing the alpine image:

   ```rego
   allow if {
       input.image.repo == "alpine"
   }
   ```

4. Build again to verify the policy works:

   ```console
   $ docker buildx build .
   ```

If it fails, see [Debugging](debugging.md) for troubleshooting guidance.

## Using policies with `docker build`

Once you've developed and tested your policy, apply it to real builds.

### Basic usage

Create a policy alongside your Dockerfile:

```dockerfile {title="Dockerfile"}
FROM alpine:3.19
RUN echo "hello"
```

```rego {title="Dockerfile.rego"}
package docker

default allow := false

allow if input.local

allow if {
    input.image.repo == "alpine"
}

decision := {"allow": allow}
```

Build normally:

```console
$ docker buildx build .
```

Buildx loads the policy automatically and validates the `alpine:3.19` image
before building.

### Build with different Dockerfile names

Specify the Dockerfile with `-f`:

```console
$ docker buildx build -f app.Dockerfile .
```

Buildx looks for `app.Dockerfile.rego` in the same directory.

### Build with manual policy

Add an extra policy to the automatic one:

```console
$ docker buildx build --policy filename=extra-checks.rego .
```

Both `Dockerfile.rego` (automatic) and `extra-checks.rego` (manual) must pass.

### Build without automatic policy

Use only your specified policy:

```console
$ docker buildx build --policy reset=true,filename=strict.rego .
```

## Using policies with bake

[Bake](/build/bake/) supports automatic policy loading just like `docker buildx
build`. Place `Dockerfile.rego` alongside your Dockerfile and run:

```console
$ docker buildx bake
```

### Manual policy in bake files

Specify additional policies in your `docker-bake.hcl`:

```hcl {title="docker-bake.hcl"}
target "default" {
  dockerfile = "Dockerfile"
  policy = ["extra.rego"]
}
```

The `policy` attribute takes a list of policy files. Bake loads these in
addition to the automatic `Dockerfile.rego` (if it exists).

### Multiple policies in bake

```hcl {title="docker-bake.hcl"}
target "webapp" {
  dockerfile = "Dockerfile"
  policy = [
    "shared/base-policy.rego",
    "security/image-signing.rego"
  ]
}
```

All policies must pass for the target to build successfully.

### Different policies per target

Apply different validation rules to different targets:

```hcl {title="docker-bake.hcl"}
target "development" {
  dockerfile = "dev.Dockerfile"
  policy = ["policies/permissive.rego"]
}

target "production" {
  dockerfile = "prod.Dockerfile"
  policy = ["policies/strict.rego", "policies/signing-required.rego"]
}
```

Build with the appropriate target:

```console
$ docker buildx bake development  # Uses permissive policy
$ docker buildx bake production   # Uses strict policies
```

### Bake with policy options

Currently, bake doesn't support policy options (reset, strict, disabled) in the
HCL file. Use command-line flags instead:

```console
$ docker buildx bake --policy disabled=true production
```

## Testing in CI/CD

Validate policies in continuous integration by running builds with the `--policy` flag. For unit testing policies before running builds, see [Test build policies](testing.md).

Test policies during CI builds:

```yaml {title=".github/workflows/test-policies.yml"}
name: Test Build Policies
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@{{% param "checkout_action_version" %}}
      - uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
      - name: Test build with policy
        run: docker buildx build --policy strict=true .
```

This ensures policy changes don't break builds and that new rules work as
intended. The `strict=true` flag fails the build if policies aren't loaded (for
example, if the BuildKit instance used by the build is too old and doesn't
support policies).

## Advanced: Policy configuration

This section covers advanced policy loading mechanisms and configuration
options.

### Automatic policy loading

Buildx automatically loads policies that match your Dockerfile name. When you
build with `Dockerfile`, Buildx looks for `Dockerfile.rego` in the same
directory. For a file named `app.Dockerfile`, it looks for
`app.Dockerfile.rego`.

```text
project/
├── Dockerfile
├── Dockerfile.rego          # Loaded automatically for Dockerfile
├── app.Dockerfile
├── app.Dockerfile.rego      # Loaded automatically for app.Dockerfile
└── src/
```

This automatic loading means you don't need command-line flags in most cases.
Create the policy file alongside your Dockerfile and build:

```console
$ docker buildx build .
```

Buildx detects `Dockerfile.rego` and evaluates it before running the build.

> [!NOTE]
> Policy files must be in the same directory as the Dockerfile they validate.
> Buildx doesn't search parent directories or subdirectories.

### When policies don't load

If Buildx can't find a matching `.rego` file, the build proceeds without policy
evaluation. To require policies and fail if none are found, use strict mode:

```console
$ docker buildx build --policy strict=true .
```

This fails the build if no policy loads or if the BuildKit daemon doesn't
support policies.

### Manual policy configuration

The `--policy` flag lets you specify additional policies, override automatic
loading, or control policy behavior.

Basic syntax:

```console
$ docker buildx build --policy filename=custom.rego .
```

This loads `custom.rego` in addition to the automatic `Dockerfile.rego` (if it
exists).

Multiple policies:

```console
$ docker buildx build --policy filename=policy1.rego --policy filename=policy2.rego .
```

All policies must pass for the build to succeed. Use this to enforce layered
requirements (base policy + project-specific rules).

Available options:

| Option              | Description                                             | Example                       |
| ------------------- | ------------------------------------------------------- | ----------------------------- |
| `filename=<path>`   | Load policy from specified file                         | `filename=custom.rego`        |
| `reset=true`        | Ignore automatic policies, use only specified ones      | `reset=true`                  |
| `disabled=true`     | Disable all policy evaluation                           | `disabled=true`               |
| `strict=true`       | Fail if BuildKit doesn't support policies               | `strict=true`                 |
| `log-level=<level>` | Control policy logging (error, warn, info, debug, none). Use `debug` to see complete input JSON and unresolved fields | `log-level=debug`             |

Combine options with commas:

```console
$ docker buildx build --policy filename=extra.rego,strict=true .
```

### Exploring sources with policy eval

The `docker buildx policy eval` command lets you quickly explore and test
sources without running a build.

#### Inspect input structure with --print

Use `--print` to see the input structure for any source without running policy
evaluation:

```console
$ docker buildx policy eval --print https://github.com/moby/buildkit.git
```

```json
{
  "git": {
    "schema": "https",
    "host": "github.com",
    "remote": "https://github.com/moby/buildkit.git"
  }
}
```

Test different source types:

```console
# HTTP downloads
$ docker buildx policy eval --print https://releases.hashicorp.com/terraform/1.5.0/terraform.zip

# Images (requires docker-image:// prefix)
$ docker buildx policy eval --print docker-image://alpine:3.19

# Local context
$ docker buildx policy eval --print .
```

Shows information parsed from the source without fetching. Use `--fields` to
fetch specific metadata (see [above](#testing-policies-with-policy-eval)).

#### Test with specific policy files

The `--filename` flag specifies which policy file to load by providing the base
Dockerfile name (without the `.rego` extension). This is useful for testing
sources against policies associated with different Dockerfiles.

For example, to test a source against the policy for `app.Dockerfile`:

```console
$ docker buildx policy eval --filename app.Dockerfile .
```

This loads `app.Dockerfile.rego` and tests whether it allows the source `.`
(the local directory). The flag defaults to `Dockerfile` if not specified.

Test different sources against your policy:

```console
$ docker buildx policy eval --filename app.Dockerfile https://github.com/org/repo.git
$ docker buildx policy eval --filename app.Dockerfile docker-image://alpine:3.19
```

### Reset automatic loading

To use only your specified policies and ignore automatic `.rego` files:

```console
$ docker buildx build --policy reset=true,filename=custom.rego .
```

This skips `Dockerfile.rego` and loads only `custom.rego`.

### Disable policies temporarily

Disable policy evaluation for testing or emergencies:

```console
$ docker buildx build --policy disabled=true .
```

The build proceeds without any policy checks. Use this carefully - you're
bypassing security controls.

## Next steps

- Write unit tests for your policies: [Test build policies](testing.md)
- Debug policy failures: [Debugging](debugging.md)
- Browse working examples: [Example policies](examples.md)
- Reference all input fields: [Input reference](inputs.md)


---

# Validating Git repositories

*Sección: Build*

Git repositories often appear in Docker builds as source code inputs. The `ADD`
instruction can clone repositories, and build contexts can reference Git URLs.
Validating these inputs ensures you're building from trusted sources with
verified versions.

This guide teaches you to write policies that validate Git inputs, from basic
version pinning to verifying signed commits and tags.

## Prerequisites

You should understand the policy basics from the [Introduction](intro.md):
creating policy files, basic Rego syntax, and how policies evaluate during
builds.

## What are Git inputs?

Git inputs come from `ADD` instructions that reference Git repositories:

```dockerfile
# Clone a specific tag
ADD https://github.com/moby/buildkit.git#v0.26.1 /buildkit

# Clone a branch
ADD https://github.com/user/repo.git#main /src

# Clone a commit
ADD https://github.com/user/repo.git#abcde123 /src
```

The build context can also be a Git repository when you build with:

```console
$ docker build https://github.com/user/repo.git#main
```

Each Git reference triggers a policy evaluation. Your policy can inspect
repository URLs, validate versions, check commit metadata, and verify
signatures.

## Match specific repositories

The simplest Git policy restricts which repositories can be used:

```rego {title="Dockerfile.rego"}
package docker

default allow := false

allow if input.local

allow if {
  input.git.host == "github.com"
  input.git.remote == "https://github.com/moby/buildkit.git"
}

decision := {"allow": allow}
```

This policy:

- Denies all inputs by default
- Allows local build context
- Allows only the BuildKit repository from GitHub

The `host` field contains the Git server hostname, and `remote` contains the
full repository URL. Test it:

```dockerfile {title="Dockerfile"}
FROM scratch
ADD https://github.com/moby/buildkit.git#v0.26.1 /
```

```console
$ docker build .
```

The build succeeds. Try a different repository and it fails.

You can match multiple repositories with additional rules:

```rego
allow if {
  input.git.host == "github.com"
  input.git.remote == "https://github.com/moby/buildkit.git"
}

allow if {
  input.git.host == "github.com"
  input.git.remote == "https://github.com/docker/cli.git"
}

decision := {"allow": allow}
```

## Pin to specific versions

Tags and branches can change over time. Pin to specific versions to ensure
reproducible builds:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.git.remote == "https://github.com/moby/buildkit.git"
  input.git.tagName == "v0.26.1"
}

decision := {"allow": allow}
```

The `tagName` field contains the tag name when the Git reference points to a
tag. Use `branch` for branches:

```rego
allow if {
  input.git.remote == "https://github.com/user/repo.git"
  input.git.branch == "main"
}
```

Or use `ref` for any type of reference (branch, tag, or commit SHA):

```rego
allow if {
  input.git.ref == "v0.26.1"
}
```

## Use version allowlists

For repositories you trust but want to control versions, maintain an allowlist:

```rego
package docker

default allow := false

allowed_versions = [
    {"tag": "v0.26.1", "annotated": true, "sha": "abc123"},
]

is_buildkit if {
    input.git.remote == "https://github.com/moby/buildkit.git"
}

allow if {
    not is_buildkit
}

allow if {
    is_buildkit
    some version in allowed_versions
    input.git.tagName == version.tag
    input.git.isAnnotatedTag == version.annotated
    startswith(input.git.commitChecksum, version.sha)
}

decision := {"allow": allow}
```

This policy:

- Defines an allowlist of approved versions with metadata
- Uses a helper rule (`is_buildkit`) for readability
- Allows all non-BuildKit inputs
- For BuildKit, checks the tag name, whether it's an annotated tag, and the commit SHA against the allowlist

The helper rule makes complex policies more maintainable. You can expand the
allowlist as new versions are approved:

```rego
allowed_versions = [
    {"tag": "v0.26.1", "annotated": true, "sha": "abc123"},
    {"tag": "v0.27.0", "annotated": true, "sha": "def456"},
    {"tag": "v0.27.1", "annotated": true, "sha": "789abc"},
]
```

## Validate with regex patterns

Use pattern matching for semantic versioning:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.git.remote == "https://github.com/moby/buildkit.git"
  regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}

decision := {"allow": allow}
```

This allows any BuildKit tag matching the pattern `vX.Y.Z` where X, Y, and Z
are numbers. The regex ensures you're using release versions, not pre-release
tags like `v0.26.0-rc1`.

Match major versions:

```rego
# Only allow v0.x releases
allow if {
  input.git.remote == "https://github.com/moby/buildkit.git"
  regex.match(`^v0\.[0-9]+\.[0-9]+$`, input.git.tagName)
}
```

## Inspect commit metadata

The `commit` object provides detailed information about commits:

```rego
package docker

default allow := false

allow if input.local

# Check commit author
allow if {
  input.git.remote == "https://github.com/user/repo.git"
  input.git.commit.author.email == "trusted@example.com"
}

decision := {"allow": allow}
```

The `commit` object includes:

- `author.name`: Author's name
- `author.email`: Author's email
- `author.when`: When the commit was authored
- `committer.name`: Committer's name
- `committer.email`: Committer's email
- `committer.when`: When the commit was committed
- `message`: Commit message

Validate commit messages:

```rego
allow if {
  input.git.commit
  contains(input.git.commit.message, "Signed-off-by:")
}
```

Pin to specific commit SHA:

```rego
allow if {
  input.git.commitChecksum == "abc123def456..."
}
```

## Require signed commits

GPG-signed commits prove authenticity. Check for commit signatures:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.git.remote == "https://github.com/moby/buildkit.git"
  input.git.commit.pgpSignature != null
}

decision := {"allow": allow}
```

The `pgpSignature` field is `null` for unsigned commits. For signed commits, it
contains signature details.

SSH signatures work similarly:

```rego
allow if {
  input.git.commit.sshSignature != null
}
```

## Require signed tags

Annotated tags can be signed, providing a cryptographic guarantee of the
release:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.git.remote == "https://github.com/moby/buildkit.git"
  input.git.tag.pgpSignature != null
}

decision := {"allow": allow}
```

The `tag` object is only available for annotated tags. It includes:

- `tagger.name`: Who created the tag
- `tagger.email`: Tagger's email
- `tagger.when`: When the tag was created
- `message`: Tag message
- `pgpSignature`: GPP signature (if signed)
- `sshSignature`: SSH signature (if signed)

Lightweight tags don't have a `tag` object, so this policy effectively requires
annotated, signed tags.

## Verify signatures with public keys

Use the `verify_git_signature()` function to cryptographically verify Git
signatures against trusted public keys:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.git.remote == "https://github.com/moby/buildkit.git"
  input.git.tagName != ""
  verify_git_signature(input.git.tag, "keys.asc")
}

decision := {"allow": allow}
```

This verifies that Git tags are signed by keys in the `keys.asc` public
key file. To set this up:

1. Export maintainer public keys:
   ```console
   $ curl https://github.com/user.gpg > keys.asc
   ```
2. Place `keys.asc` alongside your policy file

The function verifies PGP signatures on commits or tags. See [Built-in
functions](built-ins.md) for more details.

## Apply conditional rules

Use different rules for different contexts. Allow unsigned refs during
development but require signing for production:

```rego
package docker

default allow := false

allow if input.local

is_buildkit if {
    input.git.remote == "https://github.com/moby/buildkit.git"
}

is_version_tag if {
    is_buildkit
    regex.match(`^v[0-9]+\.[0-9]+\.[0-9]+$`, input.git.tagName)
}

# Version tags must be signed
allow if {
    is_version_tag
    input.git.tagName != ""
    verify_git_signature(input.git.tag, "keys.asc")
}

# Non-version refs allowed in development
allow if {
    is_buildkit
    not is_version_tag
    input.env.target != "release"
}

decision := {"allow": allow}
```

This policy:

- Defines helper rules for readability
- Requires signed version tags from maintainers
- Allows unsigned refs (branches, commits) unless building the release target
- Uses `input.env.target` to detect the build target

Build a development target without signatures:

```console
$ docker buildx build --target=dev .
```

Build the release target, and signing is enforced:

```console
$ docker buildx build --target=release .
```

## Next steps

You now understand how to validate Git repositories in build policies. To
continue learning:

- Browse [Example policies](examples.md) for complete policy patterns
- Read [Built-in functions](built-ins.md) for Git signature verification
  functions
- Check the [Input reference](inputs.md) for all available Git fields


---

# Validating image inputs

*Sección: Build*

Container images are the most common build inputs. Every `FROM` instruction
pulls an image, and `COPY --from` references pull additional images. Validating
these images protects your build supply chain from compromised registries,
unexpected updates, and unauthorized base images.

This guide teaches you to write policies that validate image inputs,
progressing from basic allowlisting to advanced attestation checks.

## Prerequisites

You should understand the policy basics from the [Introduction](intro.md):
creating policy files, basic Rego syntax, and how policies evaluate during
builds.

## What are image inputs?

Image inputs come from two Dockerfile instructions:

```dockerfile
# FROM instructions
FROM alpine:3.22
FROM golang:1.25-alpine AS builder

# COPY --from references
COPY --from=builder /app /app
COPY --from=nginx:latest /etc/nginx/nginx.conf /nginx.conf
```

Each of these references triggers a policy evaluation. Your policy can inspect
image metadata, verify attestations, and enforce constraints before the build
proceeds.

## Allowlist specific repositories

The simplest image policy restricts which repositories can be used. This
prevents developers from using arbitrary images that haven't been vetted.

Create a policy that only allows Alpine:

```rego {title="Dockerfile.rego"}
package docker

default allow := false

allow if input.local

allow if {
  input.image.repo == "alpine"
}

decision := {"allow": allow}
```

This policy:

- Denies all inputs by default
- Allows local build context
- Allows any image from the `alpine` repository (any tag or digest)

Test it with a Dockerfile:

```dockerfile {title="Dockerfile"}
FROM alpine
RUN echo "hello"
```

```console
$ docker build .
```

The build succeeds. Try changing to `FROM ubuntu`:

```console
$ docker build .
```

The build fails because `ubuntu` doesn't match the allowed repository.

## Compare semantic versions

Restrict images to specific version ranges using Rego's `semver` functions:

```rego
package docker

default allow := false

allow if input.local

# Allow Go 1.21 or newer
allow if {
  input.image.repo == "golang"
  semver.is_valid(input.image.tag)
  semver.compare(input.image.tag, "1.21.0") >= 0
}

decision := {"allow": allow}
```

The `semver.compare(a, b)` function compares semantic versions and returns:

- `-1` if version `a` is less than `b`
- `0` if versions are equal
- `1` if version `a` is greater than `b`

Use `semver.is_valid()` to check if a tag is a valid semantic version before
comparing.

Restrict to specific version ranges:

```rego
allow if {
  input.image.repo == "node"
  version := input.image.tag
  semver.is_valid(version)
  semver.compare(version, "20.0.0") >= 0  # 20.0.0 or newer
  semver.compare(version, "21.0.0") < 0   # older than 21.0.0
}
```

This allows only Node.js 20.x versions. The pattern works for any image using
semantic versioning.

These `semver` functions are standard Rego built-ins documented in the [OPA
policy
reference](https://www.openpolicyagent.org/docs/latest/policy-reference/#semver).

## Require digest references

Tags like `alpine:3.22` can change - someone could push a new image with the
same tag. Digests like `alpine@sha256:abc123...` are immutable.

### Requiring users to provide digests

You can require that users always specify digests in their Dockerfiles:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.image.isCanonical
}

decision := {"allow": allow}
```

The `isCanonical` field is `true` when the user's reference includes a digest.
This policy would allow:

```dockerfile
FROM alpine@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412
```

But reject tag-only references like `FROM alpine:3.22`.

### Pinning to specific digests

Alternatively (or additionally), you can validate that an image's actual digest
matches a specific value, regardless of how the user wrote the reference:

```rego
allow if {
  input.image.repo == "alpine"
  input.image.checksum == "sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412"
}

decision := {"allow": allow}
```

This checks the actual content digest of the pulled image. It would allow both:

```dockerfile
FROM alpine:3.22
FROM alpine@sha256:4b7ce...
```

As long as the resolved image has the specified digest. This is useful for
pinning critical base images to known-good versions.

## Restrict registries

Control which registries your builds can pull from. This helps enforce
corporate policies or restrict to trusted sources.

```rego
package docker

default allow := false

allow if input.local

# Allow Docker Hub images
allow if {
  input.image.host == "docker.io"  # Docker Hub
  input.image.repo == "alpine"
}

# Allow images from internal registry
allow if {
  input.image.host == "registry.company.com"
}

decision := {"allow": allow}
```

The `host` field contains the registry hostname. Docker Hub images use
`"docker.io"` as the host value. Test with:

```dockerfile
FROM alpine                                    # Allowed (Docker Hub)
FROM registry.company.com/myapp:latest         # Allowed (company registry)
FROM ghcr.io/someorg/image:latest              # Denied (wrong registry)
```

Use `fullRepo` when you need the complete path including registry:

```rego
allow if {
  input.image.fullRepo == "docker.io/library/alpine"
}
```

## Validate platform constraints

Multi-architecture images support different operating systems and CPU
architectures. You can restrict builds to specific platforms:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.image.os == "linux"
  input.image.arch in ["amd64", "arm64"]
}

decision := {"allow": allow}
```

This policy:

- Defines supported architectures in a list
- Checks `input.image.os` matches Linux
- Verifies `input.image.arch` is in the supported list

The `os` and `arch` fields come from the image manifest, reflecting the actual
image platform. This works with Docker's automatic platform selection -
policies validate what Buildx resolves, not what you specify.

## Inspect image metadata

Images contain metadata like environment variables, labels, and working
directories. You can validate these to ensure images meet requirements.

Check for specific environment variables:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.image.repo == "golang"
  input.image.workingDir == "/go"
  some ver in input.image.env
  startswith(ver, "GOLANG_VERSION=")
  some toolchain in input.image.env
  toolchain == "GOTOOLCHAIN=local"
}

decision := {"allow": allow}
```

This policy validates the official Go image by checking:

- The working directory is `/go`
- The environment has `GOLANG_VERSION` set
- The environment includes `GOTOOLCHAIN=local`

The `input.image.env` field is an array of strings in `KEY=VALUE` format.
Use Rego's `some` iteration to search the array.

Check image labels:

```rego
allow if {
  input.image.labels["org.opencontainers.image.vendor"] == "Example Corp"
  input.image.labels["org.opencontainers.image.version"] != ""
}
```

The `labels` field is a map, so you access values with bracket notation.

## Require attestations and provenance

Modern images include [attestations](/build/metadata/attestations/):
machine-readable metadata about how the image was built.
[Provenance](/build/metadata/attestations/slsa-provenance/) attestations
describe the build process, and [SBOMs](/build/metadata/attestations/sbom/)
list the software inside.

Require provenance:

```rego
package docker

default allow := false

allow if input.local

allow if {
  input.image.hasProvenance
}

decision := {"allow": allow}
```

The `hasProvenance` field is `true` when the image has provenance or SBOM
[attestations](../metadata/attestations/index.md).

## Verify GitHub Actions signatures

For images built with GitHub Actions, verify they came from trusted workflows by
inspecting signature metadata:

```rego
allow if {
  input.image.repo == "myapp"
  input.image.hasProvenance
  some sig in input.image.signatures
  valid_github_signature(sig)
}

# Helper to validate GitHub Actions signature
valid_github_signature(sig) if {
  sig.signer.certificateIssuer == "CN=sigstore-intermediate,O=sigstore.dev"
  sig.signer.issuer == "https://token.actions.githubusercontent.com"
  startswith(sig.signer.buildSignerURI, "https://github.com/myorg/")
  sig.signer.runnerEnvironment == "github-hosted"
}

decision := {"allow": allow}
```

This pattern works with any GitHub Actions workflow using Sigstore keyless
signing. The signature metadata provides cryptographic proof of the build's
origin. For complete signature verification examples, see [Example
policies](examples.md).

## Combine multiple checks

Real policies often combine several checks. Multiple conditions in one `allow`
rule means AND - all must be true:

```rego
package docker

default allow := false

allow if input.local

# Production images need everything
allow if {
  input.image.repo == "alpine"
  input.image.isCanonical
  input.image.hasProvenance
}

decision := {"allow": allow}
```

Multiple `allow` rules means OR - any rule can match:

```rego
package docker

default allow := false

allow if input.local

# Allow Alpine with strict checks
allow if {
  input.image.repo == "alpine"
  input.image.isCanonical
}

# Allow Go with different checks
allow if {
  input.image.repo == "golang"
  input.image.workingDir == "/go"
}

decision := {"allow": allow}
```

Use this pattern to apply different requirements to different base images.

## Next steps

You now understand how to validate container images in build policies. To
continue learning:

- Learn [Git repository validation](validate-git.md) for source code inputs
- Browse [Example policies](examples.md) for complete policy patterns
- Read [Built-in functions](built-ins.md) for signature verification and
  attestation checking
- Check the [Input reference](inputs.md) for all available image fields


---

# Release notes

*Sección: Build*

---
title: Build release notes
weight: 120
params:
  sidebar:
    goto: "https://github.com/docker/buildx/releases"
---


---

# Docker Build Cloud

*Sección: Build Cloud*

{{< summary-bar feature_name="Docker Build Cloud" >}}

Docker Build Cloud is a service that lets you build your container images
faster, both locally and in CI. Builds run on cloud infrastructure optimally
dimensioned for your workloads, no configuration required. The service uses a
remote build cache, ensuring fast builds anywhere and for all team members.

## How Docker Build Cloud works

Using Docker Build Cloud is no different from running a regular build. You invoke a
build the same way you normally would, using `docker buildx build`. The
difference is in where and how that build gets executed.

By default when you invoke a build command, the build runs on a local instance
of BuildKit, bundled with the Docker daemon. With Docker Build Cloud, you send
the build request to a BuildKit instance running remotely, in the cloud.
All data is encrypted in transit.

The remote builder executes the build steps, and sends the resulting build
output to the destination that you specify. For example, back to your local
Docker Engine image store, or to an image registry.

Docker Build Cloud provides several benefits over local builds:

- Improved build speed
- Shared build cache
- Native multi-platform builds

And the best part: you don't need to worry about managing builders or
infrastructure. Just connect to your builders, and start building.
Each cloud builder provisioned to an organization is completely
isolated to a single Amazon EC2 instance, with a dedicated EBS volume for build
cache, and encryption in transit. That means there are no shared processes or
data between cloud builders.

> [!NOTE]
> Docker Build Cloud is only available in the US East region.

## Get Docker Build Cloud

To get started with Docker Build Cloud,
[create a Docker account](/accounts/individual/create-account/). There are two options
to get access to Docker Build Cloud:

- Users with a free Personal account can opt-in to a 7-day free trial, with the option
  to subscribe for access. To start your free trial, sign in to [Docker Build Cloud Dashboard](https://app.docker.com/build/) and follow the on-screen instructions.
- All users with a paid Docker subscription have access to Docker Build Cloud included
  with their Docker suite of products. See [Docker subscriptions and features](https://www.docker.com/pricing?ref=Docs&refAction=DocsBuildCloud) for more information.

Once you've signed up and created a builder, continue by
[setting up the builder in your local environment](setup.md).

For information about roles and permissions related to Docker Build Cloud, see
[Roles and Permissions](../security/roles-and-permissions/core-roles.md#docker-build-cloud).


---

# Builder settings

*Sección: Build Cloud*

The **Builder settings** page in Docker Build Cloud lets you configure disk allocation, private resource access, and firewall settings for your cloud builders in your organization. These configurations help optimize storage, enable access to private registries, and secure outbound network traffic.

## Storage and cache management

### Disk allocation

The **Disk allocation** setting lets you control how much of the available
storage is dedicated to the build cache. A lower allocation increases
storage available for active builds.

To make disk allocation changes, navigate to **Builder settings** in Docker
Build Cloud and then adjust the **Disk allocation** slider to specify the
percentage of storage used for build caching.

Any changes take effect immediately.

### Build cache space

Your subscription includes the following Build cache space:

| Subscription | Build cache space |
| ------------ | ----------------- |
| Personal     | N/A               |
| Pro          | 50GB              |
| Team         | 100GB             |
| Business     | 200GB             |

### Multi-architecture storage allocation

Docker Build Cloud automatically provisions builders for both amd64 and arm64 architectures. Your total build cache space is split equally between these
two builders:

- Pro (50GB total): 25GB for amd64 builder + 25GB for arm64 builder
- Team (100GB total): 50GB for amd64 builder + 50GB for arm64 builder
- Business (200GB total): 100GB for amd64 builder + 100GB for arm64 builder

> [!IMPORTANT]
>
> If you only build for one architecture, be aware that your effective cache
> space is half of your subscription's total allocation.

### Get more build cache space

To get more Build cache space, [upgrade your subscription](../subscription-billing/manage/plans.md#upgrade-plans).

> [!TIP]
>
> If you build large images, consider allocating less storage for caching to
> leave more space for active builds.

## Private resource access

> [!IMPORTANT]
>
> Private resource access requires the private Buildx client. The `cloud`
> driver in standard Buildx doesn't support this feature. If your cloud builder
> uses private resource access, continue using the
> [latest private Buildx release](https://github.com/docker/buildx-desktop/releases/latest)
> until the feature is supported in standard Buildx.

Private resource access lets cloud builders pull images and packages from private resources. This feature is useful when builds rely on self-hosted artifact repositories or private OCI registries.

For example, if your organization hosts a private [PyPI](https://pypi.org/) repository on a private network, Docker Build Cloud would not be able to access it by default, since the cloud builder is not connected to your private network.

To enable your cloud builders to access your private resources, enter the host name and port of your private resource and then select **Add**.

### Authentication

If your internal artifacts require authentication, make sure that you
authenticate with the repository either before or during the build. For
internal package repositories for npm or PyPI, use [build secrets](../build/building/secrets.md)
to authenticate during the build. For internal OCI registries, use `docker
login` to authenticate before building.

If you use a private registry that requires authentication, you need to
authenticate twice before building: once to Docker Hub (to access Docker Build
Cloud), and once to your private registry (to push/pull images).

```console
$ echo $DOCKER_PAT | docker login docker.io -u <username> --password-stdin
$ echo $REGISTRY_PASSWORD | docker login registry.example.com -u <username> --password-stdin
$ docker build --builder <cloud-builder> --tag registry.example.com/<image> --push .
```

## Firewall

Firewall settings let you restrict cloud builder egress traffic to specific IP addresses. This helps enhance security by limiting external network egress from the builder.

1. Select the **Enable firewall: Restrict cloud builder egress to specific public IP address** checkbox.
2. Enter the IP address you want to allow.
3. Select **Add** to apply the restriction.


---

# Use Docker Build Cloud in CI

*Sección: Build Cloud*

Using Docker Build Cloud in CI can speed up your build pipelines, which means less time
spent waiting and context switching. You control your CI workflows as usual,
and delegate the build execution to Docker Build Cloud.

Building with Docker Build Cloud in CI involves the following steps:

1. Sign in to a Docker account.
2. Set up Buildx and connect to the builder.
3. Run the build.

When using Docker Build Cloud in CI, it's recommended that you push the result to a
registry directly, rather than loading the image and then pushing it. Pushing
directly speeds up your builds and avoids unnecessary file transfers.

If you just want to build and discard the output, export the results to the
build cache or build without tagging the image. With no explicit output, Buildx
leaves an untagged result in the cloud build cache and automatically loads
eligible tagged images. See
[Loading build results](./usage/#loading-build-results) for details.

> [!NOTE]
>
> Builds on Docker Build Cloud have a timeout limit that depends on your
> subscription plan. Builds that run for longer than your limit are
> automatically cancelled.

## Setting up credentials for CI/CD

To enable your CI/CD system to build and push images using Docker Build Cloud, provide both an access token and a username. The type of token and the username you use depend on your account type and permissions.

- If you are an organization administrator or have permission to create [organization access tokens (OAT)](../security/access-tokens/organization-access-tokens.md), use an OAT and set `DOCKER_ACCOUNT` to your Docker Hub organization name.
- If you do not have permission to create OATs or are using a personal account, use a [personal access token (PAT)](/security/access-tokens/personal-access-tokens/) and set `DOCKER_ACCOUNT` to your Docker Hub username.

### Creating access tokens

#### For organization accounts

If you are an organization administrator:

- Create an [organization access token (OAT)](../security/access-tokens/organization-access-tokens.md). The token must have these permissions:
    1. **cloud-connect** scope
    2. **Read public repositories** permission
    3. **Repository access** with **Image push** permission for the target repository:
        - Expand the **Repository** drop-down.
        - Select **Add repository** and choose your target repository.
        - Set the **Image push** permission for the repository.

If you are not an organization administrator:

- Ask your organization administrator for an access token with the permissions listed above, or use a personal access token.

#### For personal accounts

- Create a [personal access token (PAT)](/security/access-tokens/personal-access-tokens/) with the following permissions:
   1. **Read & write** access.
        - Note: Building with Docker Build Cloud only requires read access, but you need write access to push images to a Docker Hub repository.


## CI platform examples

> [!IMPORTANT]
>
> These examples require Buildx version 0.37.0 or later, which includes the
> `cloud` driver. The Docker CLI version doesn't determine the installed Buildx
> plugin version, and CI runner images may include an earlier Buildx release.
>
> Check the installed version:
>
> ```console
> $ docker buildx version
> ```
>
> If the version is earlier than 0.37.0, install Buildx as a
> [Docker CLI plugin](https://github.com/docker/buildx#manual-download).

> [!NOTE]
>
> In your CI/CD configuration, set the following variables/secrets:
> - `DOCKER_ACCESS_TOKEN` — your access token (PAT or OAT). Use a secret to store the token.
> - `DOCKER_ACCOUNT` — your Docker Hub organization name (for OAT) or username (for PAT)
> - `CLOUD_BUILDER_NAME` — the name of the cloud builder you created in the [Docker Build Cloud Dashboard](https://app.docker.com/build/)
>
> This ensures your builds authenticate correctly with Docker Build Cloud.

### GitHub Actions

<!-- TODO: Confirm whether standard Buildx requires a minimum setup-buildx-action version. -->

```yaml
name: ci

on:
  push:
    branches:
      - "main"

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - name: Login to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ vars.DOCKER_ACCOUNT }}
          password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
        with:
          driver: cloud
          endpoint: "${{ vars.DOCKER_ACCOUNT }}/${{ vars.CLOUD_BUILDER_NAME }}" # for example, "acme/default"
      
      - name: Build and push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          tags: "<IMAGE>" # for example, "acme/my-image:latest"
          # For pull requests, export results to the build cache.
          # Otherwise, push to a registry.
          outputs: ${{ github.event_name == 'pull_request' && 'type=cacheonly' || 'type=registry' }}
```

The example above uses `docker/build-push-action`, which automatically uses the
builder set up by `setup-buildx-action`. If you need to use the `docker build`
command directly instead, you have two options:

- Use `docker buildx build` instead of `docker build`
- Set the `BUILDX_BUILDER` environment variable to use the cloud builder:

  ```yaml
  - name: Set up Docker Buildx
    id: builder
    uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}
    with:
      driver: cloud
      endpoint: "${{ vars.DOCKER_ACCOUNT }}/${{ vars.CLOUD_BUILDER_NAME }}"

  - name: Build
    run: |
      docker build .
    env:
      BUILDX_BUILDER: ${{ steps.builder.outputs.name }}
  ```

For more information about the `BUILDX_BUILDER` environment variable, see
[Build variables](../build/building/variables.md#buildx_builder).

### GitLab

```yaml
default:
  image: docker:cli
  services:
    - docker:dind
  before_script:
    - docker info
    - echo "$DOCKER_ACCESS_TOKEN" | docker login --username "$DOCKER_ACCOUNT" --password-stdin
    - docker buildx create --use --driver cloud ${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}

variables:
  IMAGE_NAME: <IMAGE>
  DOCKER_ACCOUNT: <DOCKER_ACCOUNT> # your Docker Hub organization name (or username when using a personal account)
  CLOUD_BUILDER_NAME: <CLOUD_BUILDER_NAME> # the name of the cloud builder you created in the [Docker Build Cloud Dashboard](https://app.docker.com/build/)

# Build multi-platform image and push to a registry
build_push:
  stage: build
  script:
    - |
      docker buildx build \
        --platform linux/amd64,linux/arm64 \
        --tag "${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}" \
        --push .

# Build an image and discard the result
build_cache:
  stage: build
  script:
    - |
      docker buildx build \
        --platform linux/amd64,linux/arm64 \
        --tag "${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}" \
        --output type=cacheonly \
        .
```

### Circle CI

```yaml
version: 2.1

jobs:
  # Build multi-platform image and push to a registry
  build_push:
    machine:
      image: ubuntu-2204:current
    steps:
      - checkout

      - run: echo "$DOCKER_ACCESS_TOKEN" | docker login --username $DOCKER_ACCOUNT --password-stdin
      - run: docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"

      - run: |
          docker buildx build \
          --platform linux/amd64,linux/arm64 \
          --push \
          --tag "<IMAGE>" .

  # Build an image and discard the result
  build_cache:
    machine:
      image: ubuntu-2204:current
    steps:
      - checkout

      - run: echo "$DOCKER_ACCESS_TOKEN" | docker login --username $DOCKER_ACCOUNT --password-stdin
      - run: docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"

      - run: |
          docker buildx build \
          --tag temp \
          --output type=cacheonly \
          .

workflows:
  pull_request:
    jobs:
      - build_cache
  release:
    jobs:
      - build_push
```

### Buildkite

The following example sets up a Buildkite pipeline using Docker Build Cloud. The
example assumes that the pipeline name is `build-push-docker` and that you
manage the Docker access token using environment hooks, but feel free to adapt
this to your needs.

Add the following `environment` hook agent's hook directory:

```bash
#!/bin/bash
set -euo pipefail

if [[ "$BUILDKITE_PIPELINE_NAME" == "build-push-docker" ]]; then
 export DOCKER_ACCESS_TOKEN="<DOCKER_ACCESS_TOKEN>"
fi
```

Create a `pipeline.yml` that uses the `docker-login` plugin:

```yaml
env:
  DOCKER_ACCOUNT: <DOCKER_ACCOUNT> # your Docker Hub organization name (or username when using a personal account)
  CLOUD_BUILDER_NAME: <CLOUD_BUILDER_NAME> # the name of the cloud builder you created in the [Docker Build Cloud Dashboard](https://app.docker.com/build/)
  IMAGE_NAME: <IMAGE>

steps:
  - command: ./build.sh
    key: build-push
    plugins:
      - docker-login#v2.1.0:
          username: DOCKER_ACCOUNT
          password-env: DOCKER_ACCESS_TOKEN # the variable name in the environment hook
```

Create the `build.sh` script:

```bash
# Connect to your builder and set it as the default builder
docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"

# Cache-only image build
docker buildx build \
    --platform linux/amd64,linux/arm64 \
    --tag "$IMAGE_NAME:$BUILDKITE_COMMIT" \
    --output type=cacheonly \
    .

# Build, tag, and push a multi-arch docker image
docker buildx build \
    --platform linux/amd64,linux/arm64 \
    --push \
    --tag "$IMAGE_NAME:$BUILDKITE_COMMIT" \
    .
```

### Jenkins

```groovy
pipeline {
  agent any

  environment {
    DOCKER_ACCESS_TOKEN = credentials('docker-access-token')
    DOCKER_ACCOUNT = credentials('docker-account')
    CLOUD_BUILDER_NAME = '<CLOUD_BUILDER_NAME>'
    IMAGE_NAME = '<IMAGE>'
  }

  stages {
    stage('Build') {
      steps {
        sh 'echo "$DOCKER_ACCESS_TOKEN" | docker login --username $DOCKER_ACCOUNT --password-stdin'
        sh 'docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"'
        // Cache-only build
        sh 'docker buildx build --platform linux/amd64,linux/arm64 --tag "$IMAGE_NAME" --output type=cacheonly .'
        // Build and push a multi-platform image
        sh 'docker buildx build --platform linux/amd64,linux/arm64 --push --tag "$IMAGE_NAME" .'
      }
    }
  }
}
```

### Travis CI

```yaml
language: minimal 
dist: jammy 

services:
  - docker

env:
  global:
    - IMAGE_NAME=<IMAGE> # for example, "acme/my-image:latest"

before_install: |
  echo "$DOCKER_ACCESS_TOKEN" | docker login --username "$DOCKER_ACCOUNT" --password-stdin

before_script: |
  docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"

script: |
  docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --push \
  --tag "$IMAGE_NAME" .
```

### BitBucket Pipelines 

```yaml
# Prerequisites: $DOCKER_ACCOUNT, $CLOUD_BUILDER_NAME, $DOCKER_ACCESS_TOKEN setup as deployment variables
# This pipeline assumes $BITBUCKET_REPO_SLUG as the image name

image: docker:cli

pipelines:
  default:
    - step:
        name: Build multi-platform image
        script:
          - echo "$DOCKER_ACCESS_TOKEN" | docker login --username $DOCKER_ACCOUNT --password-stdin
          - docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"
          - IMAGE_NAME=$BITBUCKET_REPO_SLUG
          - docker buildx build
            --platform linux/amd64,linux/arm64
            --push
            --tag "$IMAGE_NAME" .
        services:
          - docker
```

### Shell script

```bash
#!/bin/bash

# Login to Docker Hub with an access token. See https://docs.docker.com/build-cloud/ci/#creating-access-tokens
echo "$DOCKER_ACCESS_TOKEN" | docker login --username $DOCKER_ACCOUNT --password-stdin

# Connect to your builder and set it as the default builder
docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"

# Cache-only image build
docker buildx build \
    --tag temp \
    --output type=cacheonly \
    .

# Build, tag, and push a multi-arch docker image
docker buildx build \
    --platform linux/amd64,linux/arm64 \
    --push \
    --tag "<IMAGE>" \
    .
```

### Docker Compose

This example requires Buildx version 0.37.0 or later. Set the cloud builder as
the default builder before running `docker compose build` in CI:

```bash
#!/bin/bash

# Login to Docker Hub with an access token. See https://docs.docker.com/build-cloud/ci/#creating-access-tokens
echo "$DOCKER_ACCESS_TOKEN" | docker login --username $DOCKER_ACCOUNT --password-stdin

# Connect to your builder and set it as the default builder
docker buildx create --use --driver cloud "${DOCKER_ACCOUNT}/${CLOUD_BUILDER_NAME}"

# Build the images
docker compose build
```


---

# Optimize for building in the cloud

*Sección: Build Cloud*

Docker Build Cloud runs your builds remotely, and not on the machine where you
invoke the build. This means that file transfers between the client and builder
happen over the network.

Transferring files over the network has a higher latency and lower bandwidth
than local transfers. Docker Build Cloud has several features to mitigate this:

- It uses attached storage volumes for build cache, which makes reading and
  writing cache very fast.
- Loading build results back to the client only pulls the layers that were
  changed compared to previous builds.

Despite these optimizations, building remotely can still yield slow context
transfers and image loads, for large projects or if the network connection is
slow. Here are some ways that you can optimize your builds to make the transfer
more efficient:

- [Dockerignore files](#dockerignore-files)
- [Slim base images](#slim-base-images)
- [Multi-stage builds](#multi-stage-builds)
- [Fetch remote files in build](#fetch-remote-files-in-build)
- [Multi-threaded tools](#multi-threaded-tools)

For more information on how to optimize your builds, see
[Building best practices](../build/building/best-practices.md).

### Dockerignore files

Using a [`.dockerignore` file](../build/concepts/context.md#dockerignore-files),
you can be explicit about which local files you don’t want to include in the
build context. Files caught by the glob patterns you specify in your
ignore-file aren't transferred to the remote builder.

Some examples of things you might want to add to your `.dockerignore` file are:

- `.git` — skip sending the version control history in the build context. Note
  that this means you won’t be able to run Git commands in your build steps,
  such as `git rev-parse`.
- Directories containing build artifacts, such as binaries. Build artifacts
  created locally during development.
- Vendor directories for package managers, such as `node_modules`.

In general, the contents of your `.dockerignore` file should be similar to what
you have in your `.gitignore`.

### Slim base images

Selecting smaller images for your `FROM` instructions in your Dockerfile can
help reduce the size of the final image. The [Alpine image](https://hub.docker.com/_/alpine)
is a good example of a minimal Docker image that provides all of the OS
utilities you would expect from a Linux container.

There’s also the [special `scratch` image](https://hub.docker.com/_/scratch),
which contains nothing at all. Useful for creating images of statically linked
binaries, for example.

### Multi-stage builds

[Multi-stage builds](/build/building/multi-stage/) can make your build run faster,
because stages can run in parallel. It can also make your end-result smaller.
Write your Dockerfile in such a way that the final runtime stage uses the
smallest possible base image, with only the resources that your program requires
to run.

It’s also possible to
[copy resources from other images or stages](/build/building/multi-stage/#name-your-build-stages),
using the Dockerfile `COPY --from` instruction. This technique can reduce the
number of layers, and the size of those layers, in the final stage.

### Fetch remote files in build

When possible, you should fetch files from a remote location in the build,
rather than bundling the files into the build context. Downloading files on the
Docker Build Cloud server directly is better, because it will likely be faster
than transferring the files with the build context.

You can fetch remote files during the build using the
[Dockerfile `ADD` instruction](/reference/dockerfile/#add),
or in your `RUN` instructions with tools like `wget` and `rsync`.

### Multi-threaded tools

Some tools that you use in your build instructions may not utilize multiple
cores by default. One such example is `make` which uses a single thread by
default, unless you specify the `make --jobs=<n>` option. For build steps
involving such tools, try checking if you can optimize the execution with
parallelization.


---

# Docker Build Cloud release notes

*Sección: Build Cloud*

This page contains information about the new features, improvements, known
issues, and bug fixes in Docker Build Cloud releases. 

## 2026-08-03

### Enhancements

- Cloud builders now run BuildKit v0.32.1, upgraded from v0.20.0. This spans
  twelve minor BuildKit releases of new build features, performance
  improvements, and bug fixes. For the full list of changes, see the
  [BuildKit release notes](https://github.com/moby/buildkit/releases).

  This range includes the following changes to default behavior. Each of these
  is an [exporter attribute](../build/exporters/image-registry.md) that
  you pass with `--output`, or an
  [attestation attribute](../build/metadata/attestations/index.md) that
  you pass with `--attest`:

  - Image results now use OCI media types by default. If your registry doesn't
    support OCI media types, build with
    `--output type=image,oci-mediatypes=false`. Treat this as a temporary
    measure until your registry supports OCI media types.
  - Attestations now use OCI artifact descriptors by default. If your registry
    doesn't support OCI artifacts, build with
    `--output type=image,oci-artifact=false`. Note that the attribute is
    singular.
  - [Provenance attestations](../build/metadata/attestations/slsa-provenance.md)
    now default to SLSA v1 instead of v0.2, which changes both the predicate
    type and the schema. If you verify provenance in your CI pipeline, confirm
    that your verifier supports the SLSA v1 predicate before your next build.
    A verifier that doesn't recognize the new predicate type may report that no
    attestation was found rather than failing outright, which can silently
    weaken a supply chain check. To keep the previous format while you update
    your tooling, build with `--attest type=provenance,version=v0.2`.

- Docker Build Cloud is verified against Buildx v0.36.0, up from v0.21.0. Buildx
  is the client you build with, and it's distributed with Docker Desktop and
  Docker Engine rather than with Docker Build Cloud, so your client version
  depends on how you installed Docker. For the client-side features available
  when building with a cloud builder, see the
  [Buildx release notes](https://github.com/docker/buildx/releases).

## 2025-12-19

### Bug fixes

- Fixed an error when building
  [Docker Hardened Images](../dhi/index.md) with a cloud builder.
- Fixed builds failing with gRPC message size errors when transferring large
  amounts of data.
- Fixed a 500 error when pulling images whose attestations or signatures are
  resolved through the OCI referrers fallback, which registries use when they
  don't implement the referrers API directly.

## 2025-06-04

### Enhancements

- Build timeouts are now determined by your subscription plan rather than by a
  single fixed limit applied to every build.

## 2025-04-29

### Enhancements

- Improved build error messages. Failures caused by your Dockerfile or build
  context are now reported as build errors rather than internal errors. This
  includes denied base image pulls, invalid stage names, and invalid `chmod`
  and `mkdir` targets.

## 2025-04-09

### Enhancements

- Added a consolidated cloud usage report covering all builds in your
  organization.

## 2025-03-05

### Enhancements

- Build usage reports now support custom date ranges.

## 2025-02-24

### New

Added a new **Build settings** page where you can configure disk allocation, private resource access, and firewall settings for your cloud builders in your organization. These configurations help optimize storage, enable access to private registries, and secure outbound network traffic.


---

# Docker Build Cloud setup

*Sección: Build Cloud*

Before you can start using Docker Build Cloud, you must add the builder to your local
environment.

## Prerequisites

To get started with Docker Build Cloud, you need to:

- Install Docker Desktop version 4.26.0 or later, or Buildx version 0.37.0 or
  later.
- Create a cloud builder on the [Docker Build Cloud Dashboard](https://app.docker.com/build/).
  - When you create the builder, choose a name for it (for example, `default`). You will use this name as `BUILDER_NAME` in the CLI steps below.

### Use Docker Build Cloud without Docker Desktop

Buildx version 0.37.0 or later includes the
[`cloud` driver](../build/builders/drivers/cloud.md). To use Docker Build
Cloud without Docker Desktop, check your installed version:

```console
$ docker buildx version
```

If your Docker CLI installation doesn't include a compatible Buildx version,
[install Buildx](https://github.com/docker/buildx#manual-download) as a Docker
CLI plugin.

## Steps

You can add a cloud builder using the CLI, with the `docker buildx create`
command, or using the Docker Desktop settings GUI.

{{< tabs >}}
{{< tab name="CLI" >}}

1. Sign in to your Docker account.

   ```console
   $ docker login
   ```

2. Connect Buildx to your cloud builder.

   ```console
   $ docker buildx create --driver cloud <ORG>/<BUILDER_NAME>
   ```

   Replace `<ORG>` with the Docker Hub namespace of your Docker organization (or your username if you are using a personal account), and `<BUILDER_NAME>` with the name you chose when creating the builder in the dashboard.

   This registers a local endpoint for the cloud builder named `cloud-ORG-BUILDER_NAME`.

   > [!NOTE]
   >
   > This command connects Buildx to an existing Docker Build Cloud builder. It
   > does not create a new cloud builder. To add a new builder, use the
   > [Docker Build Cloud Dashboard](https://app.docker.com/build/).

   > [!NOTE]
   >
   > If your organization is `acme` and you named your builder `default`, use:
   >
   > ```console
   > $ docker buildx create --driver cloud acme/default
   > ```

{{< /tab >}}
{{< tab name="Docker Desktop" >}}

1. Sign in to your Docker account using the **Sign in** button in Docker Desktop.

2. Open the Docker Desktop settings and navigate to the **Builders** tab.

3. Under **Available builders**, select **Connect to builder**.

{{< /tab >}}
{{< /tabs >}}

The builder has native support for the `linux/amd64` and `linux/arm64`
architectures. This gives you a high-performance build cluster for building
multi-platform images natively.

## Firewall configuration

To use Docker Build Cloud behind a firewall, ensure that your firewall allows
traffic to the following addresses:

- 3.211.38.21
- https://auth.docker.io
- https://build-cloud.docker.com
- https://hub.docker.com

## What's next

- See [Building with Docker Build Cloud](usage.md) for examples on how to use Docker Build Cloud.
- See [Use Docker Build Cloud in CI](ci.md) for examples on how to use Docker Build Cloud with CI systems.


---

# Building with Docker Build Cloud

*Sección: Build Cloud*

To build using Docker Build Cloud, invoke a build command and specify the name of the
builder using the `--builder` flag.

```console
$ docker buildx build --builder cloud-<ORG>-<BUILDER_NAME> --tag <IMAGE> .
```

## Use by default

If you want to use Docker Build Cloud without having to specify the `--builder` flag
each time, you can set it as the default builder.

{{< tabs group="ui" >}}
{{< tab name="CLI" >}}

Run the following command:

```console
$ docker buildx use cloud-<ORG>-<BUILDER_NAME> --global
```

{{< /tab >}}
{{< tab name="Docker Desktop" >}}

1. Open the Docker Desktop settings and navigate to the **Builders** tab.
2. Find the cloud builder under **Available builders**.
3. Open the drop-down menu and select **Use**.

   ![Selecting the cloud builder as default using the Docker Desktop GUI](/build/images/set-default-builder-gui.webp)

{{< /tab >}}
{{< /tabs >}}

Changing your default builder with `docker buildx use` only changes the default
builder for the `docker buildx build` command. The `docker build` command still
uses the `default` builder, unless you specify the `--builder` flag explicitly.

If you use build scripts, such as `make`, that use the `docker build` command,
update your build commands to `docker buildx build`. Alternatively, you can set
the [`BUILDX_BUILDER` environment
variable](../build/building/variables.md#buildx_builder) to specify which
builder `docker build` should use.

## Use with Docker Compose

To build with Docker Build Cloud using `docker compose build`, first set the
cloud builder as your selected builder, then run your build.

> [!NOTE]
>
> Make sure Buildx version 0.37.0 or later is installed. See
> [Prerequisites](setup.md#prerequisites).

```console
$ docker buildx use cloud-<ORG>-<BUILDER_NAME>
$ docker compose build
```

In addition to `docker buildx use`, you can also use the `docker compose build
--builder` flag or the [`BUILDX_BUILDER` environment
variable](../build/building/variables.md#buildx_builder) to select the cloud builder.

## Loading build results

When you don't specify an output, Buildx leaves an untagged build result in the
cloud build cache and doesn't load it into Docker Engine. If you use `--tag`,
Buildx automatically loads the image when the build targets a single platform
and runs on one cloud node. Use `--load` to request loading explicitly.

The target Docker context determines which Docker Engine image store receives
the result. For details about loading behavior and other output configurations,
see [Load results from Docker Build Cloud](../build/exporters/index.md#load-results-from-docker-build-cloud).

To push a multi-platform image to a registry instead of loading it:

```console
$ docker buildx build --builder cloud-<ORG>-<BUILDER_NAME> \
  --platform linux/amd64,linux/arm64 \
  --tag <IMAGE> \
  --push .
```

To keep a tagged result in the build cache instead of loading it into Docker
Engine, use the `cacheonly` exporter:

```console
$ docker buildx build --builder cloud-<ORG>-<BUILDER_NAME> \
  --platform linux/amd64,linux/arm64 \
  --tag <IMAGE> \
  --output type=cacheonly .
```

## Multi-platform builds

To run multi-platform builds, you must specify all of the platforms that you
want to build for using the `--platform` flag.

```console
$ docker buildx build --builder cloud-<ORG>-<BUILDER_NAME> \
  --platform linux/amd64,linux/arm64 \
  --tag <IMAGE> \
  --push .
```

If you don't specify the platform, the cloud builder automatically builds for the
architecture matching your local environment.

To learn more about building for multiple platforms, refer to [Multi-platform
builds](/build/building/multi-platform/).

## Cloud builds in Docker Desktop

The Docker Desktop [Builds view](/desktop/use-desktop/builds/) works with
Docker Build Cloud out of the box. This view can show information about not only your
own builds, but also builds initiated by your team members using the same
builder.

Teams using a shared builder get access to information such as:

- Ongoing and completed builds
- Build configuration, statistics, dependencies, and results
- Build source (Dockerfile)
- Build logs and errors

This lets you and your team work collaboratively on troubleshooting and
improving build speeds, without having to send build logs and benchmarks back
and forth between each other.

## Use secrets with Docker Build Cloud

To use build secrets with Docker Build Cloud,
such as authentication credentials or tokens,
use the `--secret` and `--ssh` CLI flags for the `docker buildx` command.
The traffic is encrypted and secrets are never stored in the build cache.

> [!WARNING]
>
> If you're misusing build arguments to pass credentials, authentication
> tokens, or other secrets, you should refactor your build to pass the secrets using
> [secret mounts](/reference/cli/docker/buildx/build/#secret) instead.
> Build arguments are stored in the cache and their values are exposed through attestations.
> Secret mounts don't leak outside of the build and are never included in attestations.

For more information, refer to:

- [`docker buildx build --secret`](/reference/cli/docker/buildx/build/#secret)
- [`docker buildx build --ssh`](/reference/cli/docker/buildx/build/#ssh)

## Managing build cache

You don't need to manage Docker Build Cloud cache manually.
The system manages it for you through [garbage collection](/build/cache/garbage-collection/).

Old cache is automatically removed if you hit your storage limit.
You can check your current cache state using the
[`docker buildx du` command](/reference/cli/docker/buildx/du/).

To clear the builder's cache manually,
use the [`docker buildx prune` command](/reference/cli/docker/buildx/prune/).
This works like pruning the cache for any other builder.

> [!WARNING]
>
> Pruning a cloud builder's cache also removes the cache for other team members
> using the same builder.

## Unset Docker Build Cloud as the default builder

If you've set a cloud builder as the default builder
and want to revert to the default `docker` builder,
run the following command:

```console
$ docker context use default
```

This doesn't remove the builder from your system.
It only changes the builder that's automatically selected to run your builds.

## Registries on internal networks

It is possible to use Docker Build Cloud with a [private registry](builder-settings.md#private-resource-access)
or registry mirror on an internal network.


---

# Docker Compose

*Sección: Compose*

Docker Compose is a tool for defining and running multi-container applications. 
It is the key to unlocking a streamlined and efficient development and deployment experience. 

Compose simplifies the control of your entire application stack, making it easy to manage services, networks, and volumes in a single YAML configuration file. Then, with a single command, you create and start all the services
from your configuration file.

Compose works in all environments - production, staging, development, testing, as
well as CI workflows. It also has commands for managing the whole lifecycle of your application:

 - Start, stop, and rebuild services
 - View the status of running services
 - Stream the log output of running services
 - Run a one-off command on a service

{{< grid >}}


---

# Overview of Compose Bridge

*Sección: Compose*

{{< summary-bar feature_name="Compose bridge" >}}

Compose Bridge converts your Docker Compose configuration into platform-specific deployment formats such as Kubernetes manifests. By default, it generates:

- Kubernetes manifests 
- A Kustomize overlay

These outputs are ready for deployment on Docker Desktop with [Kubernetes enabled](../../desktop/settings-and-maintenance/settings.md#kubernetes).  

Compose Bridge helps you bridge the gap between Compose and Kubernetes, making it easier to adopt Kubernetes while keeping the simplicity and efficiency of Compose.

It's a flexible tool that lets you either take advantage of the [default transformation](usage.md) or [create a custom transformation](customize.md) to suit specific project needs and requirements. 

## How it works

Compose Bridge uses transformations to convert a Compose model into another form. 

A transformation is packaged as a Docker image that receives the fully resolved Compose model as `/in/compose.yaml` and can produce any target format file under `/out`.

Compose Bridge provides its own transformation for Kubernetes using Go templates, so that it is easy to extend for customization by replacing or appending your own templates.

For more detailed information on how these transformations work and how you can customize them for your projects, see [Customize](customize.md).

Compose Bridge also supports applications that use LLMs via Docker Model Runner.

For more details, see [Use Model Runner](use-model-runner.md).

## Apply organizational standards at scale 


Compose Bridge supports custom transformation templates, which lets platform teams encode
organizational standards once and apply them consistently whenever a `compose.yaml` file
is converted to Kubernetes manifests or other formats.

Developers continue to write standard Compose files. During conversion, Compose Bridge
runs your custom transformation and automatically injects the required security contexts,
resource limits, labels, and network policies into the output manifests — without
requiring developers to know or manage those details.

When your requirements change, update the transformation template in one place. Every team
picks up the changes on their next conversion, with no edits to individual Compose files.

This separation of concerns keeps developers focused on application configuration, while
platform teams control governance and enforce policy through the transformation layer.

To get started, see [Customize Compose Bridge](customize.md).

## What's next?

- [Use Compose Bridge](usage.md)
- [Explore how you can customize Compose Bridge](customize.md)


---

# Customize Compose Bridge

*Sección: Compose*

{{< summary-bar feature_name="Compose bridge" >}}

You can customize how Compose Bridge converts your Docker Compose files into platform-specific formats. 

This page explains how Compose Bridge uses templating to generate Kubernetes manifests and how you can customize these templates for your specific requirements and needs, or how you can build your own transformation.  

## How it works 

Compose bridge uses transformations to let you convert a Compose model into another form. 

A transformation is packaged as a Docker image that receives the fully-resolved Compose model as `/in/compose.yaml` and can produce any target format file under `/out`.

Compose Bridge includes a default Kubernetes transformation using Go templates, which you can customize by replacing or extending templates.

### Template syntax

Compose Bridge makes use of templates to transform a Compose configuration file into Kubernetes manifests. Templates are plain text files that use the [Go templating syntax](https://pkg.go.dev/text/template). This enables the insertion of logic and data, making the templates dynamic and adaptable according to the Compose model.

When a template is executed, it must produce a YAML file which is the standard format for Kubernetes manifests. Multiple files can be generated as long as they are separated by `---`

Each YAML output file begins with custom header notation, for example:

```yaml
#! manifest.yaml
```

In the following example, a template iterates over services defined in a `compose.yaml` file. For each service, a dedicated Kubernetes manifest file is generated, named according to the service and containing specified configurations.

```yaml
{{ range $name, $service := .services }}
---
#! {{ $name }}-manifest.yaml
# Generated code, do not edit
key: value
## ...
{{ end }}
```

### Input model

You can generate the input model by running `docker compose config`. 

This canonical YAML output serves as the input for Compose Bridge transformations. Within the templates, data from the `compose.yaml` is accessed using dot notation, allowing you to navigate through nested data structures. For example, to access the deployment mode of a service, you would use `service.deploy.mode`:

 ```yaml
# iterate over a yaml sequence
{{ range $name, $service := .services }}
  # access a nested attribute using dot notation
  {{ if eq $service.deploy.mode "global" }}
kind: DaemonSet
  {{ end }}
{{ end }}
```

You can check the [Compose Specification JSON schema](https://github.com/compose-spec/compose-go/blob/main/schema/compose-spec.json) for a full overview of the Compose model. This schema outlines all possible configurations and their data types in the Compose model. 

### Helper functions

As part of the Go templating syntax, Compose Bridge offers a set of YAML helper functions designed to manipulate data within the templates efficiently:

| Function    | Description                                                                                                 |
| ----------- | ----------------------------------------------------------------------------------------------------------- |
| `seconds`   | Converts a [duration](../../reference/compose-file/extension.md#specifying-durations) into an integer (seconds). |
| `uppercase` | Converts a string to uppercase.                                                                             |
| `title`     | Capitalizes the first letter of each word.                                                                  |
| `safe`      | Converts a string into a safe identifier (replaces non-lowercase characters with `-`).                      |
| `truncate`  | Removes the first N elements from a list.                                                                   |
| `join`      | Joins list elements into a single string with a separator.                                                  |
| `base64`    | Encodes a string as base64 (used for Kubernetes secrets).                                                   |
| `map`       | Maps values using `“value -> newValue”` syntax.                                                             |
| `indent`    | Indents string content by N spaces.                                                                         |
| `helmValue` | Outputs a Helm-style template value.                                                                        |

In the following example, the template checks if a healthcheck interval is specified for a service, applies the `seconds` function to convert this interval into seconds and assigns the value to the `periodSeconds` attribute.

```yaml
{{ if $service.healthcheck.interval }}
            periodSeconds: {{ $service.healthcheck.interval | seconds }}{{ end }}
{{ end }}
```

## Customize the default templates

As Kubernetes is a versatile platform, there are many ways
to map Compose concepts into Kubernetes resource definitions. Compose
Bridge lets you customize the transformation to match your own infrastructure
decisions and preferences, with varying level of flexibility and effort.

### Modify the default templates

You can extract templates used by the default transformation `docker/compose-bridge-kubernetes`:

```console
$ docker compose bridge transformations create --from docker/compose-bridge-kubernetes my-template
``` 

The templates are extracted into a directory named after your template name, in this case `my-template`. It includes:

- A Dockerfile that lets you create your own image to distribute your template
- A directory containing the templating files

Edit, [add](#add-your-own-templates), or remove templates as needed. 

You can then use the generated Dockerfile to package your changes into a new transformation image, which you can then use with Compose Bridge:

```console
$ docker build --tag mycompany/transform --push .
```

Use your transformation as a replacement:

```console
$ docker compose bridge convert --transformations mycompany/transform 
```

#### Model Runner templates

The default transformation also includes templates for applications that use LLMs:

- `model-runner-deployment.tmpl`: Generates the Kubernetes deployment for Docker Model Runner. Customize it to change replica counts, image tags, resource requests and limits, GPU scheduling settings, tolerations, or additional environment variables.
- `model-runner-service.tmpl`: Builds the service that exposes Docker Model Runner. Update it to switch between `ClusterIP`, `NodePort`, or `LoadBalancer` types, adjust ports, or add annotations for ingress and service meshes.
- `model-runner-pvc.tmpl`: Defines the persistent volume claim used to store downloaded models. Edit it to set storage size, storage class, access modes, or volume annotations required by your storage provider.
- `/overlays/model-runner/kustomization.yaml`: Kustomize overlay applied when you deploy Model Runner to a standalone Kubernetes cluster. Extend it to add patches for labels and annotations, attach `NetworkPolicies`, or include extra manifests.
- `/overlays/desktop/deployment.tmpl`: Desktop-specific deployment template that keeps the in-cluster Model Runner scaled down and points workloads to the host endpoint. Adjust it if you change the Desktop endpoint or want to deploy Model Runner on Desktop instead of relying on the host service.

Common customization scenarios:

- Enable GPU support by adding vendor-specific resource requests, limits, and node selectors in `model-runner-deployment.tmpl`.
- Increase or tune storage for model artifacts by editing `model-runner-pvc.tmpl` to set the desired size, storage class, or access mode.
- Expose Model Runner outside the cluster by switching the service type in `model-runner-service.tmpl` or adding ingress annotations in the model-runner overlay.
- Align cluster policies by adding labels, annotations, or NetworkPolicies through `/overlays/model-runner/kustomization.yaml`.

For more details, see [Use Model Runner](use-model-runner.md).

### Add your own templates

For resources that are not managed by Compose Bridge's default transformation, 
you can build your own templates. 

The `compose.yaml` model may not offer all 
the configuration attributes required to populate the target manifest. If this is the case, you can
then rely on Compose custom extensions to better describe the
application, and offer an agnostic transformation.

For example, if you add `x-virtual-host` metadata
to service definitions in the `compose.yaml` file, you can use the following custom attribute
to produce Ingress rules:

```yaml
{{ $project := .name }}
#! {{ $name }}-ingress.yaml
# Generated code, do not edit
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: virtual-host-ingress
  namespace: {{ $project }}
spec:
  rules:  
{{ range $name, $service := .services }}
{{ range index $service "x-virtual-host" }}
  - host: ${{ . }}
    http:
      paths:
      - path: "/"
        backend:
          service:
            name: ${{ name }}
            port:
              number: 80  
{{ end }}
{{ end }}
```

Once packaged into a Docker image, you can use this custom template
when transforming Compose models into Kubernetes in addition to other
transformations:

```console
$ docker compose bridge convert \
    --transformation docker/compose-bridge-kubernetes \
    --transformation mycompany/transform 
```

### Build your own transformation

While Compose Bridge templates make it easy to customize with minimal changes,
you may want to make significant changes, or rely on an existing conversion tool.

A Compose Bridge transformation is a Docker image that is designed to get a Compose model
from `/in/compose.yaml` and produce platform manifests under `/out`. This simple 
contract makes it easy to bundle an alternate transformation using 
[Kompose](https://kompose.io/):

```Dockerfile
FROM alpine

# Get kompose from github release page
RUN apk add --no-cache curl
ARG VERSION=1.32.0
RUN ARCH=$(uname -m | sed 's/armv7l/arm/g' | sed 's/aarch64/arm64/g' | sed 's/x86_64/amd64/g') && \
    curl -fsL \
    "https://github.com/kubernetes/kompose/releases/download/v${VERSION}/kompose-linux-${ARCH}" \
    -o /usr/bin/kompose
RUN chmod +x /usr/bin/kompose

CMD ["/usr/bin/kompose", "convert", "-f", "/in/compose.yaml", "--out", "/out"]
```

This Dockerfile bundles Kompose and defines the command to run this tool according
to the Compose Bridge transformation contract.


---

# Use the default Compose Bridge transformation

*Sección: Compose*

{{< summary-bar feature_name="Compose bridge" >}}

Compose Bridge includes a built-in transformation that automatically converts your Compose configuration into a set of Kubernetes manifests.

Based on your `compose.yaml` file, it produces:

- A [Namespace](https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/) so all your resources are isolated and don't conflict with resources from other deployments.
- A [ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/) with an entry for each and every [config](../../reference/compose-file/configs.md) resource in your Compose application.
- [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) for application services. This ensures that the specified number of instances of your application are maintained in the Kubernetes cluster.
- [Services](https://kubernetes.io/docs/concepts/services-networking/service/) for ports exposed by your services, used for service-to-service communication.
- [Services](https://kubernetes.io/docs/concepts/services-networking/service/) for ports published by your services, with type `LoadBalancer` so that Docker Desktop will also expose the same port on the host.
- [Network policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) to replicate the networking topology defined in your `compose.yaml` file. 
- [PersistentVolumeClaims](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) for your volumes, using `hostpath` storage class so that Docker Desktop manages volume creation.
- [Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) with your secret encoded. This is designed for local use in a testing environment.

It also supplies a Kustomize overlay dedicated to Docker Desktop with:
 - `Loadbalancer` for services which need to expose ports on host.
 - A `PersistentVolumeClaim` to use the Docker Desktop storage provisioner `desktop-storage-provisioner` to handle volume provisioning more effectively.
 - A `Kustomization.yaml` file to link all the resources together.

If your Compose file defines a `models` section for a service, Compose Bridge automatically configures your deployment so your service can locate and use its models via Docker Model Runner.

For each declared model, the transformation injects two environment variables:

- `<MODELNAME>_URL`: The endpoint for Docker Model Runner serving that model  
- `<MODELNAME>_MODEL`: The model’s name or identifier

You can optionally customize these variable names using `endpoint_var` and `model_var`.

The default transformation generates two different overlays - one for Docker Desktop whilst using a local instance of Docker Model Runner, and a `model-runner` overlay with all the relevant Kubernetes resources to deploy Docker Model Runner in a pod. 

| Environment    | Endpoint                                        |
| -------------- | ----------------------------------------------- |
| Docker Desktop | `http://host.docker.internal:12434/engines/v1/` |
| Kubernetes     | `http://model-runner/engines/v1/`               |


For more details, see [Use Model Runner](use-model-runner.md).

## Use the default Compose Bridge transformation

To convert your Compose file using the default transformation:

```console
$ docker compose bridge convert
```

Compose looks for a `compose.yaml` file inside the current directory and generates Kubernetes manifests.

Example output:

```console
$ docker compose -f compose.yaml bridge convert
Kubernetes resource backend-deployment.yaml created
Kubernetes resource frontend-deployment.yaml created
Kubernetes resource backend-expose.yaml created
Kubernetes resource frontend-expose.yaml created
Kubernetes resource 0-my-project-namespace.yaml created
Kubernetes resource default-network-policy.yaml created
Kubernetes resource backend-service.yaml created
Kubernetes resource frontend-service.yaml created
Kubernetes resource kustomization.yaml created
Kubernetes resource backend-deployment.yaml created
Kubernetes resource frontend-deployment.yaml created
Kubernetes resource backend-service.yaml created
Kubernetes resource frontend-service.yaml created
Kubernetes resource kustomization.yaml created
Kubernetes resource model-runner-configmap.yaml created
Kubernetes resource model-runner-deployment.yaml created
Kubernetes resource model-runner-service.yaml created
Kubernetes resource model-runner-volume-claim.yaml created
Kubernetes resource kustomization.yaml created
```

All generated files are stored in the `/out` directory in your project.

## Deploy the generated manifests

> [!IMPORTANT]
>
> Before you deploy your Compose Bridge transformations, make sure you have [enabled Kubernetes](../../desktop/settings-and-maintenance/settings.md#kubernetes) in Docker Desktop.

Once the manifests are generated, deploy them to your local Kubernetes cluster:

```console
$ kubectl apply -k out/overlays/desktop/
```

> [!TIP]
>
> You can convert and deploy your Compose project to a Kubernetes cluster from the Compose file viewer.
> 
> Make sure you are signed in to your Docker account, navigate to your container in the **Containers** view, and in the top-right corner select **View configurations** and then **Convert and Deploy to Kubernetes**. 

## Additional commands

Convert a `compose.yaml` file located in another directory:

```console
$ docker compose -f <path-to-file>/compose.yaml bridge convert
```

To see all available flags, run:

```console
$ docker compose bridge convert --help
```

## What's next?

- [Explore how you can customize Compose Bridge](customize.md)
- [Use Model Runner](use-model-runner.md).


---

# Use Docker Model Runner with Compose Bridge

*Sección: Compose*

Compose Bridge supports model-aware deployments. It can deploy and configure Docker Model Runner, a lightweight service that hosts and serves machine LLMs.

This reduces manual setup for LLM-enabled services and keeps deployments consistent across Docker Desktop and Kubernetes environments.

If you have a `models` top-level element in your `compose.yaml` file, Compose Bridge:

- Automatically injects environment variables for each model’s endpoint and name.
- Configures model endpoints differently for Docker Desktop vs Kubernetes.
- Optionally deploys Docker Model Runner in Kubernetes when enabled in Helm values

## Configure model runner settings

When deploying using generated Helm Charts, you can control the model runner configuration through Helm values.

```yaml
# Model Runner settings
modelRunner:
    # Set to false for Docker Desktop (uses host instance)
    # Set to true for standalone Kubernetes clusters
    enabled: false
    # Endpoint used when enabled=false (Docker Desktop)
    hostEndpoint: "http://host.docker.internal:12434/engines/v1/"
    # Deployment settings when enabled=true
    image: "docker/model-runner:latest"
    imagePullPolicy: "IfNotPresent"
    # GPU support
    gpu:
        enabled: false
        vendor: "nvidia" # nvidia or amd
        count: 1
    # Node scheduling (uncomment and customize as needed)
    # nodeSelector:
    #   accelerator: nvidia-tesla-t4
    # tolerations: []
    # affinity: {}

    # Security context
    securityContext:
        allowPrivilegeEscalation: false
    # Environment variables (uncomment and add as needed)
    # env:
    #   DMR_ORIGINS: "http://localhost:31246"
    resources:
        limits:
            cpu: "1000m"
            memory: "2Gi"
        requests:
            cpu: "100m"
            memory: "256Mi"
    # Storage for models
    storage:
        size: "100Gi"
        storageClass: "" # Empty uses default storage class
    # Models to pre-pull
    models:
        - ai/qwen2.5:latest
        - ai/mxbai-embed-large
```

## Deploying a model runner

### Docker Desktop

When `modelRunner.enabled` is `false`, Compose Bridge configures your workloads to connect to Docker Model Runner running on the host:

```text
http://host.docker.internal:12434/engines/v1/
```

The endpoint is automatically injected into your service containers.

### Kubernetes

When `modelRunner.enabled` is `true`, Compose Bridge uses the generated manifests to deploy Docker Model Runner in your cluster, including:

- Deployment: Runs the `docker-model-runner` container
- Service: Exposes port `80` (maps to container port `12434`)
- `PersistentVolumeClaim`: Stores model files

The `modelRunner.enabled` setting also determines the number of replicas for the in-cluster `model-runner-deployment`:

- When `true`, the Kubernetes deployment replica count is set to 1, and Docker Model Runner is deployed in the cluster.
- When `false`, the Kubernetes deployment replica count is 0 (no in-cluster Model Runner). On Docker Desktop, workloads still connect to the host Model Runner as described above.


---

# Using the Compose SDK

*Sección: Compose*

{{< summary-bar feature_name="Compose SDK" >}}

The `docker/compose` package can be used as a Go library by third-party applications to programmatically manage
containerized applications defined in Compose files. This SDK provides a comprehensive API that lets you
integrate Compose functionality directly into your applications, allowing you to load, validate, and manage
multi-container environments without relying on the Compose CLI. 

Whether you need to orchestrate containers as part of
a deployment pipeline, build custom management tools, or embed container orchestration into your application, the
Compose SDK offers the same powerful capabilities that drive the Docker Compose command-line tool.

## Set up the SDK

To get started, create an SDK instance using the `NewComposeService()` function, which initializes a service with the
necessary configuration to interact with the Docker daemon and manage Compose projects. This service instance provides
methods for all core Compose operations including creating, starting, stopping, and removing containers, as well as
loading and validating Compose files. The service handles the underlying Docker API interactions and resource
management, allowing you to focus on your application logic.

### Requirements

Before using the SDK, make sure you're using a compatible version of the Docker CLI. 

```go
require (
    github.com/docker/cli v28.5.2+incompatible
)
```

Docker CLI version 29.0.0 and later depends on the new `github.com/moby/moby` module, whereas Docker Compose v5 currently depends on `github.com/docker/docker`. This means you need to pin `docker/cli v28.5.2+incompatible` to ensure compatibility and avoid build errors.

### Example usage

Here's a basic example demonstrating how to load a Compose project and start the services:

```go
package main

import (
    "context"
    "log"

	"github.com/docker/cli/cli/command"
	"github.com/docker/cli/cli/flags"
    "github.com/docker/compose/v5/pkg/api"
    "github.com/docker/compose/v5/pkg/compose"
)

func main() {
    ctx := context.Background()

	dockerCLI, err := command.NewDockerCli()
	if err != nil {
		log.Fatalf("Failed to create docker CLI: %v", err)
	}
	err = dockerCLI.Initialize(&flags.ClientOptions{})
	if err != nil {
		log.Fatalf("Failed to initialize docker CLI: %v", err)
	}
	
    // Create a new Compose service instance
    service, err := compose.NewComposeService(dockerCLI)
    if err != nil {
        log.Fatalf("Failed to create compose service: %v", err)
    }

    // Load the Compose project from a compose file
    project, err := service.LoadProject(ctx, api.ProjectLoadOptions{
        ConfigPaths: []string{"compose.yaml"},
        ProjectName: "my-app",
    })
    if err != nil {
        log.Fatalf("Failed to load project: %v", err)
    }

    // Start the services defined in the Compose file
    err = service.Up(ctx, project, api.UpOptions{
        Create: api.CreateOptions{},
        Start:  api.StartOptions{},
    })
    if err != nil {
        log.Fatalf("Failed to start services: %v", err)
    }

    log.Printf("Successfully started project: %s", project.Name)
}
```

This example demonstrates the core workflow - creating a service instance, loading a project from a Compose file, and
starting the services. The SDK provides many additional operations for managing the lifecycle of your containerized
application.

## Customizing the SDK

The `NewComposeService()` function accepts optional `compose.Option` parameters to customize the SDK behavior. These
options allow you to configure I/O streams, concurrency limits, dry-run mode, and other advanced features.

```go
    // Create a custom output buffer to capture logs
    var outputBuffer bytes.Buffer

    // Create a compose service with custom options
    service, err := compose.NewComposeService(dockerCLI,
        compose.WithOutputStream(&outputBuffer),          // Redirect output to custom writer
        compose.WithErrorStream(os.Stderr),               // Use stderr for errors
        compose.WithMaxConcurrency(4),                    // Limit concurrent operations
        compose.WithPrompt(compose.AlwaysOkPrompt()),     // Auto-confirm all prompts
    )
```

### Available options

- `WithOutputStream(io.Writer)`: Redirect standard output to a custom writer
- `WithErrorStream(io.Writer)`: Redirect error output to a custom writer
- `WithInputStream(io.Reader)`: Provide a custom input stream for interactive prompts
- `WithStreams(out, err, in)`: Set all I/O streams at once
- `WithMaxConcurrency(int)`: Limit the number of concurrent operations against the Docker API
- `WithPrompt(Prompt)`: Customize user confirmation behavior (use `AlwaysOkPrompt()` for non-interactive mode)
- `WithDryRun`: Run operations in dry-run mode without actually applying changes
- `WithContextInfo(api.ContextInfo)`: Set custom Docker context information
- `WithProxyConfig(map[string]string)`: Configure HTTP proxy settings for builds
- `WithEventProcessor(progress.EventProcessor)`: Receive progress events and operation notifications

These options provide fine-grained control over the SDK's behavior, making it suitable for various integration
scenarios including CLI tools, web services, automation scripts, and testing environments.

## Tracking operations with `EventProcessor`

The `EventProcessor` interface allows you to monitor Compose operations in real-time by receiving events about changes
applied to Docker resources such as images, containers, volumes, and networks. This is particularly useful for building
user interfaces, logging systems, or monitoring tools that need to track the progress of Compose operations.

### Understanding `EventProcessor`

A Compose operation, such as `up`, `down`, `build`, performs a series of changes to Docker resources. The
`EventProcessor` receives notifications about these changes through three key methods:

- `Start(ctx, operation)`: Called when a Compose operation begins, for example `up`
- `On(events...)`: Called with progress events for individual resource changes, for example, container starting, image
  being pulled
- `Done(operation, success)`: Called when the operation completes, indicating success or failure

Each event contains information about the resource being modified, its current status, and progress indicators when
applicable (such as download progress for image pulls).

### Event status types

Events report resource changes with the following status types:

- Working: Operation is in progress, for example, creating, starting, pulling
- Done: Operation completed successfully
- Warning: Operation completed with warnings
- Error: Operation failed

Common status text values include: `Creating`, `Created`, `Starting`, `Started`, `Running`, `Stopping`, `Stopped`,
`Removing`, `Removed`, `Building`, `Built`, `Pulling`, `Pulled`, and more.

### Built-in `EventProcessor` implementations

The SDK provides three ready-to-use `EventProcessor` implementations:

- `progress.NewTTYWriter(io.Writer)`: Renders an interactive terminal UI with progress bars and task lists
  (similar to the Docker Compose CLI output)
- `progress.NewPlainWriter(io.Writer)`: Outputs simple text-based progress messages suitable for non-interactive
  environments or log files
- `progress.NewJSONWriter()`: Render events as JSON objects
- `progress.NewQuietWriter()`: (Default) Silently processes events without producing any output

Using `EventProcessor`, a custom UI can be plugged into `docker/compose`.


---

# Docker Compose Quickstart

*Sección: Compose*

This tutorial aims to introduce fundamental concepts of Docker Compose by guiding you through the development of a basic Python web application. 

Using the Flask framework, the application features a hit counter in Redis, providing a practical example of how Docker Compose can be applied in web development scenarios. The concepts demonstrated here should be understandable even if you're not familiar with Python. 

## Prerequisites

Make sure you have:

- [Installed the latest version of Docker Compose](install/index.md)
- A basic understanding of Docker concepts and how Docker works

## Step 1: Set up the project

1. Create a directory for the project:

   ```console
   $ mkdir compose-demo
   $ cd compose-demo
   ```

2. Create `app.py` in your project directory and add the following:

   ```python
   import os
   import redis
   from flask import Flask

   app = Flask(__name__)
   cache = redis.Redis(
       host=os.getenv("REDIS_HOST", "redis"),
       port=int(os.getenv("REDIS_PORT", "6379")),
   )

   @app.route("/")
   def hello():
       count = cache.incr("hits")
       return f"Hello from Docker! I have been seen {count} time(s).\n"
   ```

   The app reads its Redis connection details from environment variables, with sensible defaults so it works out of the box.

3. Create `requirements.txt` in your project directory and add the following:

   ```text
   flask
   redis
   ```

4. Create a `Dockerfile`:

   ```dockerfile
   # syntax=docker/dockerfile:1
   
   # Build an image with the Python 3.12 image
   FROM python:3.12-alpine
   
   # Set the working directory to `/code`
   WORKDIR /code
   
   # Set environment variables used by the `flask` command
   ENV FLASK_APP=app.py
   ENV FLASK_RUN_HOST=0.0.0.0
   
   # Install `gcc` and other dependencies
   RUN apk add --no-cache gcc musl-dev linux-headers
   
   # Copy `requirements.txt`
   COPY requirements.txt .
   
   # Install the Python dependencies
   RUN pip install -r requirements.txt
   
   # Copy the current directory `.` in the project to the workdir `.` in the image
   COPY . .
   
   EXPOSE 5000
   
   # Set the default command for the container to `flask run --debug`
   CMD ["flask", "run", "--debug"]
   ```

   > [!IMPORTANT]
   >
   > Make sure the file is named `Dockerfile` with no extension. Some editors add `.txt`
   > automatically, which causes the build to fail.

   For more information on how to write Dockerfiles, see the [Dockerfile reference](/reference/dockerfile/).

5. Create a `.env` file to hold configuration values:

   ```text
   APP_PORT=8000
   REDIS_HOST=redis
   REDIS_PORT=6379
   ```

   Compose automatically reads `.env` and makes these values available for interpolation
   in your `compose.yaml`. For this example the gains are modest, but in practice,
   keeping configuration out of the Compose file makes it easier to:
   - Change values across environments without editing YAML
   - Avoid committing secrets to version control
   - Reuse values across multiple services

6. Create a `.dockerignore` file to keep unnecessary files out of your build context:

   ```text
   .env
   *.pyc
   __pycache__
   redis-data
   ```

   Docker sends everything in your project directory to the daemon when it builds an image.
   Without `.dockerignore`, that includes your `.env` file (which may contain secrets) and
   any cached Python bytecode. Excluding them keeps builds fast and avoids accidentally
   baking sensitive values into an image layer.

## Step 2: Define and start your services

Compose simplifies the control of your entire application stack, making it easy to manage services, networks, and volumes in a single YAML configuration file. 

1. Create `compose.yaml` in your project directory and paste the following:

   ```yaml
   services:
     web:
       build: .
       ports:
         - "${APP_PORT}:5000"
       environment:
         - REDIS_HOST=${REDIS_HOST}
         - REDIS_PORT=${REDIS_PORT}

     redis:
       image: redis:alpine
   ```

   This Compose file defines two services: 

   - The `web` service uses an image that's built from the `Dockerfile` in the current directory. It maps port `8000` on the host to port `5000` on the container where Flask listens by default.

   - The `redis` service uses a public [Redis](https://registry.hub.docker.com/_/redis/) image pulled from the Docker Hub registry.

   For more information on the `compose.yaml` file, see [How Compose works](intro/compose-application-model.md).

2. Start up your application: 

   ```console
   $ docker compose up
   ```

   With a single command, you create and start all the services from your configuration file. Compose builds your web image, pulls the Redis image, and starts both containers. 

3. Open `http://localhost:8000`. You should see:

   ```text
   Hello from Docker! I have been seen 1 time(s).
   ```

   Refresh the page — the counter increments on each visit.

   This minimal setup works, but it has two problems you'll fix in the next steps:

   - Startup race: `web` starts at the same time as `redis`. If Redis isn't ready yet,
   the Flask app fails to connect and crashes.
   - No persistence: If you run `docker compose down` followed by `docker compose up`, the
   counter resets to zero. `docker compose down` removes the containers, and with them
   any data written to the container's writable layer. `docker compose stop` preserves
   the containers so data survives, but you can't rely on that in production where
   containers are regularly replaced.

4. Stop the stack before moving on:

   ```console
   $ docker compose down
   ```

## Step 3: Fix the startup race with health checks

To fix the startup race, Compose needs to wait until `redis` is confirmed healthy before
starting `web`.

1. Update `compose.yaml`:

   ```yaml
   services:
     web:
       build: .
       ports:
         - "${APP_PORT}:5000"
       environment:
         - REDIS_HOST=${REDIS_HOST}
         - REDIS_PORT=${REDIS_PORT}
       depends_on:
         redis:
           condition: service_healthy

     redis:
       image: redis:alpine
       healthcheck:
         test: ["CMD", "redis-cli", "ping"]
         interval: 5s
         timeout: 3s
         retries: 5
         start_period: 10s
   ```

   The `healthcheck` block tells Compose how to test whether Redis is ready:

   - `test` is the command Compose runs inside the container to check its health.
     `redis-cli ping` connects to Redis and expects a `PONG` response — if it gets one,
     the container is healthy.
   - `start_period` gives Redis 10 seconds to initialize before health checks begin.
     Any failures during this window don't count toward the retry limit.
   - `interval` runs the check every 5 seconds after the start period has elapsed.
   - `timeout` gives each check 3 seconds to respond before treating it as a failure.
   - `retries` sets how many consecutive failures are allowed before Compose marks the
     container as unhealthy. With `interval: 5s` and `retries: 5`, Compose will wait up
     to 25 seconds before giving up.

2. Start the stack to confirm the ordering is fixed:

   ```console
   $ docker compose up
   ```

   You should see something similar to:

   ```text
   [+] Running 2/2
   ✔ Container compose-demo-redis-1  Healthy                       0.0s
   ```

3. Open `http://localhost:8000` to confirm the app is still working, then stop the stack before moving on:

   ```console
   $ docker compose down
   ```

## Step 4: Enable Compose Watch for live updates

Without Compose Watch, every code change requires you to stop the stack, rebuild the image, and restart the containers. Compose Watch eliminates that cycle by automatically syncing changes into your running container as you save files.

1. Update `compose.yaml` to add the `develop.watch` block to the `web` service:
   
   ```yaml
   services:
     web:
       build: .
       ports:
         - "${APP_PORT}:5000"
       environment:
         - REDIS_HOST=${REDIS_HOST}
         - REDIS_PORT=${REDIS_PORT}
       depends_on:
         redis:
           condition: service_healthy
       develop:
         watch:
           - action: sync+restart
             path: .
             target: /code
           - action: rebuild
             path: requirements.txt

     redis:
       image: redis:alpine
       healthcheck:
         test: ["CMD", "redis-cli", "ping"]
         interval: 5s
         timeout: 3s
         retries: 5
         start_period: 10s
   ```

   The `watch` block defines two rules:
   - The `sync+restart` action watches your project directory (`.`) on the host. When a file changes, Compose copies any changed files into `/code` inside the running container, then restarts the container. Because the container restarts with the updated files already in place, Flask starts up reading the new code directly — no manual rebuild or restart needed. 
   - The `rebuild` action on `requirements.txt` triggers a full image rebuild whenever you add a new dependency, since installing packages requires rebuilding the image, not just syncing files.
   
2. Start the stack with Watch enabled:

   ```console
   $ docker compose up --watch
   ```

3. Make a live change. Open `app.py` and update the greeting:

   ```python
   return f"Hello from Compose Watch! I have been seen {count} time(s).\n"
   ```

4. Save the file. Compose Watch detects the change and syncs it immediately:

   ```text
   Syncing service "web" after changes were detected
   ```

5. Refresh `http://localhost:8000`. The updated greeting appears without any restart
   and the counter should still be incrementing.

6. Stop the stack before moving on:

   ```console
   $ docker compose down
   ```

   For more information on how Compose Watch works, see [Use Compose Watch](how-tos/file-watch.md).

## Step 5: Persist data with named volumes

Each time you stop and restart the stack the visit counter resets to zero. Redis data
lives inside the container, so it disappears when the container is removed. A named
volume fixes this by storing the data on the host, outside the container lifecycle.

1. Update `compose.yaml`:

   ```yaml
   services:
     web:
       build: .
       ports:
         - "${APP_PORT}:5000"
       environment:
         - REDIS_HOST=${REDIS_HOST}
         - REDIS_PORT=${REDIS_PORT}
       depends_on:
         redis:
           condition: service_healthy
       develop:
         watch:
           - action: sync+restart
             path: .
             target: /code
           - action: rebuild
             path: requirements.txt

     redis:
       image: redis:alpine
       volumes:
         - redis-data:/data
       healthcheck:
         test: ["CMD", "redis-cli", "ping"]
         interval: 5s
         timeout: 3s
         retries: 5
         start_period: 10s

   volumes:
     redis-data:
   ```

   The `redis-data:/data` entry under `redis.volumes` mounts the named volume at `/data`, the path where Redis
   writes its data files. The top-level `volumes` key registers it with Docker so it
   persists between `compose down` and `compose up` cycles.

2. Start the stack with `docker compose up --watch` and refresh `http://localhost:8000` a few times to build up a count.

3. Tear down the stack with `docker compose down` and then bring it back up again with `docker compose up --watch`.

4. Open `http://localhost:8000` — the counter continues from where it left off.

5. Now reset the counter with `docker compose down -v`. 

   The `-v` flag removes named volumes along with the containers. Use this intentionally — it permanently deletes the stored data.

## Step 6: Structure your project with multiple Compose files

As applications grow, a single `compose.yaml` becomes harder to maintain. The `include`
top-level element lets you split services across multiple files while keeping them part of the
same application.

This is especially useful when different teams own different parts of the stack, or when
you want to reuse infrastructure definitions across projects.

1. Create a new file in your project directory called `infra.yaml` and move the Redis service and volume into it:

   ```yaml
   services:
     redis:
       image: redis:alpine
       volumes:
         - redis-data:/data
       healthcheck:
         test: ["CMD", "redis-cli", "ping"]
         interval: 5s
         timeout: 3s
         retries: 5
         start_period: 10s

   volumes:
     redis-data:
   ```

2. Update `compose.yaml` to include `infra.yaml`:

   ```yaml
   include:
      - path: ./infra.yaml
   services:
     web:
       build: .
       ports:
         - "${APP_PORT}:5000"
       environment:
         - REDIS_HOST=${REDIS_HOST}
         - REDIS_PORT=${REDIS_PORT}
       depends_on:
         redis:
           condition: service_healthy
       develop:
         watch:
           - action: sync+restart
             path: .
             target: /code
           - action: rebuild
             path: requirements.txt
   ```

3. Run the application to confirm everything still works:

   ```console
   $ docker compose up --watch
   ```

   Compose merges both files at startup. The `web` service can still reference `redis`
   by name because all included services share the same default network.

   This is a simplified example, but it demonstrates the basic principle of `include` and how it can make it easier to modularize complex applications into sub-Compose files. For more information on `include` and working with multiple Compose files, see [Working with multiple Compose files](how-tos/multiple-compose-files/index.md).

4. Stop the stack before moving on:

   ```console
   $ docker compose down
   ```

## Step 7: Inspect and debug your running stack

With a fully configured stack, you can observe what's happening inside your containers
without stopping anything. This step covers the core commands for inspecting the resolved configuration, streaming logs, and running commands
inside a running container.

Before starting the stack, verify that Compose has resolved your `.env` variables and
merged all files correctly:

```console
$ docker compose config
```

`docker compose config` doesn't require the stack to be running — it works purely from
your files. A few things worth noting in the output:

- `${APP_PORT}`, `${REDIS_HOST}`, and `${REDIS_PORT}` have all been replaced with the
  values from your `.env` file.
- Short-form port notation (`"8000:5000"`) is expanded into its canonical fields
  (`target`, `published`, `protocol`).
- The default network and volume names are made explicit, prefixed with the project name
  `compose-demo`.
- The output is the fully resolved configuration, with any files
  brought in via `include` merged into a single view.

Use `docker compose config` any time you want to confirm what Compose will actually
apply, especially when debugging variable substitution or working with multiple Compose files.

Now start the stack in detached mode so the terminal stays free for the commands that
follow:

```console
$ docker compose up -d
```

### Stream logs from all services

```console
$ docker compose logs -f
```

The `-f` flag follows the log stream in real time, interleaving output from both
containers with color-coded service name prefixes. Refresh `http://localhost:8000` a
few times and watch the Flask request logs appear. To follow logs for a single service,
pass its name:

```console
$ docker compose logs -f web
```

Press `Ctrl+C` to stop following logs. The containers keep running.

### Run commands inside a running container

`docker compose exec` runs a command inside an already-running container without
starting a new one. This is the primary tool for live debugging.

#### Verify environment variables are set correctly

```console
$ docker compose exec web env | grep REDIS
```

```text
REDIS_HOST=redis
REDIS_PORT=6379
```

#### Test that the `web` container can reach Redis using the service name as the hostname

```console
$ docker compose exec web python -c "import redis; r = redis.Redis(host='redis'); print(r.ping())"
```

```text
True
```

This uses the same `redis` library your app uses, so a `True` response confirms that
service discovery, networking, and the Redis connection are all working end to end.

#### Inspect the live value of the hit counter in Redis

```console
$ docker compose exec redis redis-cli GET hits
```

## Where to go next

- [Explore the full list of Compose commands](/reference/cli/docker/compose/)
- [Explore the Compose file reference](../reference/compose-file/index.md)
- [Check out the Learning Docker Compose video on LinkedIn Learning](https://www.linkedin.com/learning/learning-docker-compose/)
- [Learn how to set environment variables in Compose](/compose/how-tos/environment-variables/set-environment-variables/)
- [Learn how to package and distribute your Compose app](/compose/how-tos/oci-artifact/)


---

# Index

*Sección: Compose*

---
build:
  render: never
title: How-tos
weight: 40
---


---

# Build dependent images

*Sección: Compose*

{{< summary-bar feature_name="Compose dependent images" >}}

To reduce push/pull time and image weight, a common practice for Compose applications is to have services
share base layers as much as possible. You typically select the same operating system base image for
all services. But you can also get one step further by sharing image layers when your images share the same
system packages. The challenge to address is then to avoid repeating the exact same Dockerfile instruction 
in all services.

For illustration, this page assumes you want all your services to be built with an `alpine` base
image and install the system package `openssl`.

## Multi-stage Dockerfile

The recommended approach is to group the shared declaration in a single Dockerfile, and use multi-stage features
so that service images are built from this shared declaration.

Dockerfile:

```dockerfile
FROM alpine as base
RUN /bin/sh -c apk add --update --no-cache openssl

FROM base as service_a
# build service a
...

FROM base as service_b
# build service b
...
```

Compose file:

```yaml
services:
  a:
     build:
       target: service_a
  b:
     build:
       target: service_b
```

## Use another service's image as the base image

A popular pattern is to reuse a service image as a base image in another service.
As Compose does not parse the Dockerfile, it can't automatically detect this dependency 
between services to correctly order the build execution.

a.Dockerfile:

```dockerfile
FROM alpine
RUN /bin/sh -c apk add --update --no-cache openssl
```

b.Dockerfile:

```dockerfile
FROM service_a
# build service b
```

Compose file:

```yaml
services:
  a:
     image: service_a 
     build:
       dockerfile: a.Dockerfile
  b:
     image: service_b
     build:
       dockerfile: b.Dockerfile
```

Legacy Docker Compose v1 used to build images sequentially, which made this pattern usable
out of the box. Compose v2 uses BuildKit to optimise builds and build images in parallel 
and requires an explicit declaration.

The recommended approach is to declare the dependent base image as an additional build context:

Compose file:

```yaml
services:
  a:
     image: service_a
     build: 
       dockerfile: a.Dockerfile
  b:
     image: service_b
     build:
       dockerfile: b.Dockerfile
       additional_contexts:
         # `FROM service_a` will be resolved as a dependency on service "a" which has to be built first
         service_a: "service:a"
```

With the `additional_contexts` attribute, you can refer to an image built by another service without needing to explicitly name it:

b.Dockerfile:

```dockerfile

FROM base_image  
# `base_image` doesn't resolve to an actual image. This is used to point to a named additional context

# build service b
```

Compose file:

```yaml
services:
  a:
     build: 
       dockerfile: a.Dockerfile
       # built image will be tagged <project_name>_a
  b:
     build:
       dockerfile: b.Dockerfile
       additional_contexts:
         # `FROM base_image` will be resolved as a dependency on service "a" which has to be built first
         base_image: "service:a"
```

## Build with Bake

Using [Bake](../../build/bake/index.md) let you pass the complete build definition for all services
and to orchestrate build execution in the most efficient way. 

To enable this feature, run Compose with the `COMPOSE_BAKE=true` variable set in your environment.

```console
$ COMPOSE_BAKE=true docker compose build
[+] Building 0.0s (0/1)                                                         
 => [internal] load local bake definitions                                 0.0s
...
[+] Building 2/2 manifest list sha256:4bd2e88a262a02ddef525c381a5bdb08c83  0.0s
 ✔ service_b  Built                                                        0.7s 
 ✔ service_a  Built    
```

Bake can also be selected as the default builder by editing your `$HOME/.docker/config.json` config file:
```json
{
  ...
  "plugins": {
    "compose": {
      "build": "bake"
    }
  }
  ...
}
```

## Additional resources

- [Docker Compose build reference](/reference/cli/docker/compose/build/)
- [Learn about multi-stage Dockerfiles](../../build/building/multi-stage.md)


---

# Environment variables in Compose

*Sección: Compose*

Environment variables and interpolation in Docker Compose help you create reusable, flexible configurations. This makes Dockerized applications easier to manage and deploy across environments.

> [!TIP]
>
> Before using environment variables, read through all of the information first to get a full picture of environment variables in Docker Compose.

This section covers:

- [How to set environment variables within your container's environment](set-environment-variables.md).
- [How environment variable precedence works within your container's environment](envvars-precedence.md).
- [Pre-defined environment variables](envvars.md).

It also covers: 
- How [interpolation](variable-interpolation.md) can be used to set variables within your Compose file and how it relates to a container's environment.
- Some [best practices](best-practices.md).


---

# Best practices for working with environment variables in Docker Compose

*Sección: Compose*

#### Handle sensitive information securely

Be cautious about including sensitive data in environment variables. Consider using [Secrets](../use-secrets.md) for managing sensitive information.

#### Understand environment variable precedence

Be aware of how Docker Compose handles the [precedence of environment variables](envvars-precedence.md) from different sources (`.env` files, shell variables, Dockerfiles).

#### Use specific environment files

Consider how your application adapts to different environments. For example development, testing, production, and use different `.env` files as needed.

#### Know interpolation
   
Understand how [interpolation](variable-interpolation.md) works within compose files for dynamic configurations.

#### Command line overrides
    
Be aware that you can [override environment variables](set-environment-variables.md#cli) from the command line when starting containers. This is useful for testing or when you have temporary changes.


---

# Environment variables precedence in Docker Compose

*Sección: Compose*

When the same environment variable is set in multiple sources, Docker Compose follows a precedence rule to determine the value for that variable in your container's environment.

This page explains how Docker Compose determines the final value of an environment variable when it's defined in multiple locations.

The order of precedence (highest to lowest) is as follows:
1. Set using [`docker compose run -e` in the CLI](set-environment-variables.md#set-environment-variables-with-docker-compose-run---env).
2. Set with either the `environment` or `env_file` attribute but with the value interpolated from your [shell](variable-interpolation.md#substitute-from-the-shell) or an environment file. (either your default [`.env` file](variable-interpolation.md#env-file), or with the [`--env-file` argument](variable-interpolation.md#substitute-with---env-file) in the CLI).
3. Set using just the [`environment` attribute](set-environment-variables.md#use-the-environment-attribute) in the Compose file.
4. Use of the [`env_file` attribute](set-environment-variables.md#use-the-env_file-attribute) in the Compose file.
5. Set in a container image in the [ENV directive](../../../build/concepts/dockerfile.md#env).
   Having any `ARG` or `ENV` setting in a `Dockerfile` evaluates only if there is no Docker Compose entry for `environment`, `env_file` or `run --env`.

> [!NOTE] 
> 
> When `--env-file` is not set, Compose may load up to two `.env` files.
> It first loads one from the project directory (determined by `--project-directory`
> if set, otherwise the directory of the first `-f`/`--file` Compose file, otherwise
> `PWD`). If that file sets `COMPOSE_FILE` to a path in a different directory, Compose
> loads a second `.env` file from that directory with lower precedence. For more
> information, see [local `.env` file versus project directory `.env` file](variable-interpolation.md#local-env-file-versus-project-directory-env-file).

## Simple example

In the following example, a different value for the same environment variable in an `.env` file and with the `environment` attribute in the Compose file:

```console
$ cat ./webapp.env
NODE_ENV=test

$ cat compose.yaml
services:
  webapp:
    image: 'webapp'
    env_file:
     - ./webapp.env
    environment:
     - NODE_ENV=production
```

The environment variable defined with the `environment` attribute takes precedence.

```console
$ docker compose run webapp env | grep NODE_ENV
NODE_ENV=production
```

## Advanced example 

The following table uses `VALUE`, an environment variable defining the version for an image, as an example.

### How the table works

Each column represents a context from where you can set a value, or substitute in a value for `VALUE`.

The columns `Host OS environment` and `.env` file is listed only for illustration purposes. In reality, they don't result in a variable in the container by itself, but in conjunction with either the `environment` or `env_file` attribute.

Each row represents a combination of contexts where `VALUE` is set, substituted, or both. The **Result** column indicates the final value for `VALUE` in each scenario.

|  # |  `docker compose run`  |  `environment` attribute  |  `env_file` attribute  |  Image `ENV` |  `Host OS` environment  |  `.env` file      |   Result  |
|:--:|:----------------:|:-------------------------------:|:----------------------:|:------------:|:-----------------------:|:-----------------:|:----------:|
|  1 |   -              |   -                             |   -                    |   -          |  `VALUE=1.4`            |  `VALUE=1.3`      | -               |
|  2 |   -              |   -                             |  `VALUE=1.6`           |  `VALUE=1.5` |  `VALUE=1.4`            |   -               |**`VALUE=1.6`**  |
|  3 |   -              |  `VALUE=1.7`                    |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |   -               |**`VALUE=1.7`**  |
|  4 |   -              |   -                             |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.5`**  |
|  5 |`--env VALUE=1.8` |   -                             |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.8`**  |
|  6 |`--env VALUE`     |   -                             |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.4`**  |
|  7 |`--env VALUE`     |   -                             |   -                    |  `VALUE=1.5` |   -                     |  `VALUE=1.3`      |**`VALUE=1.3`**  |
|  8 |   -              |   -                             |   `VALUE`              |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.4`**  |
|  9 |   -              |   -                             |   `VALUE`              |  `VALUE=1.5` |   -                     |  `VALUE=1.3`      |**`VALUE=1.3`**  |
| 10 |   -              |  `VALUE`                        |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.4`**  |
| 11 |   -              |  `VALUE`                        |   -                    |  `VALUE=1.5` |  -                      |  `VALUE=1.3`      |**`VALUE=1.3`**  |
| 12 |`--env VALUE`     |  `VALUE=1.7`                    |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.4`**  |
| 13 |`--env VALUE=1.8` |  `VALUE=1.7`                    |   -                    |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.8`**  |
| 14 |`--env VALUE=1.8` |   -                             |  `VALUE=1.6`           |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.8`**  |
| 15 |`--env VALUE=1.8` |  `VALUE=1.7`                    |  `VALUE=1.6`           |  `VALUE=1.5` |  `VALUE=1.4`            |  `VALUE=1.3`      |**`VALUE=1.8`**  |

### Understanding precedence results

Result 1: The local environment takes precedence, but the Compose file is not set to replicate this inside the container, so no such variable is set.

Result 2: The `env_file` attribute in the Compose file defines an explicit value for `VALUE` so the container environment is set accordingly.

Result 3: The `environment` attribute in the Compose file defines an explicit value for `VALUE`, so the container environment is set accordingly.

Result 4: The image's `ENV` directive declares the variable `VALUE`, and since the Compose file is not set to override this value, this variable is defined by image

Result 5: The `docker compose run` command has the `--env` flag set with an explicit value, and overrides the value set by the image. 

Result 6: The `docker compose run` command has the `--env` flag set to replicate the value from the environment. Host OS value takes precedence and is replicated into the container's environment.

Result 7: The `docker compose run` command has the `--env` flag set to replicate the value from the environment. Value from `.env` file is selected to define the container's environment.

Result 8: The `env_file` attribute in the Compose file is set to replicate `VALUE` from the local environment. Host OS value takes precedence and is replicated into the container's environment.

Result 9: The `env_file` attribute in the Compose file is set to replicate `VALUE` from the local environment. Value from `.env` file is selected to define the container's environment.

Result 10: The `environment` attribute in the Compose file is set to replicate `VALUE` from the local environment. Host OS value takes precedence and is replicated into the container's environment.

Result 11: The `environment` attribute in the Compose file is set to replicate `VALUE` from the local environment. Value from `.env` file is selected to define the container's environment.

Result 12: The `--env` flag has higher precedence than the `environment` and `env_file` attributes and is to set to replicate `VALUE` from the local environment. Host OS value takes precedence and is replicated into the container's environment.

Results 13 to 15: The `--env` flag has higher precedence than the `environment` and `env_file` attributes and so sets the value. 

## Next steps

- [Set environment variables in Compose](set-environment-variables.md)
- [Use variable interpolation in Compose files](variable-interpolation.md)


---

# Configure pre-defined environment variables in Docker Compose

*Sección: Compose*

Docker Compose includes several pre-defined environment variables. It also inherits common Docker CLI environment variables, such as `DOCKER_HOST` and `DOCKER_CONTEXT`. See [Docker CLI environment variable reference](/reference/cli/docker/#environment-variables) for details.

This page explains how to set or change the following pre-defined environment variables:

- `COMPOSE_PROJECT_NAME`
- `COMPOSE_FILE`
- `COMPOSE_PROFILES`
- `COMPOSE_CONVERT_WINDOWS_PATHS`
- `COMPOSE_PATH_SEPARATOR`
- `COMPOSE_IGNORE_ORPHANS`
- `COMPOSE_REMOVE_ORPHANS`
- `COMPOSE_PARALLEL_LIMIT`
- `COMPOSE_ANSI`
- `COMPOSE_STATUS_STDOUT`
- `COMPOSE_ENV_FILES`
- `COMPOSE_DISABLE_ENV_FILE`
- `COMPOSE_MENU`
- `COMPOSE_EXPERIMENTAL`
- `COMPOSE_PROGRESS`

## Methods to override 

| Method      | Description                                  |
| ----------- | -------------------------------------------- |
| [`.env` file](variable-interpolation.md) | Located in the working directory.            |
| [Shell](variable-interpolation.md#substitute-from-the-shell)       | Defined in the host operating system shell.  |
| CLI         | Passed with `--env` or `-e` flag at runtime. |

When changing or setting any environment variables, be aware of [Environment variable precedence](envvars-precedence.md).

## Configuration details

### Project and file configuration

#### COMPOSE\_PROJECT\_NAME

Sets the project name. This value is prepended along with the service name to
the container's name on startup.

For example, if your project name is `myapp` and it includes two services `db` and `web`, 
then Compose starts containers named `myapp-db-1` and `myapp-web-1` respectively.

Compose can set the project name in different ways. The level of precedence (from highest to lowest) for each method is as follows:

1. The `-p` command line flag 
2. `COMPOSE_PROJECT_NAME`
3. The top-level `name:` variable from the config file (or the last `name:` from
  a series of config files specified using `-f`)
4. The `basename` of the project directory containing the config file (or
  containing the first config file specified using `-f`)
5. The `basename` of the current directory if no config file is specified

Project names must contain only lowercase letters, decimal digits, dashes, and
underscores, and must begin with a lowercase letter or decimal digit. If the
`basename` of the project directory or current directory violates this
constraint, you must use one of the other mechanisms.

See also [using `-p` to specify a project name](/reference/cli/docker/compose/#use--p-to-specify-a-project-name).

#### COMPOSE\_FILE

Specifies the path to a Compose file. Specifying multiple Compose files is supported.

- Default behavior: If not provided, Compose looks for a file named `compose.yaml` in the current directory and, if not found, then Compose searches each parent directory recursively until a file by that name is found.
- When specifying multiple Compose files, the path separators are, by default, on:
   - Mac and Linux: `:` (colon)
   - Windows: `;` (semicolon)
   For example:

      ```console
      COMPOSE_FILE=compose.yaml:compose.prod.yaml
      ```  
   The path separator can also be customized using [`COMPOSE_PATH_SEPARATOR`](#compose_path_separator).  

See also [using `-f` to specify name and path of one or more Compose files](/reference/cli/docker/compose/#use--f-to-specify-the-name-and-path-of-one-or-more-compose-files).

#### COMPOSE\_PROFILES

Specifies one or more profiles to be enabled when `docker compose up` is run.

Services with matching profiles are started as well as any services for which no profile has been defined.

For example, calling `docker compose up` with `COMPOSE_PROFILES=frontend` selects services with the 
`frontend` profile as well as any services without a profile specified.

If specifying multiple profiles, use a comma as a separator.

The following example enables all services matching both the `frontend` and `debug` profiles and services without a profile. 

```console
COMPOSE_PROFILES=frontend,debug
```

See also [Using profiles with Compose](../profiles.md) and the [`--profile` command-line option](/reference/cli/docker/compose/#use-profiles-to-enable-optional-services).

#### COMPOSE\_PATH\_SEPARATOR

Specifies a different path separator for items listed in `COMPOSE_FILE`.

- Defaults to:
    - On macOS and Linux to `:`
    - On Windows to`;`

#### COMPOSE\_ENV\_FILES

Specifies which environment files Compose should use if `--env-file` isn't used.

When using multiple environment files, use a comma as a separator. For example: 

```console
COMPOSE_ENV_FILES=.env.envfile1,.env.envfile2
```

If `COMPOSE_ENV_FILES` is not set, and you don't provide `--env-file` in the CLI, Docker Compose uses the default behavior, which is to look for an `.env` file in the project directory.

#### COMPOSE\_DISABLE\_ENV\_FILE

Lets you disable the use of the default `.env` file. 

- Supported values: 
    - `true` or `1`, Compose ignores the `.env` file
    - `false` or `0`, Compose looks for an `.env` file in the project directory
- Defaults to: `0`

### Environment handling and container lifecycle

#### COMPOSE\_CONVERT\_WINDOWS\_PATHS

When enabled, Compose performs path conversion from Windows-style to Unix-style in volume definitions.

- Supported values: 
    - `true` or `1`, to enable
    - `false` or `0`, to disable
- Defaults to: `0`

#### COMPOSE\_IGNORE\_ORPHANS

When enabled, Compose doesn't try to detect orphaned containers for the project.

- Supported values: 
   - `true` or `1`, to enable
   - `false` or `0`, to disable
- Defaults to: `0`

#### COMPOSE\_REMOVE\_ORPHANS

When enabled, Compose automatically removes orphaned containers when updating a service or stack. Orphaned containers are those that were created by a previous configuration but are no longer defined in the current `compose.yaml` file.

- Supported values:
   - `true` or `1`, to enable automatic removal of orphaned containers
   - `false` or `0`, to disable automatic removal. Compose displays a warning about orphaned containers instead.
- Defaults to: `0`

#### COMPOSE\_PARALLEL\_LIMIT

Specifies the maximum level of parallelism for concurrent engine calls.

### Output 

#### COMPOSE\_ANSI

Specifies when to print ANSI control characters. 

- Supported values:
   - `auto`, Compose detects if TTY mode can be used. Otherwise, use plain text mode
   - `never`, use plain text mode
   - `always` or `0`, use TTY mode
- Defaults to: `auto`

#### COMPOSE\_STATUS\_STDOUT

When enabled, Compose writes its internal status and progress messages to `stdout` instead of `stderr`. 
The default value is false to clearly separate the output streams between Compose messages and your container's logs.

- Supported values:
   - `true` or `1`, to enable
   - `false` or `0`, to disable
- Defaults to: `0`

#### COMPOSE\_PROGRESS

{{< summary-bar feature_name="Compose progress" >}}

Defines the type of progress output, if `--progress` isn't used. 

Supported values are `auto`, `tty`, `plain`, `json`, and `quiet`.
Default is `auto`. 

### User experience

#### COMPOSE\_MENU

{{< summary-bar feature_name="Compose menu" >}}

When enabled, Compose displays a navigation menu where you can choose to open the Compose stack in Docker Desktop, switch on [`watch` mode](../file-watch.md), or use [Docker Debug](/reference/cli/docker/debug/).

- Supported values:
   - `true` or `1`, to enable
   - `false` or `0`, to disable
- Defaults to: `1` if you obtained Docker Compose through Docker Desktop, otherwise the default is `0`

#### COMPOSE\_EXPERIMENTAL

{{< summary-bar feature_name="Compose experimental" >}}

This is an opt-out variable. When turned off it deactivates the experimental features.

- Supported values:
   - `true` or `1`, to enable
   - `false` or `0`, to disable
- Defaults to: `1`

## Unsupported in Compose V2

The following environment variables have no effect in Compose V2.

- `COMPOSE_API_VERSION`
    By default the API version is negotiated with the server. Use `DOCKER_API_VERSION`.  
    See the [Docker CLI environment variable reference](/reference/cli/docker/#environment-variables) page.
- `COMPOSE_HTTP_TIMEOUT`
- `COMPOSE_TLS_VERSION`
- `COMPOSE_FORCE_WINDOWS_HOST`
- `COMPOSE_INTERACTIVE_NO_CLI`
- `COMPOSE_DOCKER_CLI_BUILD`
    Use `DOCKER_BUILDKIT` to select between BuildKit and the classic builder. If `DOCKER_BUILDKIT=0` then `docker compose build` uses the classic builder to build images.


---

# Set environment variables within your container's environment

*Sección: Compose*

A container's environment is not set until there's an explicit entry in the service configuration to make this happen. With Compose, there are two ways you can set environment variables in your containers with your Compose file. 

>[!TIP]
>
> Don't use environment variables to pass sensitive information, such as passwords, in to your containers. Use [secrets](../use-secrets.md) instead.


## Use the `environment` attribute

You can set environment variables directly in your container's environment with the
[`environment` attribute](../../../reference/compose-file/services.md#environment) in your `compose.yaml`.

It supports both list and mapping syntax:

```yaml
services:
  webapp:
    environment:
      DEBUG: "true"
```
is equivalent to 
```yaml
services:
  webapp:
    environment:
      - DEBUG=true
```

See [`environment` attribute](../../../reference/compose-file/services.md#environment) for more examples on how to use it. 

### Additional information 

- You can choose not to set a value and pass the environment variables from your shell straight through to your containers. It works in the same way as `docker run -e VARIABLE ...`:
  ```yaml
  web:
    environment:
      - DEBUG
  ```
The value of the `DEBUG` variable in the container is taken from the value for the same variable in the shell in which Compose is run. Note that in this case no warning is issued if the `DEBUG` variable in the shell environment is not set. 

- You can also take advantage of [interpolation](variable-interpolation.md#interpolation-syntax). In the following example, the result is similar to the one above but Compose gives you a warning if the `DEBUG` variable is not set in the shell environment or in an `.env` file in the project directory.

  ```yaml
  web:
    environment:
      - DEBUG=${DEBUG}
  ```

## Use the `env_file` attribute

A container's environment can also be set using [`.env` files](variable-interpolation.md#env-file) along with the [`env_file` attribute](../../../reference/compose-file/services.md#env_file).

```yaml
services:
  webapp:
    env_file: "webapp.env"
```

Using an `.env` file lets you use the same file for use by a plain `docker run --env-file ...` command, or to share the same `.env` file within multiple services without the need to duplicate a long `environment` YAML block.

It can also help you keep your environment variables separate from your main configuration file, providing a more organized and secure way to manage sensitive information, as you do not need to place your `.env` file in the root of your project's directory.

The [`env_file` attribute](../../../reference/compose-file/services.md#env_file) also lets you use multiple `.env` files in your Compose application.  

The paths to your `.env` file, specified in the `env_file` attribute, are relative to the location of your `compose.yaml` file.

> [!IMPORTANT]
>
> Interpolation in `.env` files is a Docker Compose CLI feature.
>
> It is not supported when running `docker run --env-file ...`.

### Additional information 

- If multiple files are specified, they are evaluated in order and can override values set in previous files.
- As of Docker Compose version 2.24.0, you can set your `.env` file, defined by the `env_file` attribute, to be optional by using the `required` field. When `required` is set to `false` and the `.env` file is missing, Compose silently ignores the entry.
  ```yaml
  env_file:
    - path: ./default.env
      required: true # default
    - path: ./override.env
      required: false
  ``` 
- As of Docker Compose version 2.30.0, you can use an alternative file format for the `env_file` with the `format` attribute. For more information, see [`format`](../../../reference/compose-file/services.md#format).
- Values in your `.env` file can be overridden from the command line by using [`docker compose run -e`](#set-environment-variables-with-docker-compose-run---env). 

## Set environment variables with `docker compose run --env`

Similar to `docker run --env`, you can set environment variables temporarily with `docker compose run --env` or its short form `docker compose run -e`:

```console
$ docker compose run -e DEBUG=1 web python console.py
```

### Additional information 

- You can also pass a variable from the shell or your environment files by not giving it a value:

  ```console
  $ docker compose run -e DEBUG web python console.py
  ```

The value of the `DEBUG` variable in the container is taken from the value for the same variable in the shell in which Compose is run or from the environment files.

## Further resources

- [Understand environment variable precedence](envvars-precedence.md).
- [Set or change predefined environment variables](envvars.md)
- [Explore best practices](best-practices.md)
- [Understand interpolation](variable-interpolation.md)


---

# Set, use, and manage variables in a Compose file with interpolation

*Sección: Compose*

A Compose file can use variables to offer more flexibility. If you want to quickly switch 
between image tags to test multiple versions, or want to adjust a volume source to your local
environment, you don't need to edit the Compose file each time, you can just set variables that insert values into your Compose file at runtime.

Interpolation can also be used to insert values into your Compose file at runtime, which is then used to pass variables into your container's environment

Below is a simple example: 

```console
$ cat .env
TAG=v1.5
$ cat compose.yaml
services:
  web:
    image: "webapp:${TAG}"
```

When you run `docker compose up`, the `web` service defined in the Compose file [interpolates](variable-interpolation.md) in the image `webapp:v1.5` which was set in the `.env` file. You can verify this with the
[config command](/reference/cli/docker/compose/config/), which prints your resolved application config to the terminal:

```console
$ docker compose config
services:
  web:
    image: 'webapp:v1.5'
```

## Interpolation syntax

Interpolation is applied for unquoted and double-quoted values.
Both braced (`${VAR}`) and unbraced (`$VAR`) expressions are supported.

For braced expressions, the following formats are supported:
- Direct substitution
  - `${VAR}` -> value of `VAR`
- Default value
  - `${VAR:-default}` -> value of `VAR` if set and non-empty, otherwise `default`
  - `${VAR-default}` -> value of `VAR` if set, otherwise `default`
- Required value
  - `${VAR:?error}` -> value of `VAR` if set and non-empty, otherwise exit with error
  - `${VAR?error}` -> value of `VAR` if set, otherwise exit with error
- Alternative value
  - `${VAR:+replacement}` -> `replacement` if `VAR` is set and non-empty, otherwise empty
  - `${VAR+replacement}` -> `replacement` if `VAR` is set, otherwise empty

For more information, see [Interpolation](../../../reference/compose-file/interpolation.md) in the Compose Specification. 

## Ways to set variables with interpolation

Docker Compose can interpolate variables into your Compose file from multiple sources. 

Note that when the same variable is declared by multiple sources, precedence applies:

1. Variables from your shell environment
2. Variables from a file set by `--env-file`
3. If `--env-file` is not set, variables from an `.env` file in the project directory,
   where the project directory is:
   - `--project-directory` if set
   - otherwise, the directory of the first Compose file specified with `-f`/`--file`
   - otherwise, your shell's current directory (`PWD`)

You can check variables and values used by Compose to interpolate the Compose model by running `docker compose config --environment`.

### `.env` file

An `.env` file in Docker Compose is a text file used to define variables that should be made available for interpolation when running `docker compose up`. This file typically contains key-value pairs of variables, and it lets you  centralize and manage configuration in one place. The `.env` file is useful if you have multiple variables you need to store.

The `.env` file is the default method for setting variables. The `.env` file should be placed at the root of the project directory next to your `compose.yaml` file. For more information on formatting an environment file, see [Syntax for environment files](#env-file-syntax).

Basic example: 

```console
$ cat .env
## define COMPOSE_DEBUG based on DEV_MODE, defaults to false
COMPOSE_DEBUG=${DEV_MODE:-false}

$ cat compose.yaml 
  services:
    webapp:
      image: my-webapp-image
      environment:
        - DEBUG=${COMPOSE_DEBUG}

$ DEV_MODE=true docker compose config
services:
  webapp:
    environment:
      DEBUG: "true"
```

#### Additional information 

- If you define a variable in your `.env` file, you can reference it directly in your `compose.yaml` with the [`environment` attribute](../../../reference/compose-file/services.md#environment). For example, if your `.env` file contains the environment variable `DEBUG=1` and your `compose.yaml` file looks like this:
   ```yaml
    services:
      webapp:
        image: my-webapp-image
        environment:
          - DEBUG=${DEBUG}
   ```
   Docker Compose replaces `${DEBUG}` with the value from the `.env` file

   > [!IMPORTANT]
   >
   > Be aware of [Environment variables precedence](envvars-precedence.md) when using variables in an `.env` file that  as environment variables in your container's environment.

- You can place your `.env` file in a location other than the root of your project's directory, and then use the [`--env-file` option in the CLI](#substitute-with---env-file) so Compose can navigate to it.

- Your `.env` file can be overridden by another `.env` if it is [substituted with `--env-file`](#substitute-with---env-file).

> [!IMPORTANT]
>
> Substitution from `.env` files is a Docker Compose CLI feature.
>
> It is not supported by Swarm when running `docker stack deploy`.

#### `.env` file syntax

The following syntax rules apply to environment files:

- Lines beginning with `#` are processed as comments and ignored.
- Blank lines are ignored.
- Unquoted and double-quoted (`"`) values have interpolation applied.
- Each line represents a key-value pair. Values can optionally be quoted.
- Delimiter separating key and value can be either `=` or `:`.
- Spaces before and after value are ignored.
  - `VAR=VAL` -> `VAL`
  - `VAR="VAL"` -> `VAL`
  - `VAR='VAL'` -> `VAL`
  - `VAR: VAL` -> `VAL`
  - `VAR = VAL  ` -> `VAL` <!-- markdownlint-disable-line no-space-in-code -->
- Inline comments for unquoted values must be preceded with a space.
  - `VAR=VAL # comment` -> `VAL`
  - `VAR=VAL# not a comment` -> `VAL# not a comment`
- Inline comments for quoted values must follow the closing quote.
  - `VAR="VAL # not a comment"` -> `VAL # not a comment`
  - `VAR="VAL" # comment` -> `VAL`
- Single-quoted (`'`) values are used literally.
  - `VAR='$OTHER'` -> `$OTHER`
  - `VAR='${OTHER}'` -> `${OTHER}`
- Quotes can be escaped with `\`.
  - `VAR='Let\'s go!'` -> `Let's go!`
  - `VAR="{\"hello\": \"json\"}"` -> `{"hello": "json"}`
- Common shell escape sequences including `\n`, `\r`, `\t`, and `\\` are supported in double-quoted values.
  - `VAR="some\tvalue"` -> `some  value`
  - `VAR='some\tvalue'` -> `some\tvalue`
  - `VAR=some\tvalue` -> `some\tvalue`
- Single-quoted values can span multiple lines. Example:

   ```yaml
   KEY='SOME
   VALUE'
   ```

   If you then run `docker compose config`, you'll see:
  
   ```yaml
   environment:
     KEY: |-
       SOME
       VALUE
   ```

### Substitute with `--env-file`

You can set default values for multiple environment variables, in an `.env` file and then pass the file as an argument in the CLI.

The advantage of this method is that you can store the file anywhere and name it appropriately, for example, 
This file path is relative to the current working directory where the Docker Compose command is executed. Passing the file path is done using the `--env-file` option:

```console
$ docker compose --env-file ./config/.env.dev up
```

#### Additional information 

- This method is useful if you want to temporarily override an `.env` file that is already referenced in your `compose.yaml` file. For example you may have different `.env` files for production ( `.env.prod`) and testing (`.env.test`).
  In the following example, there are two environment files, `.env` and `.env.dev`. Both have different values set for `TAG`. 
  ```console
  $ cat .env
  TAG=v1.5
  $ cat ./config/.env.dev
  TAG=v1.6
  $ cat compose.yaml
  services:
    web:
      image: "webapp:${TAG}"
  ```
  If the `--env-file` is not used in the command line, the `.env` file is loaded by default:
  ```console
  $ docker compose config
  services:
    web:
      image: 'webapp:v1.5'
  ```
  Passing the `--env-file` argument overrides the default file path:
  ```console
  $ docker compose --env-file ./config/.env.dev config
  services:
    web:
      image: 'webapp:v1.6'
  ```
  When an invalid file path is being passed as an `--env-file` argument, Compose returns an error:
  ```console
  $ docker compose --env-file ./doesnotexist/.env.dev  config
  ERROR: Couldn't find env file: /home/user/./doesnotexist/.env.dev
  ```
- You can use multiple `--env-file` options to specify multiple environment files, and Docker Compose reads them in order. Later files can override variables from earlier files.
  ```console
  $ docker compose --env-file .env --env-file .env.override up
  ```
- You can override specific environment variables from the command line when starting containers. 
  ```console
  $ docker compose --env-file .env.dev up -e DATABASE_URL=mysql://new_user:new_password@new_db:3306/new_database
  ```

### local `.env` file versus &lt;project directory&gt; `.env` file

An `.env` file can also be used to declare [pre-defined environment variables](envvars.md) used to control Compose behavior and files to be loaded. 

When executed without an explicit `--env-file` flag, Compose searches for an `.env` file
in the project directory and loads values both for self-configuration and interpolation.
The project directory is determined by `--project-directory` if set, otherwise by the
directory of the first Compose file specified with `-f`/`--file`, otherwise `PWD`.
If the values in this file define the `COMPOSE_FILE` pre-defined variable, which results
in a project directory being set to another folder, Compose loads a second `.env` file,
if present. This second `.env` file has a lower precedence. 

This mechanism makes it possible to invoke an existing Compose project with a custom set of variables as overrides, without the need to pass environment variables by the command line.

```console
$ cat .env
COMPOSE_FILE=../compose.yaml
POSTGRES_VERSION=9.3

$ cat ../compose.yaml 
services:
  db:
    image: "postgres:${POSTGRES_VERSION}"
$ cat ../.env
POSTGRES_VERSION=9.2

$ docker compose config
services:
  db:
    image: "postgres:9.3"
```

### Substitute from the shell 

You can use existing environment variables from your host machine or from the shell environment where you execute `docker compose` commands. This lets you dynamically inject values into your Docker Compose configuration at runtime.
For example, suppose the shell contains `POSTGRES_VERSION=9.3` and you supply the following configuration:

```yaml
db:
  image: "postgres:${POSTGRES_VERSION}"
```

When you run `docker compose up` with this configuration, Compose looks for the `POSTGRES_VERSION` environment variable in the shell and substitutes its value in. For this example, Compose resolves the image to `postgres:9.3` before running the configuration.

If an environment variable is not set, Compose substitutes with an empty string. In the previous example, if `POSTGRES_VERSION` is not set, the value for the image option is `postgres:`.

> [!NOTE]
>
> `postgres:` is not a valid image reference. Docker expects either a reference without a tag, like `postgres` which defaults to the latest image, or with a tag such as `postgres:15`.


---

# Use Compose Watch

*Sección: Compose*

{{< summary-bar feature_name="Compose file watch" >}}

{{% include "compose/watch.md" %}}

`watch` adheres to the following file path rules:
* All paths are relative to the project directory, apart from ignore file patterns
* Directories are watched recursively
* Glob patterns aren't supported
* Rules from `.dockerignore` apply
  * Use `ignore` option to define additional paths to be ignored (same syntax)
  * Temporary/backup files for common IDEs (Vim, Emacs, JetBrains, & more) are ignored automatically
  * `.git` directories are ignored automatically

You don't need to switch on `watch` for all services in a Compose project. In some instances, only part of the project, for example the Javascript frontend, might be suitable for automatic updates.

Compose Watch is designed to work with services built from local source code using the `build` attribute. It doesn't track changes for services that rely on pre-built images specified by the `image` attribute.

## Compose Watch versus bind mounts

Compose supports sharing a host directory inside service containers. Watch mode does not replace this functionality but exists as a companion specifically suited to developing in containers.

More importantly, `watch` allows for greater granularity than is practical with a bind mount. Watch rules let you ignore specific files or entire directories within the watched tree.

For example, in a JavaScript project, ignoring the `node_modules/` directory has two benefits:
* Performance. File trees with many small files can cause a high I/O load in some configurations
* Multi-platform. Compiled artifacts cannot be shared if the host OS or architecture is different from the container

For example, in a Node.js project, it's not recommended to sync the `node_modules/` directory. Even though JavaScript is interpreted, `npm` packages can contain native code that is not portable across platforms.

## Configuration

The `watch` attribute defines a list of rules that control automatic service updates based on local file changes.

Each rule requires a `path` pattern and `action` to take when a modification is detected. There are two possible actions for `watch` and depending on
the `action`, additional fields might be accepted or required. 

Watch mode can be used with many different languages and frameworks.
The specific paths and rules will vary from project to project, but the concepts remain the same. 

### Prerequisites

In order to work properly, `watch` relies on common executables. Make sure your service image contains the following binaries:
* stat
* mkdir
* rmdir

`watch` also requires that the container's `USER` can write to the target path so it can update files. A common pattern is for 
initial content to be copied into the container using the `COPY` instruction in a Dockerfile. To ensure such files are owned 
by the configured user, use the `COPY --chown` flag:

```dockerfile
# Run as a non-privileged user
FROM node:18
RUN useradd -ms /bin/sh -u 1001 app
USER app

# Install dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install

# Copy source files into application directory
COPY --chown=app:app . /app
```

### `action`

#### Sync

If `action` is set to `sync`, Compose makes sure any changes made to files on your host automatically match with the corresponding files within the service container.

`sync` is ideal for frameworks that support "Hot Reload" or equivalent functionality.

More generally, `sync` rules can be used in place of bind mounts for many development use cases.

#### Rebuild

If `action` is set to `rebuild`, Compose automatically builds a new image with BuildKit and replaces the running service container.

The behavior is the same as running `docker compose up --build <svc>`.

Rebuild is ideal for compiled languages or as a fallback for modifications to particular files that require a full
image rebuild (e.g. `package.json`).

> [!NOTE]
>
> When a service is rebuilt, the previous image version becomes dangling. By default, Compose removes these superseded dangling images after each rebuild to avoid accumulating unused layers. To keep them, use `docker compose watch --prune=false`.

#### Sync + Restart

If `action` is set to `sync+restart`, Compose synchronizes your changes with the service containers and restarts them. 

`sync+restart` is ideal when the config file changes, and you don't need to rebuild the image but just restart the main process of the service containers. 
It will work well when you update a database configuration or your `nginx.conf` file, for example.

>[!TIP]
>
> Optimize your `Dockerfile` for speedy
incremental rebuilds with [image layer caching](/build/cache)
and [multi-stage builds](/build/building/multi-stage/).

### `path` and `target`

The `target` field controls how the path is mapped into the container.

For `path: ./app/html` and a change to `./app/html/index.html`:

* `target: /app/html` -> `/app/html/index.html`
* `target: /app/static` -> `/app/static/index.html`
* `target: /assets` -> `/assets/index.html`

### `ignore`

The `ignore` patterns are relative to the `path` defined in the current `watch` action, not to the project directory. In the following Example 1, the ignore path would be relative to the `./web` directory specified in the `path` attribute.

### `initial_sync`

When using a `sync+x` action, the `initial_sync` attribute tells Compose to ensure files that are part of the defined `path` are up to date before starting a new watch session.

## Example 1

This minimal example targets a Node.js application with the following structure:
```text
myproject/
├── web/
│   ├── App.jsx
│   ├── index.js
│   └── node_modules/
├── Dockerfile
├── compose.yaml
└── package.json
```

```yaml
services:
  web:
    build: .
    command: npm start
    develop:
      watch:
        - action: sync
          path: ./web
          target: /src/web
          initial_sync: true
          ignore:
            - node_modules/
        - action: rebuild
          path: package.json
```

In this example, when running `docker compose up --watch`, a container for the `web` service is launched using an image built from the `Dockerfile` in the project's root.
The `web` service runs `npm start` for its command, which then launches a development version of the application with Hot Module Reload enabled in the bundler (Webpack, Vite, Turbopack, etc).

After the service is up, the watch mode starts monitoring the target directories and files.
Then, whenever a source file in the `web/` directory is changed, Compose syncs the file to the corresponding location under `/src/web` inside the container.
For example, `./web/App.jsx` is copied to `/src/web/App.jsx`.

Once copied, the bundler updates the running application without a restart.

And in this case, the `ignore` rule would apply to `myproject/web/node_modules/`, not `myproject/node_modules/`.

Unlike source code files, adding a new dependency can’t be done on-the-fly, so whenever `package.json` is changed, Compose
rebuilds the image and recreates the `web` service container.

This pattern can be followed for many languages and frameworks, such as Python with Flask: Python source files can be synced while a change to `requirements.txt` should trigger a rebuild.

## Example 2 

Adapting the previous example to demonstrate `sync+restart`:

```yaml
services:
  web:
    build: .
    command: npm start
    develop:
      watch:
        - action: sync
          path: ./web
          target: /app/web
          ignore:
            - node_modules/
        - action: sync+restart
          path: ./proxy/nginx.conf
          target: /etc/nginx/conf.d/default.conf

  backend:
    build:
      context: backend
      target: builder
```

This setup demonstrates how to use the `sync+restart` action in Docker Compose to efficiently develop and test a Node.js application with a frontend web server and backend service. The configuration ensures that changes to the application code and configuration files are quickly synchronized and applied, with the `web` service restarting as needed to reflect the changes.

## Use `watch`

{{% include "compose/configure-watch.md" %}}

> [!NOTE]
>
> Watch can also be used with the dedicated `docker compose watch` command if you don't want to 
> get the application logs mixed with the (re)build logs and filesystem sync events.

> [!TIP]
>
> Check out [`dockersamples/avatars`](https://github.com/dockersamples/avatars),
> or [local setup for Docker docs](https://github.com/docker/docs/blob/main/CONTRIBUTING.md)
> for a demonstration of Compose `watch`.

## Reference

- [Compose Develop Specification](../../reference/compose-file/develop.md)


---

# Run Docker Compose services with GPU access

*Sección: Compose*

Compose services can define GPU device reservations if the Docker host contains such devices and the Docker Daemon is set accordingly. For this, make sure you install the [prerequisites](../../engine/containers/resource-constraints.md#gpu) if you haven't already done so.

The examples in the following sections focus specifically on providing service containers access to GPU devices with Docker Compose. 

## Enabling GPU access to service containers

GPUs are referenced in a `compose.yaml` file using the [device](../../reference/compose-file/deploy.md#devices) attribute from the Compose Deploy specification, within your services that need them.

This provides more granular control over a GPU reservation as custom values can be set for the following device properties: 

- `capabilities`. This value is specified as a list of strings. For example, `capabilities: [gpu]`. You must set this field in the Compose file. Otherwise, it returns an error on service deployment.
- `count`. Specified as an integer or the value `all`, represents the number of GPU devices that should be reserved (providing the host holds that number of GPUs). If `count` is set to `all` or not specified, all GPUs available on the host are used by default.
- `device_ids`. This value, specified as a list of strings, represents GPU device IDs from the host. You can find the device ID in the output of `nvidia-smi` on the host. If no `device_ids` are set, all GPUs available on the host are used by default.
- `driver`. Specified as a string, for example `driver: 'nvidia'`
- `options`. Key-value pairs representing driver specific options.


> [!IMPORTANT]
>
> You must set the `capabilities` field. Otherwise, it returns an error on service deployment.

> [!NOTE]
>
> `count` and `device_ids` are mutually exclusive. You must only define one field at a time.

For more information on these properties, see the [Compose Deploy Specification](../../reference/compose-file/deploy.md#devices).

### Example of a Compose file for running a service with access to 1 GPU device

```yaml
services:
  test:
    image: nvidia/cuda:12.9.0-base-ubuntu22.04
    command: nvidia-smi
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]
```

Run with Docker Compose:

```console
$ docker compose up
Creating network "gpu_default" with the default driver
Creating gpu_test_1 ... done
Attaching to gpu_test_1    
test_1  | +-----------------------------------------------------------------------------+
test_1  | | NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.1     |
test_1  | |-------------------------------+----------------------+----------------------+
test_1  | | GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
test_1  | | Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
test_1  | |                               |                      |               MIG M. |
test_1  | |===============================+======================+======================|
test_1  | |   0  Tesla T4            On   | 00000000:00:1E.0 Off |                    0 |
test_1  | | N/A   23C    P8     9W /  70W |      0MiB / 15109MiB |      0%      Default |
test_1  | |                               |                      |                  N/A |
test_1  | +-------------------------------+----------------------+----------------------+
test_1  |                                                                                
test_1  | +-----------------------------------------------------------------------------+
test_1  | | Processes:                                                                  |
test_1  | |  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
test_1  | |        ID   ID                                                   Usage      |
test_1  | |=============================================================================|
test_1  | |  No running processes found                                                 |
test_1  | +-----------------------------------------------------------------------------+
gpu_test_1 exited with code 0

```

On machines hosting multiple GPUs, the `device_ids` field can be set to target specific GPU devices and `count` can be used to limit the number of GPU devices assigned to a service container. 

You can use `count` or `device_ids` in each of your service definitions. An error is returned if you try to combine both, specify an invalid device ID, or use a value of count that’s higher than the number of GPUs in your system.

```console
$ nvidia-smi   
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 450.80.02    Driver Version: 450.80.02    CUDA Version: 11.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Tesla T4            On   | 00000000:00:1B.0 Off |                    0 |
| N/A   72C    P8    12W /  70W |      0MiB / 15109MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  Tesla T4            On   | 00000000:00:1C.0 Off |                    0 |
| N/A   67C    P8    11W /  70W |      0MiB / 15109MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   2  Tesla T4            On   | 00000000:00:1D.0 Off |                    0 |
| N/A   74C    P8    12W /  70W |      0MiB / 15109MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   3  Tesla T4            On   | 00000000:00:1E.0 Off |                    0 |
| N/A   62C    P8    11W /  70W |      0MiB / 15109MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
```

## Access specific devices

To allow access only to GPU-0 and GPU-3 devices:

```yaml
services:
  test:
    image: tensorflow/tensorflow:latest-gpu
    command: python -c "import tensorflow as tf;tf.test.gpu_device_name()"
    deploy:
      resources:
        reservations:
          devices:
          - driver: nvidia
            device_ids: ['0', '3']
            capabilities: [gpu]

```


---

# Use init containers in Compose

*Sección: Compose*

{{< summary-bar feature_name="Compose pre_start" >}}

Init containers are short-lived containers that run before a service's main container starts. They execute sequentially, each running to completion before the next begins. If any step exits with a non-zero code, the service will not start.

Use them for setup work that must finish before the application boots: running database migrations, fixing volume permissions, generating dynamic configuration, or executing any ordered sequence of prerequisites.

Compose models init containers as [`pre_start`](../../reference/compose-file/services.md#pre_start) lifecycle hooks. Unlike [`post_start`](../../reference/compose-file/services.md#post_start) and [`pre_stop`](../../reference/compose-file/services.md#pre_stop), which run a command inside the running service container, each `pre_start` step runs in its own ephemeral container created after the service container is created but before it is started.

## When not to use init containers

For static files and secrets, use the native [`configs`](../../reference/compose-file/configs.md) and [`secrets`](../../reference/compose-file/secrets.md) top-level elements instead. Compose mounts them directly into containers with a configurable target path, mode, UID, and GID. No init container required.

For background tasks with their own lifecycle - scheduled backups, post-exit cleanup, periodic maintenance — init containers are the wrong tool. Those tasks run independently of service startup, not before it.

## How `pre_start` containers run

Each step in a service's `pre_start` list:

- Runs in its own ephemeral container, created after the service container is created but before it starts.
- Inherits the service's image by default. Set `image` to override. The hook image follows the parent service's `pull_policy`, including refresh interval (`daily`, `weekly`, `every_<duration>`). This applies when starting services and when running `docker compose pull`.
- Joins the same networks as the service, so it can reach services declared in [`depends_on`](../../reference/compose-file/services.md#depends_on).
- Shares the service's volume mounts, so files written to a shared volume are immediately visible to the service.
- Must exit `0` for the next step, and the service itself, to start. A non-zero exit aborts startup for the service and anything that depends on it.

A `pre_start` step is skipped on subsequent `docker compose up` runs if it previously succeeded, its definition hasn't changed, or when the service container restarts under its `restart` policy. It reruns if the definition changes, the previous run failed, or the service is recreated with `--force-recreate`.

## Examples

### Run a database migration before the app starts

In the following example, `app` waits for `db` to be healthy, then runs
`./manage.py migrate` in an ephemeral container that reuses the app's
image. The service container only starts once the migration exits `0`.

```yaml
services:
  app:
    image: myapp:latest
    depends_on:
      db:
        condition: service_healthy
    pre_start:
      - command: ["./manage.py", "migrate"]

  db:
    image: postgres:18
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 10s
```

If the migration fails, `app` does not start and the failure is reported in
the `docker compose up` output.

### Fix volume ownership before a non-root service starts

Named volumes are created with root ownership. When the service runs as a
non-root user, you can use a `pre_start` step to adjust ownership before
the service mounts the volume.

```yaml
services:
  app:
    image: myapp:latest
    user: "1000:1000"
    volumes:
      - data:/data
    pre_start:
      - image: busybox
        user: root
        command: sh -c 'chown -R 1000:1000 /data'

volumes:
  data:
```

The `pre_start` step uses a different image (`busybox`) and runs as `root`,
even though the service itself runs as user `1000`.

### Chain multiple setup steps

`pre_start` steps run in declared order. The next step only starts once the
previous one exits `0`. In the following example, the application waits
for migrations to finish, then for seed data to load, before starting.

```yaml
services:
  app:
    image: myapp:latest
    depends_on:
      db:
        condition: service_healthy
    pre_start:
      - command: ["./manage.py", "migrate"]
      - command: ["./manage.py", "loaddata", "fixtures.json"]

  db:
    image: postgres:18
```

Each step runs in its own ephemeral container. If the second step fails,
the first step is not rolled back, but `app` does not start.

### Replace the one-shot service pattern

Before `pre_start`, the common way to express "run X before Y starts" was
to model the setup work as a service with `restart: "no"` and have the main
service `depends_on` it with `condition: service_completed_successfully`:

```yaml
services:
  migrate:
    image: myapp:latest
    command: ["./manage.py", "migrate"]
    restart: "no"

  app:
    image: myapp:latest
    depends_on:
      migrate:
        condition: service_completed_successfully
```

The equivalent expressed with `pre_start`:

```yaml
services:
  app:
    image: myapp:latest
    pre_start:
      - command: ["./manage.py", "migrate"]
```

`pre_start` is preferable because:

- The setup work is modeled as a subordinate step of the service, not as a peer service that exits immediately.
- Completed steps do not appear as exited services in `docker compose ps`.
- Chaining several setup steps does not require a web of `depends_on` edges between one-shot services.
- The ephemeral container inherits the service's image by default, so no duplicate `image:` declaration is needed.

The one-shot service pattern still has its place when the setup work is a shared concern that multiple services depend on, or when it needs to be addressable independently of any single service.

## Limitations

- `pre_start` runs once for the service as a whole, not once per replica (`per_replica: false`). Per-replica execution (`per_replica: true`) is not yet supported.
- Volume mounts shared across replicas (named volumes, bind mounts) are accessible from a `pre_start` step. Per-instance mounts such as `tmpfs`
  or anonymous volumes cannot be addressed by a single shared run.
- `pre_start` does not re-trigger when you scale a service up. A step runs again only on definition change, prior failure, or `--force-recreate`.

## Reference and additional information

- [`pre_start`](../../reference/compose-file/services.md#pre_start)
- [`post_start`](../../reference/compose-file/services.md#post_start)
- [`pre_stop`](../../reference/compose-file/services.md#pre_stop)
- [`depends_on`](../../reference/compose-file/services.md#depends_on)
- [Use lifecycle hooks](lifecycle.md)
- [Control startup order](startup-order.md)


---

# Using lifecycle hooks with Compose

*Sección: Compose*

{{< summary-bar feature_name="Compose lifecycle hooks" >}}

## Services lifecycle hooks

When Docker Compose runs a container, it uses two elements, 
[ENTRYPOINT and COMMAND](/manuals/engine/containers/run.md#default-command-and-options), 
to manage what happens when the container starts and stops.

However, it can sometimes be easier to handle these tasks separately with lifecycle hooks - 
commands that run right after the container starts or just before it stops.

Lifecycle hooks are particularly useful because they can have special privileges 
(like running as the root user), even when the container itself runs with lower privileges 
for security. This means that certain tasks requiring higher permissions can be done without 
compromising the overall security of the container.

### Post-start hooks

Post-start hooks are commands that run after the container has started, but there's no 
set time for when exactly they will execute. The hook execution timing is not assured during 
the execution of the container's `entrypoint`.

Because there is no ordering guarantee between the hook and the container's entrypoint,
post-start hooks are best suited for tasks that do not need to complete before the
application begins running, such as registering the container with an external system.

In the following example, after the container starts, a root-level hook registers the
service with an internal service registry. The application does not depend on registration
being complete before it starts serving requests.

```yaml
services:
  app:
    image: backend
    user: 1001
    post_start:
      - command: /opt/scripts/register-service.sh
        user: root
```

### Pre-stop hooks

Pre-stop hooks are commands that run before the container is stopped by a specific 
command (like `docker compose down` or stopping it manually with `Ctrl+C`). 
These hooks won't run if the container stops by itself or gets killed suddenly.

Because the pre-stop hook runs before the stop signal is sent to the container, it is
suited for actions that must complete while the application is still fully running.

In the following example, the hook backs up a data file before the container receives the stop signal.

```yaml
services:
  app:
    image: backend
    volumes:
      - data:/data
    pre_stop:
      - command: cp /data/app.db /data/app.db.bak

volumes:
  data: {} # a Docker volume is created with root ownership
```

## Reference information

- [`post_start`](../../reference/compose-file/services.md#post_start)
- [`pre_stop`](../../reference/compose-file/services.md#pre_stop)


---

# Use multiple Compose files

*Sección: Compose*

This section contains information on the ways you can work with multiple Compose files. 

Using multiple Compose files lets you customize a Compose application for different environments or workflows. This is useful for large applications that may use dozens of containers, with ownership distributed across multiple teams. For example, if your organization or team uses a monorepo, each team may have their own “local” Compose file to run a subset of the application. They then need to rely on other teams to provide a reference Compose file that defines the expected way to run their own subset. Complexity moves from the code in to the infrastructure and the configuration file.

The simplest way to work with multiple Compose files is to [merge](merge.md) them using
the `-f` flag. This works well for straightforward overrides, but the
[merging rules](merge.md#merging-rules) can make it complex to manage as your
configuration grows.

Docker Compose provides two other options to manage this complexity when working with multiple Compose files. Depending on your project's needs, you can: 

- [Extend a Compose file](extends.md) by referring to another Compose file and selecting the bits you want to use in your own application, with the ability to override some attributes.
- [Include other Compose files](include.md) directly in your Compose file.


---

# Extend your Compose file

*Sección: Compose*

Docker Compose's [`extends` attribute](../../../reference/compose-file/services.md#extends)
lets you share common configurations among different files, or even different
projects entirely.

Extending services is useful if you have several services that reuse a common
set of configuration options. With `extends` you can define a common set of
service options in one place and refer to it from anywhere. You can refer to
another Compose file and select a service you want to also use in your own
application, with the ability to override some attributes for your own needs.

> [!IMPORTANT]
>
> When you use multiple Compose files, you must make sure all paths in the files
are relative to the base Compose file (i.e. the Compose file in your main-project folder). This is required because extend files
need not be valid Compose files. Extend files can contain small fragments of
configuration. Tracking which fragment of a service is relative to which path is
difficult and confusing, so to keep paths easier to understand, all paths must
be defined relative to the base file. 

> [!NOTE]
>
> `extends` is not supported when deploying with `docker stack deploy`. Running
> `docker stack config` on a Compose file that uses `extends` returns the error:
> `Configuration contains forbidden properties`.

## How the `extends` attribute works

### Extending services from another file

Take the following example:

```yaml
services:
  web:
    extends:
      file: common-services.yml
      service: webapp
```

This instructs Compose to reuse only the properties of the `webapp` service
defined in the `common-services.yml` file. The `webapp` service itself is not part of the final project.

If `common-services.yml`
looks like this:

```yaml
services:
  webapp:
    build: .
    ports:
      - "8000:8000"
    volumes:
      - "/data"
```
You get exactly the same result as if you wrote
`compose.yaml` with the same `build`, `ports`, and `volumes` configuration
values defined directly under `web`.

To include the service `webapp` in the final project when extending services from another file, you need to explicitly include both services in your current Compose file. For example (this is for illustrative purposes only):

```yaml
services:
  web:
    build: ./alpine
    command: echo
    extends:
      file: common-services.yml
      service: webapp
  webapp:
    extends:
      file: common-services.yml
      service: webapp
```

Alternatively, you can use [include](include.md). 

### Extending services within the same file 

If you define services in the same Compose file and extend one service from another, both the original service and the extended service will be part of your final configuration. For example:

```yaml 
services:
  web:
    build: ./alpine
    extends: webapp
  webapp:
    environment:
      - DEBUG=1
```

### Extending services within the same file and from another file

You can go further and define, or re-define, configuration locally in
`compose.yaml`:

```yaml
services:
  web:
    extends:
      file: common-services.yml
      service: webapp
    environment:
      - DEBUG=1
    cpu_shares: 5

  important_web:
    extends: web
    cpu_shares: 10
```

## Additional example

Extending an individual service is useful when you have multiple services that
have a common configuration. The example below is a Compose app with two
services, a web application and a queue worker. Both services use the same
codebase and share many configuration options.

The `common.yaml` file defines the common configuration:

```yaml
services:
  app:
    build: .
    environment:
      CONFIG_FILE_PATH: /code/config
      API_KEY: xxxyyy
    cpu_shares: 5
```

The `compose.yaml` defines the concrete services which use the common
configuration:

```yaml
services:
  webapp:
    extends:
      file: common.yaml
      service: app
    command: /code/run_web_app
    ports:
      - 8080:8080
    depends_on:
      - queue
      - db

  queue_worker:
    extends:
      file: common.yaml
      service: app
    command: /code/run_worker
    depends_on:
      - queue
```

## Relative paths

When using `extends` with a `file` attribute which points to another folder, relative paths 
declared by the service being extended are converted so they still point to the
same file when used by the extending service. This is illustrated in the following example:

Base Compose file:
```yaml
services:
  webapp:
    image: example
    extends:
      file: ../commons/compose.yaml
      service: base
```

The `commons/compose.yaml` file:
```yaml
services:
  base:
    env_file: ./container.env
```

The resulting service refers to the original `container.env` file
within the `commons` directory. This can be confirmed with `docker compose config`
which inspects the actual model:
```yaml
services:
  webapp:
    image: example
    env_file: 
      - ../commons/container.env
```

## Reference information

- [`extends`](../../../reference/compose-file/services.md#extends)


---

# Include

*Sección: Compose*

{{< summary-bar feature_name="Compose include" >}}

{{% include "compose/include.md" %}}

The [`include` top-level element](../../../reference/compose-file/include.md) helps to reflect the engineering team responsible for the code directly in the config file's organization. It also solves the relative path problem that [`extends`](extends.md) and [merge](merge.md) present. 

Each path listed in the `include` section loads as an individual Compose application model, with its own project directory, in order to resolve relative paths.

Once the included Compose application loads, all resources are copied into the current Compose application model.

> [!NOTE]
>
> `include` applies recursively so an included Compose file which declares its own `include` section, causes those files to also be included.

## Example

```yaml
include:
  - my-compose-include.yaml  #with serviceB declared
services:
  serviceA:
    build: .
    depends_on:
      - serviceB #use serviceB directly as if it was declared in this Compose file
```

`my-compose-include.yaml` manages `serviceB` which details some replicas, web UI to inspect data, isolated networks, volumes for data persistence, etc. The application relying on `serviceB` doesn’t need to know about the infrastructure details, and consumes the Compose file as a building block it can rely on. 

This means the team managing `serviceB` can refactor its own database component to introduce additional services without impacting any dependent teams. It also means that the dependent teams don't need to include additional flags on each Compose command they run.

```yaml
include:
  - oci://docker.io/username/my-compose-app:latest # use a Compose file stored as an OCI artifact
services:
  serviceA:
    build: .
    depends_on:
      - serviceB 
```
`include` allows you to reference Compose files from remote sources, such as OCI artifacts or Git repositories.  
Here `serviceB` is defined in a Compose file stored on Docker Hub.

## Using overrides with included Compose files

Compose reports an error if any resource from `include` conflicts with resources from the included Compose file. This rule prevents
unexpected conflicts with resources defined by the included compose file author. However, there may be some circumstances where you might want to customize the
included model. This can be achieved by adding an override file to the include directive:

```yaml
include:
  - path : 
      - third-party/compose.yaml
      - override.yaml  # local override for third-party model
```

The main limitation with this approach is that you need to maintain a dedicated override file per include. For complex projects with multiple
includes this would result in many Compose files.

The other option is to use a `compose.override.yaml` file. While conflicts will be rejected from the file using `include` when same
resource is declared, a global Compose override file can override the resulting merged model, as demonstrated in following example:

Main `compose.yaml` file:
```yaml
include:
  - team-1/compose.yaml # declare service-1
  - team-2/compose.yaml # declare service-2
```

Override `compose.override.yaml` file:
```yaml
services:
  service-1:
    # override included service-1 to enable debugger port
    ports:
      - 2345:2345

  service-2:
    # override included service-2 to use local data folder containing test data
    volumes:
      - ./data:/data
```

Combined together, this allows you to benefit from third-party reusable components, and adjust the Compose model for your needs.

## Reference information

[`include` top-level element](../../../reference/compose-file/include.md)


---

# Merge Compose files

*Sección: Compose*

Docker Compose lets you merge and override a set of Compose files together to create a composite Compose file.

By default, Compose reads two files, a `compose.yaml` and an optional
`compose.override.yaml` file. By convention, the `compose.yaml`
contains your base configuration. The override file can
contain configuration overrides for existing services or entirely new
services.

If a service is defined in both files, Compose merges the configurations using
the rules described below and in the 
[Compose Specification](../../../reference/compose-file/merge.md).

## How to merge multiple Compose files

To use multiple override files, or an override file with a different name, you
can either use the pre-defined [COMPOSE_FILE](../environment-variables/envvars.md#compose_file) environment variable, or use the `-f` option to specify the list of files. 

Compose merges files in
the order they're specified on the command line. Subsequent files may merge, override, or
add to their predecessors.

For example:

```console
$ docker compose -f compose.yaml -f compose.admin.yaml run backup_db
```

The `compose.yaml` file might specify a `webapp` service.

```yaml
webapp:
  image: examples/web
  ports:
    - "8000:8000"
  volumes:
    - "/data"
```

The `compose.admin.yaml` may also specify this same service: 

```yaml
webapp:
  environment:
    - DEBUG=1
```

Any matching
fields override the previous file. New values, add to the `webapp` service
configuration:

```yaml
webapp:
  image: examples/web
  ports:
    - "8000:8000"
  volumes:
    - "/data"
  environment:
    - DEBUG=1
```

## Merging rules 

- Paths are evaluated relative to the base file. When you use multiple Compose files, you must make sure all paths in the files are relative to the base Compose file (the first Compose file specified
with `-f`). This is required because override files need not be valid
Compose files. Override files can contain small fragments of configuration.
Tracking which fragment of a service is relative to which path is difficult and
confusing, so to keep paths easier to understand, all paths must be defined
relative to the base file.

   >[!TIP]
   >
   > You can use `docker compose config` to review your merged configuration and avoid path-related issues.

- Compose copies configurations from the original service over to the local one.
If a configuration option is defined in both the original service and the local
service, the local value replaces or extends the original value.

   - For single-value options like `image`, `command` or `mem_limit`, the new value replaces the old value.

      original service:

      ```yaml
      services:
        myservice:
          # ...
          command: python app.py
      ```

      local service:

      ```yaml
      services:
        myservice:
          # ...
          command: python otherapp.py
      ```

      result:

      ```yaml
      services:
        myservice:
          # ...
          command: python otherapp.py
      ```

   - For the multi-value options `ports`, `expose`, `external_links`, `dns`, `dns_search`, and `tmpfs`, Compose concatenates both sets of values:

      original service:

      ```yaml
      services:
        myservice:
          # ...
          expose:
            - "3000"
      ```

      local service:

      ```yaml
      services:
        myservice:
          # ...
          expose:
            - "4000"
            - "5000"
      ```

      result:

      ```yaml
      services:
        myservice:
          # ...
          expose:
            - "3000"
            - "4000"
            - "5000"
      ```

   - In the case of `environment`, `labels`, `volumes`, and `devices`, Compose "merges" entries together with locally defined values taking precedence. For `environment` and `labels`, the environment variable or label name determines which value is used:

      original service:

      ```yaml
      services:
        myservice:
          # ...
          environment:
            - FOO=original
            - BAR=original
      ```

      local service:

      ```yaml
      services:
        myservice:
          # ...
          environment:
            - BAR=local
            - BAZ=local
      ```

     result:

      ```yaml
      services:
        myservice:
          # ...
          environment:
            - FOO=original
            - BAR=local
            - BAZ=local
      ```

   - Entries for `volumes` and `devices` are merged using the mount path in the container:

      original service:

      ```yaml
      services:
        myservice:
          # ...
          volumes:
            - ./original:/foo
            - ./original:/bar
      ```

      local service:

      ```yaml
      services:
        myservice:
          # ...
          volumes:
            - ./local:/bar
            - ./local:/baz
      ```

      result:

      ```yaml
      services:
        myservice:
          # ...
          volumes:
            - ./original:/foo
            - ./local:/bar
            - ./local:/baz
      ```

For more merging rules, see [Merge and override](../../../reference/compose-file/merge.md) in the Compose Specification. 

### Additional information

- Using `-f` is optional. If not provided, Compose searches the working directory and its parent directories for a `compose.yaml` and a `compose.override.yaml` file. You must supply at least the `compose.yaml` file. If both files exist on the same directory level, Compose combines them into a single configuration.

- You can use a `-f` with `-` (dash) as the filename to read the configuration from `stdin`. For example: 
   ```console
   $ docker compose -f - <<EOF
     webapp:
       image: examples/web
       ports:
        - "8000:8000"
       volumes:
        - "/data"
       environment:
        - DEBUG=1
     EOF
   ```
   
   When `stdin` is used, all paths in the configuration are relative to the current working directory.
   
- You can use the `-f` flag to specify a path to a Compose file that is not located in the current directory, either from the command line or by setting up a [COMPOSE_FILE environment variable](../environment-variables/envvars.md#compose_file) in your shell or in an environment file.

   For example, if you are running the [Compose Rails sample](https://github.com/docker/awesome-compose/tree/master/official-documentation-samples/rails/README.md), and have a `compose.yaml` file in a directory called `sandbox/rails`. You can use a command like [docker compose pull](/reference/cli/docker/compose/pull/) to get the postgres image for the `db` service from anywhere by using the `-f` flag as follows: `docker compose -f ~/sandbox/rails/compose.yaml pull db`

   Here's the full example:

   ```console
   $ docker compose -f ~/sandbox/rails/compose.yaml pull db
   Pulling db (postgres:18)...
   18: Pulling from library/postgres
   ef0380f84d05: Pull complete
   50cf91dc1db8: Pull complete
   d3add4cd115c: Pull complete
   467830d8a616: Pull complete
   089b9db7dc57: Pull complete
   6fba0a36935c: Pull complete
   81ef0e73c953: Pull complete
   338a6c4894dc: Pull complete
   15853f32f67c: Pull complete
   044c83d92898: Pull complete
   17301519f133: Pull complete
   dcca70822752: Pull complete
   cecf11b8ccf3: Pull complete
   Digest: sha256:1364924c753d5ff7e2260cd34dc4ba05ebd40ee8193391220be0f9901d4e1651
   Status: Downloaded newer image for postgres:18
   ```

## Example

A common use case for multiple files is changing a development Compose app
for a production-like environment (which may be production, staging or CI).
To support these differences, you can split your Compose configuration into
a few different files:

Start with a base file that defines the canonical configuration for the
services.

`compose.yaml`

```yaml
services:
  web:
    image: example/my_web_app:latest
    depends_on:
      - db
      - cache

  db:
    image: postgres:18

  cache:
    image: redis:latest
```

In this example the development configuration exposes some ports to the
host, mounts our code as a volume, and builds the web image.

`compose.override.yaml`

```yaml
services:
  web:
    build: .
    volumes:
      - '.:/code'
    ports:
      - 8883:80
    environment:
      DEBUG: 'true'

  db:
    command: '-d'
    ports:
     - 5432:5432

  cache:
    ports:
      - 6379:6379
```

When you run `docker compose up` it reads the overrides automatically.

To use this Compose app in a production environment, another override file is created, which might be stored in a different git
repository or managed by a different team.

`compose.prod.yaml`

```yaml
services:
  web:
    ports:
      - 80:80
    environment:
      PRODUCTION: 'true'

  cache:
    environment:
      TTL: '500'
```

To deploy with this production Compose file you can run

```console
$ docker compose -f compose.yaml -f compose.prod.yaml up -d
```

This deploys all three services using the configuration in
`compose.yaml` and `compose.prod.yaml` but not the
dev configuration in `compose.override.yaml`.

For more information, see [Using Compose in production](../production.md). 

## Limitations

When merging Compose files, all relative paths (for build contexts, environment files,
bind-mounted volumes, and other resources) are resolved relative to the base Compose file. The
first file specified with `-f`, or `compose.yaml` in the current directory if `-f` is
not used. Paths in override files are not resolved relative to the override file's own
location.

This means that in a monorepo where Compose files are spread across team or component
subdirectories, relative paths in those files are resolved incorrectly when used as
override files.

> [!TIP] 
>
> If you need each Compose file's paths to resolve relative to its own location,
> use the [`include` top-level element](include.md) instead of merging with `-f`. Each
> included file is loaded with its own project directory, so relative paths resolve
> correctly.

## Reference information

- [Merge rules](../../../reference/compose-file/merge.md)


---

# Networking in Compose

*Sección: Compose*

Compose handles networking for you by default, but gives you fine-grained control when you need it. This page explains how the default network works and how containers discover each other by name. It also covers when and how to define custom networks, connect services across separate Compose projects, map custom hostnames, and debug connectivity issues.

## Default network and service discovery

By default, Compose sets up a single [network](/reference/cli/docker/network/create/) for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by its service name. This network uses the `bridge` driver. To attach services to a different Compose network or an external one, see [Specify custom networks](#specify-custom-networks). To change how a service uses the host network stack (`network_mode: host`), see [Change the network mode](#change-the-network-mode).

For most development setups, the default network is sufficient. When you run `docker compose up`, Compose creates a network named `<project-name>_default` and attaches all services to it. Each service registers its name with an internal DNS server, so containers can reach each other using the service name directly. No IP addresses or manual configuration is needed.

For example, suppose your app is in a directory called `myapp`, and your `compose.yaml` looks like this:

```yaml
services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres:latest
    ports:
      - "8001:5432"
```

Compose automatically connects all services to the default network, so you don't need to define `networks` explicitly in the Compose file.

When you run `docker compose up`, the following happens:

1. A network called `myapp_default` is created.
2. A container is created using `web`'s configuration. It joins `myapp_default` under the name `web`.
3. A container is created using `db`'s configuration. It joins `myapp_default` under the name `db`.

Each container can now look up the service name `web` or `db` and get back the appropriate container's IP address. The `web` service can connect to the database at `postgres://db:5432`. From the host machine, the same database is accessible at `postgres://localhost:8001` if your container is running locally.

> [!TIP]
>
> Docker assigns container IP addresses dynamically from the network's subnet each time a container starts so they are not persisted across restarts or recreations. This means you should always reference services by name, not IP address. When containers are recreated, for example after a configuration change, they receive a new IP address. The service name stays stable.

Your app's network is given a name based on the "project name", which is taken from the name of the directory it lives in. You can override the project name with either the [`--project-name` flag](/reference/cli/docker/compose/) or the [`COMPOSE_PROJECT_NAME` environment variable](environment-variables/envvars.md#compose_project_name).

The `HOST_PORT` and `CONTAINER_PORT` serve different purposes. In the example above, for `db`, the `HOST_PORT` is `8001` and the container port is `5432` (the Postgres default). Networked service-to-service communication uses the `CONTAINER_PORT`. The host port is only used when accessing the service from outside the network.

### Updating containers on the network

If you make a configuration change to a service and run `docker compose up` to update it, the old container is removed and the new one joins the network under a different IP address but the same name. Running containers can look up that name and connect to the new address, but the old address stops working.

If any containers have connections open to the old container, they are closed. It is each container's responsibility to detect this condition, look up the name again, and reconnect.

## Change the network mode

By default, each service joins the project's bridge network. It is the most secure networking mode. If you don't specify [`network_mode`](../../reference/compose-file/services.md#network_mode), this is the type of network you are creating.

You can override the networking mode on a per-service basis. The `network_mode` option accepts the following values:

- `host`: The container shares the host's network stack. No port mapping is needed or supported, and service name DNS resolution does not work. Use for system-level tools like network monitors that require direct access to host interfaces. A container using `network_mode: host` can access all host ports and observe all network traffic on the host. Use it only when genuinely required.
- `none`: Turns off all container networking.
- `service:{name}`: Gives the container access to the specified container by referring to its service name.
- `container:{name}`: Gives the container access to the specified container by referring to its container ID.

You can mix modes in a single project:

```yaml
services:
  app:
    image: myapp
    networks:
      - isolated
    ports:
      - "3000:3000"

  monitoring:
    image: netdata/netdata
    network_mode: host   # Can monitor host system and all host ports

networks:
  isolated:
    driver: bridge
```

## Specify custom networks

Instead of just using the default app network, you can specify your own networks with the top-level `networks` key. This lets you create more complex topologies and specify [custom network drivers](/engine/extend/plugins_network/) and options. You can also use it to connect services to externally-created networks which aren't managed by Compose.

Each service can specify what networks to connect to with the service-level `networks` key, which is a list of names referencing entries under the top-level `networks` key.

The following example shows a Compose file which defines two custom networks. The `proxy` service is isolated from the `db` service, because they do not share a network in common. Only `app` can talk to both.

```yaml
services:
  proxy:
    build: ./proxy
    networks:
      - frontend
  app:
    build: ./app
    networks:
      - frontend
      - backend
  db:
    image: postgres:latest
    networks:
      - backend

networks:
  frontend:
    driver: bridge   # Specify driver options
    driver_opts:
      com.docker.network.bridge.host_binding_ipv4: "127.0.0.1"
  backend:
    driver: custom-driver  # Use a custom driver
```

Networks can be configured with static IP addresses by setting the [ipv4_address and/or ipv6_address](../../reference/compose-file/services.md#ipv4_address-ipv6_address) for each attached network.

Networks can also be given a [custom name](../../reference/compose-file/networks.md#name):

```yaml
services:
  # ...
networks:
  frontend:
    name: custom_frontend
    driver: custom-driver-1
```

### Internal networks

Setting `internal: true` on a network creates it without a connection to the host's network interfaces. It has no default gateway for external connectivity. This is useful for services like databases that should be completely unreachable from outside the container network:

```yaml
services:
  cache:
    image: redis
    networks:
      - isolated

  worker:
    image: myworker
    networks:
      - isolated
      - public

networks:
  isolated:
    internal: true   # No external connectivity
  public:   # Standard bridge network, created by Compose on docker compose up
```

Note that a service connected to both an internal and a non-internal network (like `worker` above) can still reach the internet via the non-internal network `public`.

### Configure the default network

Instead of, or as well as, specifying your own networks, you can also change the settings of the app-wide default network by defining an entry under `networks` named `default`:

```yaml
services:
  web:
    build: .
    ports:
      - "8000:8000"
  db:
    image: postgres:latest

networks:
  default:
    driver: custom-driver-1   # Use a custom driver
```

## Use an existing external network

If you've manually created a bridge network using `docker network create`, you can connect your Compose services to it by marking the network as [`external`](../../reference/compose-file/networks.md#external):

```yaml
services:
  # ...
networks:
  network1:
    name: my-pre-existing-network
    external: true
```

Instead of creating `<project-name>_default`, Compose looks for a network called `my-pre-existing-network` and connects your containers to it.

### Connecting multiple Compose projects

External networks are particularly useful when services in separate Compose projects need to communicate. Create a shared network once, then reference it as external in each project:

```bash
docker network create inter-project
```

backend-compose.yaml:

```yaml
services:
  api:
    image: myapi:latest
    networks:
      - shared
      - default   # Also keep the project's internal network

networks:
  shared:
    external: true
    name: inter-project
```

frontend-compose.yaml:

```yaml
services:
  web:
    image: myfrontend:latest
    environment:
      API_URL: http://api:8080   # Reference by service name
    networks:
      - shared

networks:
  shared:
    external: true
    name: inter-project
```

Services on the same external network can reach each other by service name, just like services within a single project.

> [!IMPORTANT]
>
> The external network must exist before you run `docker compose up`. If it doesn't, Compose fails with a `Network not found` error. Always create it first with `docker network create`.

## Hybrid networking

A service can belong to both an external shared network and its own project-internal network. This lets you expose only the services that need to be reachable from other projects, while keeping everything else, such as databases, fully isolated:

```yaml
services:
  api:
    image: myapp-api
    networks:
      - shared     # Reachable from other projects
      - internal   # Can also reach the database

  database:
    image: postgres:latest
    networks:
      - internal   # Not exposed on the shared network

networks:
  shared:
    name: inter-project
    external: true
  internal: {}     # Project-specific, isolated
```

## Custom DNS with `extra_hosts`

You can add custom hostname-to-IP mappings to a container's `/etc/hosts` file using [`extra_hosts`](../../reference/compose-file/services.md#extra_hosts). This is useful when a service needs to resolve a hostname that isn't registered in Docker's internal DNS. For example, a fixed-IP dependency or a staging endpoint:

```yaml
services:
  app:
    image: myapp
    extra_hosts:
      - "api.staging:192.168.1.100"
      - "cache.internal:192.168.1.101"
```

To map a hostname dynamically to the host machine's IP, use the special `host-gateway` value:

```yaml
services:
  app:
    image: myapp
    extra_hosts:
      - "host.docker.internal:host-gateway"
```

On Linux, `host-gateway` resolves to the host's IP on the default bridge network. On Mac and Windows, Docker automatically provides this, `host-gateway` resolves to the same internal IP address as `host.docker.internal`.

You can also drive `extra_hosts` from environment variables, which makes it easy to point services at different targets per environment:

```yaml
services:
  app:
    image: myapp
    extra_hosts:
      - "api.service:${API_HOST:-127.0.0.1}"
      - "auth.service:${AUTH_HOST:-127.0.0.1}"
```

Where `.env.development` might set `API_HOST=localhost` and a production env file might set `API_HOST=10.0.1.50`.

To verify what has been injected, inspect the hosts file inside the container:

```bash
$ docker compose exec app cat /etc/hosts
```

## Multi-host networking

When deploying a Compose application on a Docker Engine with [Swarm mode enabled](../../engine/swarm/index.md), you can use the built-in `overlay` driver to enable multi-host communication. Overlay networks are always created as `attachable`. You can optionally set the [`attachable`](../../reference/compose-file/networks.md#attachable) property to `false`.

To learn more, see the [overlay network driver documentation](../../engine/network/drivers/overlay.md).

## Link containers

Links allow you to define extra aliases by which a service is reachable from another service. They are not required for basic service-to-service communication. By default, any service can reach any other service at that service's name. In the following example, `db` is reachable from `web` at both the hostnames `db` and `database`:

```yaml
services:
  web:
    build: .
    links:
      - "db:database"
  db:
    image: postgres:latest
```

See the [links reference](../../reference/compose-file/services.md#links) for more information.

## Debugging

When a service can't reach another, work through the following steps in order: first confirm the network configuration looks right, then confirm the containers are actually attached, then test live connectivity.

### Inspect port mappings

To find out which host port maps to a container port, use `docker compose port`:

```bash
# Which host port maps to container port 5432 on db?
$ docker compose port db 5432
# Output: 0.0.0.0:8001
```

This is especially useful when using dynamic port mapping, where the host port changes on every `docker compose up`:

```yaml
services:
  web:
    image: nginx
    ports:
      - "80"   # Docker assigns the host port dynamically
```

```bash
$ docker compose port web 80
# Output: 0.0.0.0:55432
```

When you scale a service, each replica gets its own dynamic port. Use `--index` to query a specific replica:

```bash
$ docker compose up -d --scale web=3

$ docker compose port --index=1 web 80   # Output: 0.0.0.0:55001
$ docker compose port --index=2 web 80   # Output: 0.0.0.0:55002
$ docker compose port --index=3 web 80   # Output: 0.0.0.0:55003
```

By default, `docker compose port` looks for TCP mappings. If a service exposes both TCP and UDP on the same port, use `--protocol`:

```bash
$ docker compose port --protocol=udp myservice 53
```

### Verify network membership

To check which containers are attached to a network (useful when troubleshooting connectivity across external or custom networks):

```bash
$ docker network inspect <network-name>
```

### Check connectivity

If the network membership looks correct but services still can't reach each other, test connectivity from inside a running container using `docker compose exec`.

## Further reference information

For full details of the network configuration options available, see the following references:

- [Top-level `networks` element](../../reference/compose-file/networks.md)
- [Service-level `networks` attribute](../../reference/compose-file/services.md#networks)


---

# Package and deploy Docker Compose applications as OCI artifacts

*Sección: Compose*

{{< summary-bar feature_name="Compose OCI artifact" >}}

Docker Compose supports working with [OCI artifacts](../../docker-hub/repos/manage/hub-images/oci-artifacts.md), allowing you to package and distribute your Compose applications through container registries. This means you can store your Compose files alongside your container images, making it easier to version, share, and deploy your multi-container applications.

## Publish your Compose application as an OCI artifact

To distribute your Compose application as an OCI artifact, you can use the `docker compose publish` command, to publish it to an OCI-compliant registry. 
This allows others to then deploy your application directly from the registry.

The publish function supports most of the composition capabilities of Compose, like overrides, extends or include, [with some limitations](#limitations).

### General steps

1. Navigate to your Compose application's directory.  
   Ensure you're in the directory containing your `compose.yml` file or that you are specifying your Compose file with the `-f` flag.

2. In your terminal, sign in to your Docker account so you're authenticated with Docker Hub.

   ```console
   $ docker login
   ```

3. Use the `docker compose publish` command to push your application as an OCI artifact:

   ```console
   $ docker compose publish username/my-compose-app:latest
   ```
   If you have multiple Compose files, run:

   ```console
   $ docker compose -f compose-base.yml -f compose-production.yml publish username/my-compose-app:latest
   ```

### Advanced publishing options

When publishing, you can pass additional options: 
- `--oci-version`: Specify the OCI version (default is automatically determined).
- `--resolve-image-digests`: Pin image tags to digests.
- `--with-env`: Include environment variables in the published OCI artifact.

Compose checks to make sure there isn't any sensitive data in your configuration and displays your environment variables to confirm you want to publish them.

```text
...
you are about to publish sensitive data within your OCI artifact.
please double check that you are not leaking sensitive data
AWS Client ID
"services.serviceA.environment.AWS_ACCESS_KEY_ID": xxxxxxxxxx
AWS Secret Key
"services.serviceA.environment.AWS_SECRET_ACCESS_KEY": aws"xxxx/xxxx+xxxx+"
Github authentication
"GITHUB_TOKEN": ghp_xxxxxxxxxx
JSON Web Token
"": xxxxxxx.xxxxxxxx.xxxxxxxx
Private Key
"": -----BEGIN DSA PRIVATE KEY-----
xxxxx
-----END DSA PRIVATE KEY-----
Are you ok to publish these sensitive data? [y/N]:y

you are about to publish environment variables within your OCI artifact.
please double check that you are not leaking sensitive data
Service/Config  serviceA
FOO=bar
Service/Config  serviceB
FOO=bar
QUIX=
BAR=baz
Are you ok to publish these environment variables? [y/N]: 
```

If you decline, the publish process stops without sending anything to the registry.

## Limitations

There are limitations to publishing Compose applications as OCI artifacts. You can't publish a Compose configuration:
- With service(s) containing bind mounts
- With service(s) containing only a `build` section
- That includes local files with the `include` attribute. To publish successfully, ensure that any included local files are also published. You can then use  `include` to reference these files as remote `include` is supported.

## Start an OCI artifact application

To start a Docker Compose application that uses an OCI artifact, you can use the `-f` (or `--file`) flag followed by the OCI artifact reference. This allows you to specify a Compose file stored as an OCI artifact in a registry.

The `oci://` prefix indicates that the Compose file should be pulled from an OCI-compliant registry rather than loaded from the local filesystem.

```console
$ docker compose -f oci://docker.io/username/my-compose-app:latest up
```

To then run the Compose application, use the `docker compose up` command with the `-f` flag pointing to your OCI artifact:

```console
$ docker compose -f oci://docker.io/username/my-compose-app:latest up
```

### Troubleshooting

When you run an application from an OCI artifact, Compose may display warning messages that require you to confirm the following so as to limit the risk of running a malicious application:

- A list of the interpolation variables used along with their values
- A list of all environment variables used by the application
- If your OCI artifact application is using another remote resources, for example via [`include`](/reference/compose-file/include/).

```text 
$ REGISTRY=myregistry.com docker compose -f oci://docker.io/username/my-compose-app:latest up

Found the following variables in configuration:
VARIABLE     VALUE                SOURCE        REQUIRED    DEFAULT
REGISTRY     myregistry.com      command-line   yes         
TAG          v1.0                environment    no          latest
DOCKERFILE   Dockerfile          default        no          Dockerfile
API_KEY      <unset>             none           no          

Do you want to proceed with these variables? [Y/n]:y

Warning: This Compose project includes files from remote sources:
- oci://registry.example.com/stack:latest
Remote includes could potentially be malicious. Make sure you trust the source.
Do you want to continue? [y/N]: 
```

If you agree to start the application, Compose displays the directory where all the resources from the OCI artifact have been downloaded:

```text
...
Do you want to continue? [y/N]: y

Your compose stack "oci://registry.example.com/stack:latest" is stored in "~/Library/Caches/docker-compose/964e715660d6f6c3b384e05e7338613795f7dcd3613890cfa57e3540353b9d6d"
```

The `docker compose publish` command supports non-interactive execution, letting you skip the confirmation prompt by including the `-y` (or `--yes`) flag: 

```console
$ docker compose publish -y username/my-compose-app:latest
```

## Next steps

- [Familiarize yourself with Compose's trust model](../trust-model.md)
- [Learn about OCI artifacts in Docker Hub](../../docker-hub/repos/manage/hub-images/oci-artifacts.md)
- [Compose publish command](/reference/cli/docker/compose/publish/)
- [Understand `include`](../../reference/compose-file/include.md)


---

# Use Compose in production

*Sección: Compose*

When you define your app with Compose in development, you can use this
definition to run your application in different environments such as CI,
staging, and production.

The easiest way to deploy an application is to run it on a single server,
similar to how you would run your development environment. If you want to scale
up your application, you can run Compose apps on a Swarm cluster.

### Modify your Compose file for production

You may need to make changes to your app configuration to make it ready for
production. These changes might include:

- Removing any volume bindings for application code, so that code stays inside
  the container and can't be changed from outside
- Binding to different ports on the host
- Setting environment variables differently, such as reducing the verbosity of
  logging, or to specify settings for external services such as an email server
- Specifying a restart policy like [`restart: always`](../../reference/compose-file/services.md#restart)to avoid downtime
- Adding extra services such as a log aggregator

For this reason, consider defining an additional Compose file, for example
`compose.production.yaml`, with production-specific
configuration details. This configuration file only needs to include the changes you want to make from the original Compose file. The additional Compose file
is then applied over the original `compose.yaml` to create a new configuration.

Once you have a second configuration file, you can use it with the
`-f` option:

```console
$ docker compose -f compose.yaml -f compose.production.yaml up -d
```

See [Using multiple compose files](multiple-compose-files/index.md) for a more complete example, and other options.

### Deploying changes

When you make changes to your app code, remember to rebuild your image and
recreate your app's containers. To redeploy a service called
`web`, use:

```console
$ docker compose build web
$ docker compose up --no-deps -d web
```

This first command rebuilds the image for `web` and then stops, destroys, and recreates
just the `web` service. The `--no-deps` flag prevents Compose from also
recreating any services that `web` depends on.

### Running Compose on a single server

You can use Compose to deploy an app to a remote Docker host by setting the
`DOCKER_HOST`, `DOCKER_TLS_VERIFY`, and `DOCKER_CERT_PATH` environment variables
appropriately. For more information, see [pre-defined environment variables](environment-variables/envvars.md).

Once you've set up your environment variables, all the normal `docker compose`
commands work with no further configuration.

## Next steps

- [Familiarize yourself with Compose's trust model](../trust-model.md)
- [Using multiple Compose files](multiple-compose-files/index.md)


---

# Using profiles with Compose

*Sección: Compose*

{{% include "compose/profiles.md" %}}

## Assigning profiles to services

Services are associated with profiles through the
[`profiles` attribute](../../reference/compose-file/services.md#profiles) which takes an
array of profile names:

```yaml
services:
  frontend:
    image: frontend
    profiles: [frontend]

  phpmyadmin:
    image: phpmyadmin
    depends_on: [db]
    profiles: [debug]

  backend:
    image: backend

  db:
    image: mysql
```

Here the services `frontend` and `phpmyadmin` are assigned to the profiles
`frontend` and `debug` respectively and as such are only started when their
respective profiles are enabled.

Services without a `profiles` attribute are always enabled. In this
case running `docker compose up` would only start `backend` and `db`.

Valid profiles names follow the regex format of `[a-zA-Z0-9][a-zA-Z0-9_.-]+`.

> [!TIP]
>
> The core services of your application shouldn't be assigned `profiles` so
> they are always enabled and automatically started.

## Start specific profiles

To start a specific profile supply the `--profile` [command-line option](/reference/cli/docker/compose/) or
use the [`COMPOSE_PROFILES` environment variable](environment-variables/envvars.md#compose_profiles):

```console
$ docker compose --profile debug up
```
```console
$ COMPOSE_PROFILES=debug docker compose up
```

Both commands start the services with the `debug` profile enabled.
In the previous `compose.yaml` file, this starts the services
`db`, `backend` and `phpmyadmin`.

### Start multiple profiles

You can also enable
multiple profiles, e.g. with `docker compose --profile frontend --profile debug up`
the profiles `frontend` and `debug` will be enabled.

Multiple profiles can be specified by passing multiple `--profile` flags or
a comma-separated list for the `COMPOSE_PROFILES` environment variable:

```console
$ docker compose --profile frontend --profile debug up
```

```console
$ COMPOSE_PROFILES=frontend,debug docker compose up
```

If you want to enable all profiles at the same time, you can run `docker compose --profile "*"`.

## Auto-starting profiles and dependency resolution

When you explicitly target a service on the command line that has one or more profiles assigned, you do not need to enable the profile manually as Compose runs that service regardless of whether its profile is activated. This is useful for running one-off services or debugging tools.

Only the targeted service (and any of its declared dependencies via `depends_on`) is started. Other services that share the same profile will not be started unless:
- They are also explicitly targeted, or
- The profile is explicitly enabled using `--profile` or `COMPOSE_PROFILES`.

When a service with assigned `profiles` is explicitly targeted on the command
line its profiles are started automatically so you don't need to start them
manually. This can be used for one-off services and debugging tools.
As an example consider the following configuration:

```yaml
services:
  backend:
    image: backend

  db:
    image: mysql

  db-migrations:
    image: backend
    command: myapp migrate
    depends_on:
      - db
    profiles:
      - tools
```

```sh
# Only start backend and db (no profiles involved)
$ docker compose up -d

# Run the db-migrations service without manually enabling the 'tools' profile
$ docker compose run db-migrations
```

In this example, `db-migrations` runs even though it is assigned to the tools profile, because it was explicitly targeted. The `db` service is also started automatically because it is listed in `depends_on`.

If the targeted service has dependencies that are also gated behind a profile, you must ensure those dependencies are either: 
 - In the same profile
 - Started separately
 - Not assigned to any profile so are always enabled

## Stop application and services with specific profiles

As with starting specific profiles, you can use the `--profile` [command-line option](/reference/cli/docker/compose/#use--p-to-specify-a-project-name) or
use the [`COMPOSE_PROFILES` environment variable](environment-variables/envvars.md#compose_profiles):

```console
$ docker compose --profile debug down
```
```console
$ COMPOSE_PROFILES=debug docker compose down
```

Both commands stop and remove services with the `debug` profile and services without a profile. In the following `compose.yaml` file, this stops the services `db`, `backend` and `phpmyadmin`.

```yaml
services:
  frontend:
    image: frontend
    profiles: [frontend]

  phpmyadmin:
    image: phpmyadmin
    depends_on: [db]
    profiles: [debug]

  backend:
    image: backend

  db:
    image: mysql
```

if you only want to stop the `phpmyadmin` service, you can run 

```console 
$ docker compose down phpmyadmin
``` 
or 
```console 
$ docker compose stop phpmyadmin
```

> [!NOTE]
>
> Running `docker compose down` only stops `backend` and `db`.

## Reference information

[`profiles`](../../reference/compose-file/services.md#profiles)


---

# Specify a project name

*Sección: Compose*

By default, Compose assigns the project name based on the name of the directory that contains the Compose file. You can override this with several methods.

This page offers examples of scenarios where custom project names can be helpful, outlines the various methods to set a project name, and provides the order of precedence for each approach.

> [!NOTE]
>
> The default project directory is the base directory of the Compose file. A custom value can also be set
> for it using the [`--project-directory` command line option](/reference/cli/docker/compose/#options).

## Example use cases

Compose uses a project name to isolate environments from each other. There are multiple contexts where a project name is useful:

- On a development host: Create multiple copies of a single environment, useful for running stable copies for each feature branch of a project.
- On a CI server: Prevent interference between builds by setting the project name to a unique build number.
- On a shared or development host: Avoid interference between different projects that might share the same service names.

## Set a project name

Project names must contain only lowercase letters, decimal digits, dashes, and
underscores, and must begin with a lowercase letter or decimal digit. If the
base name of the project directory or current directory violates this
constraint, alternative mechanisms are available.

The precedence order for each method, from highest to lowest, is as follows:

1. The `-p` command line flag. 
2. The [COMPOSE_PROJECT_NAME environment variable](environment-variables/envvars.md).
3. The [top-level `name:` attribute](../../reference/compose-file/version-and-name.md) in your Compose file. Or the last `name:` if you [specify multiple Compose files](multiple-compose-files/merge.md) in the command line with the `-f` flag.
4. The base name of the project directory containing your Compose file. Or the base name of the first Compose file if you [specify multiple Compose files](multiple-compose-files/merge.md) in the command line with the `-f` flag. 
5. The base name of the current directory if no Compose file is specified.

## What's next?

- Read up on [working with multiple Compose files](multiple-compose-files/index.md).
- Explore some [sample apps](https://github.com/docker/awesome-compose).


---

# Use provider services

*Sección: Compose*

{{< summary-bar feature_name="Compose provider services" >}}

Docker Compose supports provider services, which allow integration with services whose lifecycles are managed by third-party components rather than by Compose itself.  
This feature enables you to define and utilize platform-specific services without the need for manual setup or direct lifecycle management.

## What are provider services?

Provider services are a special type of service in Compose that represents platform capabilities rather than containers.
They allow you to declare dependencies on specific platform features that your application needs.

When you define a provider service in your Compose file, Compose works with the platform to provision and configure
the requested capability, making it available to your application services.

## Using provider services

To use a provider service in your Compose file, you need to:

1. Define a service with the `provider` attribute
2. Specify the `type` of provider you want to use
3. Configure any provider-specific options
4. Declare dependencies from your application services to the provider service

Here's a basic example:

```yaml
services:
  database:
    provider:
      type: awesomecloud
      options:
        type: mysql
        foo: bar  
  app:
    image: myapp 
    depends_on:
       - database
```

Notice the dedicated `provider` attribute in the `database` service.
This attribute specifies that the service is managed by a provider and lets you define options specific to that provider type.

The `depends_on` attribute in the `app` service specifies that it depends on the `database` service.
This means that the `database` service will be started before the `app` service, allowing the provider information
to be injected into the `app` service.

## How it works

During the `docker compose up` command execution, Compose identifies services relying on providers and works with them to provision
the requested capabilities. The provider then populates Compose model with information about how to access the provisioned resource.

This information is passed to services that declare a dependency on the provider service, typically through environment
variables. The naming convention for these variables is:

```env
<<PROVIDER_SERVICE_NAME>>_<<VARIABLE_NAME>>
```

For example, if your provider service is named `database`, your application service might receive environment variables like:

- `DATABASE_URL` with the URL to access the provisioned resource
- `DATABASE_TOKEN` with an authentication token
- Other provider-specific variables

Your application can then use these environment variables to interact with the provisioned resource.

## Provider types

The `type` field in a provider service references the name of either:

1. A Docker CLI plugin (e.g., `docker-model`)
2. A binary available in the user's PATH
3. A path to the binary or script to execute

When Compose encounters a provider service, it looks for a plugin or binary with the specified name to handle the provisioning of the requested capability.

For example, if you specify `type: model`, Compose will look for a Docker CLI plugin named `docker-model` or a binary named `model` in the PATH.

```yaml
services:
  ai-runner:
    provider:
      type: model  # Looks for docker-model plugin or model binary
      options:
        model: ai/example-model
```

The plugin or binary is responsible for:

1. Interpreting the options provided in the provider service
2. Provisioning the requested capability
3. Returning information about how to access the provisioned resource

This information is then passed to dependent services as environment variables.

> [!TIP]
>
> If you're working with AI models in Compose, use the [`models` top-level element](../../ai/compose/models-and-compose.md) instead.

## Benefits of using provider services

Using provider services in your Compose applications offers several benefits:

1. Simplified configuration: You don't need to manually configure and manage platform capabilities
2. Declarative approach: You can declare all your application's dependencies in one place
3. Consistent workflow: You use the same Compose commands to manage your entire application, including platform capabilities

## Creating your own provider

If you want to create your own provider to extend Compose with custom capabilities, you can implement a Compose plugin that registers provider types.

For detailed information on how to create and implement your own provider, refer to the [Compose Extensions documentation](https://github.com/docker/compose/blob/main/docs/extension.md).   
This guide explains the extension mechanism that allows you to add new provider types to Compose.

## Reference

- [Docker Model Runner documentation](/manuals/ai/model-runner.md)
- [Compose Extensions documentation](https://github.com/docker/compose/blob/main/docs/extension.md)


---

# Control startup and shutdown order in Compose

*Sección: Compose*

You can control the order of service startup and shutdown with the
[depends_on](../../reference/compose-file/services.md#depends_on) attribute. Compose always starts and stops
containers in dependency order, where dependencies are determined by
`depends_on`, `links`, `volumes_from`, and `network_mode: "service:..."`.

For example, if your application needs to access a database and both services are started with `docker compose up`, there is a chance this will fail since the application service might start before the database service and won't find a database able to handle its SQL statements. 

## Control startup

On startup, Compose does not wait until a container is "ready", only until it's running. This can cause issues if, for example, you have a relational database system that needs to start its own services before being able to handle incoming connections.

The solution for detecting the ready state of a service is  to use the `condition` attribute with one of the following options:

- `service_started`
- `service_healthy`. This specifies that a dependency is expected to be “healthy”, which is defined with `healthcheck`, before starting a dependent service.
- `service_completed_successfully`. This specifies that a dependency is expected to run to successful completion before starting a dependent service.

## Example

```yaml
services:
  web:
    build: .
    depends_on:
      db:
        condition: service_healthy
        restart: true
      redis:
        condition: service_started
  redis:
    image: redis
  db:
    image: postgres:18
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 10s
```

Compose creates services in dependency order. `db` and `redis` are created before `web`. 

Compose waits for healthchecks to pass on dependencies marked with `service_healthy`. `db` is expected to be "healthy" (as indicated by `healthcheck`) before `web` is created.

`restart: true` ensures that if `db` is updated or restarted due to an explicit Compose operation, for example `docker compose restart`, the `web` service is also restarted automatically, ensuring it re-establishes connections or dependencies correctly.

The healthcheck for the `db` service uses the `pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}` command to check if the PostgreSQL database is ready. The service is retried every 10 seconds, up to 5 times.

Compose also removes services in dependency order. `web` is removed before `db` and `redis`.

## Reference information 

- [`depends_on`](../../reference/compose-file/services.md#depends_on)
- [`healthcheck`](../../reference/compose-file/services.md#healthcheck)


---

# Manage secrets securely in Docker Compose

*Sección: Compose*

A secret is any piece of data, such as a password, certificate, or API key, that shouldn’t be transmitted over a network or stored unencrypted in a Dockerfile or in your application’s source code.

{{% include "compose/secrets.md" %}}

Environment variables are often available to all processes, and it can be difficult to track access. They can also be printed in logs when debugging errors without your knowledge. Using secrets mitigates these risks.

## Use secrets

Secrets are mounted as a file in `/run/secrets/<secret_name>` inside the container.

> [!NOTE]
>
> Secrets are supported on Linux containers only. Compose delivers each secret by bind-mounting a single file into the container, and Windows containers support bind-mounting directories only.

Getting a secret into a container is a two-step process. First, define the secret using the [top-level secrets element in your Compose file](../../reference/compose-file/secrets.md). Next, update your service definitions to reference the secrets they require with the [secrets attribute](../../reference/compose-file/services.md#secrets). Compose grants access to secrets on a per-service basis.

Unlike the other methods, this permits granular access control within a service container via standard filesystem permissions.

## Examples

### Single-service secret injection

In the following example, the frontend service is given access to the `my_secret` secret. In the container, `/run/secrets/my_secret` is set to the contents of the file `./my_secret.txt`.

```yaml
services:
  myapp:
    image: myapp:latest
    secrets:
      - my_secret
secrets:
  my_secret:
    file: ./my_secret.txt
```

### Multi-service secret sharing and password management

```yaml
services:
   db:
     image: mysql:latest
     volumes:
       - db_data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_root_password
       - db_password

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_password


secrets:
   db_password:
     file: db_password.txt
   db_root_password:
     file: db_root_password.txt

volumes:
    db_data:
```
In the advanced example above:

- The `secrets` attribute under each service defines the secrets you want to inject into the specific container.
- The top-level `secrets` section defines the variables `db_password` and `db_root_password` and provides the `file` that populates their values.
- The deployment of each container means Docker creates a bind mount under `/run/secrets/<secret_name>` with their specific values.

> [!NOTE]
>
> The `_FILE` environment variables demonstrated here are a convention used by some images, including Docker Official Images like [mysql](https://hub.docker.com/_/mysql) and [postgres](https://hub.docker.com/_/postgres).

### Build secrets

In the following example, the `npm_token` secret is made available at build time. Its value is taken from the `NPM_TOKEN` environment variable.

```yaml
services:
  myapp:
    build:
      secrets:
        - npm_token
      context: .

secrets:
  npm_token:
    environment: NPM_TOKEN
```

## Resources

- [Familiarize yourself with Compose's trust model](../trust-model.md)
- [Secrets top-level element](../../reference/compose-file/secrets.md)
- [Secrets attribute for services top-level element](../../reference/compose-file/services.md#secrets)
- [Build secrets](https://docs.docker.com/build/building/secrets/)


---

# Overview of installing Docker Compose

*Sección: Compose*

This page summarizes the different ways you can install Docker Compose, depending on your platform and needs.

## Installation scenarios 

### Docker Desktop (Recommended)

The easiest and recommended way to get Docker Compose is to install Docker Desktop. 

Docker Desktop includes Docker Compose along with Docker Engine and Docker CLI which are Compose prerequisites. 

Docker Desktop is available for:
- [Linux](../../desktop/setup/install/linux/index.md)
- [Mac](../../desktop/setup/install/mac-install.md)
- [Windows](../../desktop/setup/install/windows-install.md)

> [!TIP]
> 
> If you have already installed Docker Desktop, you can check which version of Compose you have by selecting **About Docker Desktop** from the Docker menu {{< inline-image src="../../desktop/images/whale-x.svg" alt="whale menu" >}}.

### Plugin (Linux only)

> [!IMPORTANT]
>
> This method is only available on Linux.

If you already have Docker Engine and Docker CLI installed, you can install the Docker Compose plugin from the command line, by either:
- [Using Docker's repository](linux.md#install-using-the-repository)
- [Downloading and installing manually](linux.md#install-the-plugin-manually)

### Standalone (Legacy)

> [!WARNING]
>
> This install scenario is not recommended and is only supported for backward compatibility purposes.

You can [install the Docker Compose standalone](standalone.md) on Linux or on Windows Server.


---

# Install the Docker Compose plugin

*Sección: Compose*

This page contains instructions on how to install the Docker Compose plugin on Linux from the command line.

To install the Docker Compose plugin on Linux, you can either:
- [Set up Docker's repository on your Linux system](#install-using-the-repository).
- [Install manually](#install-the-plugin-manually).

> [!NOTE]
>
> These instructions assume you already have Docker Engine and Docker CLI installed and now want to install the Docker Compose plugin. 

## Install using the repository

1. Set up the repository. Find distribution-specific instructions in:

    [Ubuntu](../../engine/install/ubuntu.md#install-using-the-repository) |
    [CentOS](../../engine/install/centos.md#set-up-the-repository) |
    [Debian](../../engine/install/debian.md#install-using-the-repository) |
    [Raspberry Pi OS](../../engine/install/raspberry-pi-os.md#install-using-the-repository) |
    [Fedora](../../engine/install/fedora.md#set-up-the-repository) |
    [RHEL](../../engine/install/rhel.md#set-up-the-repository).

2. Update the package index, and install the latest version of Docker Compose:

    * For Ubuntu and Debian, run:

        ```console
        $ sudo apt-get update
        $ sudo apt-get install docker-compose-plugin
        ```
    * For RPM-based distributions, run:

        ```console
        $ sudo yum update
        $ sudo yum install docker-compose-plugin
        ```

3.  Verify that Docker Compose is installed correctly by checking the version.

    ```console
    $ docker compose version
    ```

### Update Docker Compose

To update the Docker Compose plugin, run the following commands:

* For Ubuntu and Debian, run:

    ```console
    $ sudo apt-get update
    $ sudo apt-get install docker-compose-plugin
    ```
* For RPM-based distributions, run:

    ```console
    $ sudo yum update
    $ sudo yum install docker-compose-plugin
    ```

## Install the plugin manually

> [!WARNING]
>
> Manual installations don’t auto-update. For ease of maintenance, use the Docker repository method.

1.  To download and install the Docker Compose CLI plugin, run:

    ```console
    $ DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}
    $ mkdir -p $DOCKER_CONFIG/cli-plugins
    $ curl -SL https://github.com/docker/compose/releases/download/{{% param "compose_version" %}}/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose
    ```

    This command downloads and installs the latest release of Docker Compose for the active user under `$HOME` directory.

    To install:
    - Docker Compose for _all users_ on your system, replace `~/.docker/cli-plugins` with `/usr/local/lib/docker/cli-plugins`.
    - A different version of Compose, substitute `{{% param "compose_version" %}}` with the version of Compose you want to use.
    - For a different architecture, substitute `x86_64` with the [architecture you want](https://github.com/docker/compose/releases).   


2. Apply executable permissions to the binary:

    ```console
    $ chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
    ```
    or, if you chose to install Compose for all users:

    ```console
    $ sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
    ```

3. Test the installation.

    ```console
    $ docker compose version
    ```

## What's next?

- [Understand how Compose works](../intro/compose-application-model.md)
- [Try the Quickstart guide](../gettingstarted.md)


---

# Install the Docker Compose standalone (Legacy)

*Sección: Compose*

> [!WARNING]
>
> This install scenario is not recommended and is only supported for backward compatibility purposes.
> Use [Docker Desktop](../../desktop/index.md) or the
> [Docker Compose plugin](linux.md) instead.
> Use the standalone binary only if you cannot use either of these options.

This page contains instructions on how to install Docker Compose standalone on Linux or Windows Server, from the command line.

> [!WARNING]
>
> The Docker Compose standalone uses the `-compose` syntax instead of the current standard syntax `compose`.  
> For example, you must type `docker-compose up` when using Docker Compose standalone, instead of `docker compose up`.
> Use it only for backward compatibility.

## On Linux

1. To download and install the Docker Compose standalone, run:

   ```console
   $ curl -SL https://github.com/docker/compose/releases/download/{{% param "compose_version" %}}/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
   ```

2. Apply executable permissions to the standalone binary in the target path for the installation.

   ```console
   $ chmod +x /usr/local/bin/docker-compose
   ```

3. Test and execute Docker Compose commands using `docker-compose`.

> [!TIP]
>
> If the command `docker-compose` fails after installation, check your path.
> You can also create a symbolic link to `/usr/bin` or any other directory in your path.
> For example:
>
> ```console
> $ sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
> ```

## On Windows Server

Follow these instructions if you are [running the Docker daemon directly
on Microsoft Windows Server](../../engine/install/binaries.md#install-server-and-client-binaries-on-windows) and want to install Docker Compose.

1.  Run PowerShell as an administrator.
    In order to proceed with the installation, select **Yes** when asked if you want this app to make changes to your device.

2.  Optional. Ensure TLS1.2 is enabled.
    GitHub requires TLS1.2 for secure connections. If you’re using an older version of Windows Server, for example 2016, or suspect that TLS1.2 is not enabled, run the following command in PowerShell:

    ```powershell
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    ```

3.  Download the latest release of Docker Compose ({{% param "compose_version" %}}). Run the following command:

    ```powershell
     Start-BitsTransfer -Source "https://github.com/docker/compose/releases/download/{{% param "compose_version" %}}/docker-compose-windows-x86_64.exe" -Destination $Env:ProgramFiles\Docker\docker-compose.exe
    ```

    To install a different version of Docker Compose, substitute `{{% param "compose_version" %}}` with the version of Compose you want to use.

    > [!NOTE]
    >
    > On Windows Server 2019 you can add the Compose executable to `$Env:ProgramFiles\Docker`.
    > Because this directory is registered in the system `PATH`, you can run the `docker-compose --version`
    > command on the subsequent step with no additional configuration.

4.  Test the installation.

    ```console
    $ docker-compose.exe version
    Docker Compose version {{% param "compose_version" %}}
    ```

## What's next?

- [Understand how Compose works](../intro/compose-application-model.md)
- [Try the Quickstart guide](../gettingstarted.md)


---

# Uninstall Docker Compose

*Sección: Compose*

How you uninstall Docker Compose depends on how it was installed. This guide covers uninstallation instructions for:

- Docker Compose installed via Docker Desktop
- Docker Compose installed as a CLI plugin

## Uninstalling Docker Compose with Docker Desktop

If you want to uninstall Docker Compose and you have installed Docker Desktop, see [Uninstall Docker Desktop](../../desktop/uninstall.md).

> [!WARNING]
>
> Unless you have other Docker instances installed on that specific environment, uninstalling Docker Desktop removes all Docker components, including Docker Engine, Docker CLI, and Docker Compose.

## Uninstalling the Docker Compose CLI plugin

If you installed Docker Compose via a package manager, run:

On Ubuntu or Debian:

   ```console
   $ sudo apt-get remove docker-compose-plugin
   ```
On RPM-based distributions:

   ```console
   $ sudo yum remove docker-compose-plugin
   ```

### Manually installed

If you installed Docker Compose manually (using curl), remove it by deleting the binary:

   ```console
   $ rm $DOCKER_CONFIG/cli-plugins/docker-compose
   ```

### Remove for all users

If installed for all users, remove it from the system directory:

   ```console
   $ rm /usr/local/lib/docker/cli-plugins/docker-compose
   ```

> [!NOTE]
>
> If you get a **Permission denied** error using either of the previous
> methods, you do not have the permissions needed to remove
> Docker Compose. To force the removal, prepend `sudo` to either of the previous instructions and run it again.

### Inspect the location of the Compose CLI plugin

To check where Compose is installed, use:

```console
$ docker info --format '{{range .ClientInfo.Plugins}}{{if eq .Name "compose"}}{{.Path}}{{end}}{{end}}'
```


---

# Introduction to Compose

*Sección: Compose*




---

# How Compose works

*Sección: Compose*

With Docker Compose you use a YAML configuration file, known as the [Compose file](#the-compose-file), to configure your application’s services, and then you create and start all the services from your configuration with the [Compose CLI](#cli). 

The Compose file, or `compose.yaml` file, follows the rules provided by the [Compose Specification](../../reference/compose-file/index.md) in how to define multi-container applications. This is the Docker Compose implementation of the formal [Compose Specification](https://github.com/compose-spec/compose-spec). 

{{< accordion title="The Compose application model" >}}

Computing components of an application are defined as [services](../../reference/compose-file/services.md). A service is an abstract concept implemented on platforms by running the same container image, and configuration, one or more times.

Services communicate with each other through [networks](../../reference/compose-file/networks.md). In the Compose Specification, a network is a platform capability abstraction to establish an IP route between containers within services connected together.

Services store and share persistent data into [volumes](../../reference/compose-file/volumes.md). The Specification describes such a persistent data as a high-level filesystem mount with global options.

Some services require configuration data that is dependent on the runtime or platform. For this, the Specification defines a dedicated [configs](../../reference/compose-file/configs.md) concept. From inside the container, configs behave like volumes—they’re mounted as files. However, configs are defined differently at the platform level.

A [secret](../../reference/compose-file/secrets.md) is a specific flavor of configuration data for sensitive data that should not be exposed without security considerations. Secrets are made available to services as files mounted into their containers, but the platform-specific resources to provide sensitive data are specific enough to deserve a distinct concept and definition within the Compose Specification.

> [!NOTE]
>
> With volumes, configs and secrets you can have a simple declaration at the top-level and then add more platform-specific information at the service level.

A project is an individual deployment of an application specification on a platform. A project's name, set with the top-level [`name`](../../reference/compose-file/version-and-name.md) attribute, is used to group
resources together and isolate them from other applications or other installation of the same Compose-specified application with distinct parameters. If you are creating resources on a platform, you must prefix resource names by project and
set the label `com.docker.compose.project`.

Compose offers a way for you to set a custom project name and override this name, so that the same `compose.yaml` file can be deployed twice on the same infrastructure, without changes, by just passing a distinct name.

{{< /accordion >}} 

## The Compose file

The default path for a Compose file is `compose.yaml` (preferred) or `compose.yml` that is placed in the working directory.
Compose also supports `docker-compose.yaml` and `docker-compose.yml` for backwards compatibility of earlier versions.
If both files exist, Compose prefers the canonical `compose.yaml`.

You can use [fragments](../../reference/compose-file/fragments.md) and [extensions](../../reference/compose-file/extension.md) to keep your Compose file efficient and easy to maintain.

Multiple Compose files can be [merged](../../reference/compose-file/merge.md) together to define the application model. The combination of YAML files is implemented by appending or overriding YAML elements based on the Compose file order you set. 
Simple attributes and maps get overridden by the highest order Compose file, lists get merged by appending. Relative
paths are resolved based on the first Compose file's parent folder, whenever complementary files being
merged are hosted in other folders. As some Compose file elements can both be expressed as single strings or complex objects, merges apply to
the expanded form. For more information, see [Working with multiple Compose files](../how-tos/multiple-compose-files/index.md).

If you want to reuse other Compose files, or factor out parts of your application model into separate Compose files, you can also use [`include`](../../reference/compose-file/include.md). This is useful if your Compose application is dependent on another application which is managed by a different team, or needs to be shared with others.

## CLI

The Docker CLI lets you interact with your Docker Compose applications through the `docker compose` command and its subcommands. If you're using Docker Desktop, the Docker Compose CLI is included by default.

Using the CLI, you can manage the lifecycle of your multi-container applications defined in the `compose.yaml` file. The CLI commands enable you to start, stop, and configure your applications effortlessly.

### Key commands 

To start all the services defined in your `compose.yaml` file:

```console
$ docker compose up
```

To stop and remove the running services:

```console
$ docker compose down 
```

If you want to monitor the output of your running containers and debug issues, you can view the logs with: 

```console
$ docker compose logs
```

To list all the services along with their current status:

```console
$ docker compose ps
```

For a full list of all the Compose CLI commands, see the [reference documentation](/reference/cli/docker/compose/).

## Illustrative example

The following example illustrates the Compose concepts outlined above. The example is non-normative.

Consider an application split into a frontend web application and a backend service.

The frontend is configured at runtime with an HTTP configuration file managed by infrastructure, providing an external domain name, and an HTTPS server certificate injected by the platform's secured secret store.

The backend stores data in a persistent volume.

Both services communicate with each other on an isolated back-tier network, while the frontend is also connected to a front-tier network and exposes port 443 for external usage.

![Compose application example](../images/compose-application.webp)

The example application is composed of the following parts:

- Two services, backed by Docker images: `webapp` and `database`
- One secret (HTTPS certificate), injected into the frontend
- One configuration (HTTP), injected into the frontend
- One persistent volume, attached to the backend
- Two networks

```yml
services:
  frontend:
    image: example/webapp
    ports:
      - "443:8043"
    networks:
      - front-tier
      - back-tier
    configs:
      - httpd-config
    secrets:
      - server-certificate

  backend:
    image: example/database
    volumes:
      - db-data:/etc/data
    networks:
      - back-tier

volumes:
  db-data:
    driver: flocker
    driver_opts:
      size: "10GiB"

configs:
  httpd-config:
    external: true

secrets:
  server-certificate:
    external: true

networks:
  # The presence of these objects is sufficient to define them
  front-tier: {}
  back-tier: {}
```

The `docker compose up` command starts the `frontend` and `backend` services, creates the necessary networks and volumes, and injects the configuration and secret into the frontend service.

`docker compose ps` provides a snapshot of the current state of your services, making it easy to see which containers are running, their status, and the ports they are using:

```text
$ docker compose ps

NAME                IMAGE                COMMAND                  SERVICE             CREATED             STATUS              PORTS
example-frontend-1  example/webapp       "nginx -g 'daemon of…"   frontend            2 minutes ago       Up 2 minutes        0.0.0.0:443->8043/tcp
example-backend-1   example/database     "docker-entrypoint.s…"   backend             2 minutes ago       Up 2 minutes
```

## What's next 

- [Try the Quickstart guide](../gettingstarted.md)
- [Explore some sample applications](https://github.com/docker/awesome-compose)
- [Familiarize yourself with the Compose Specification](../../reference/compose-file/index.md)


---

# Why use Compose?

*Sección: Compose*

## Key benefits of Docker Compose

Using Docker Compose offers several benefits that streamline the development, deployment, and management of containerized applications:

- Simplified control: Define and manage multi-container apps in one YAML file, streamlining orchestration and replication.

- Efficient collaboration: Shareable YAML files support smooth collaboration between developers and operations, improving workflows and issue resolution, leading to increased overall efficiency.

- Rapid application development: Compose caches the configuration used to create a container. When you restart a service that has not changed, Compose reuses the existing containers. Reusing containers means that you can make changes to your environment quickly.

- Portability across environments: Compose supports variables in the Compose file. You can use these variables to customize your composition for different environments, or different users.

## Common use cases of Docker Compose

Compose can be used in many different ways. Some common use cases are outlined
below.

### Development environments

When you're developing software, the ability to run an application in an
isolated environment and interact with it is crucial. The Compose command
line tool can be used to create the environment and interact with it.

The [Compose file](../../reference/compose-file/index.md) provides a way to document and configure
all of the application's service dependencies (databases, queues, caches,
web service APIs, etc). Using the Compose command line tool you can create
and start one or more containers for each dependency with a single command
(`docker compose up`).

Together, these features provide a convenient way for you to get
started on a project. Compose can reduce a multi-page "developer getting
started guide" to a single machine-readable Compose file and a few commands.

### Automated testing environments

An important part of any Continuous Deployment or Continuous Integration process
is the automated test suite. Automated end-to-end testing requires an
environment in which to run tests. Compose provides a convenient way to create
and destroy isolated testing environments for your test suite. By defining the full environment in a [Compose file](../../reference/compose-file/index.md), you can create and destroy these environments in just a few commands:

```console
$ docker compose up -d
$ ./run_tests
$ docker compose down
```

### Single host deployments

Compose supports production deployments on single hosts. You can use
Compose to deploy applications to remote Docker hosts and manage
production-specific configurations.

For details on using production-oriented features, see
[Compose in production](../how-tos/production.md).

## What's next?

- [Learn about the history of Compose](history.md)
- [Understand how Compose works](compose-application-model.md)
- [Try the Quickstart guide](../gettingstarted.md)


---

# History and development of Docker Compose

*Sección: Compose*

This page provides:
 - A brief history of the development of the Docker Compose CLI
 - A clear explanation of the major versions and file formats that make up Compose v1, v2, and v5
 - The main differences between Compose v1, v2, and v5

## Introduction

![Image showing the main differences between Compose v1, Compose v2, and Compose v5](../images/v1-versus-v2-versus-v5.png)

The diagram above highlights the key differences between Docker Compose v1, v2, and v5. Today, the supported Docker Compose CLI versions are Compose v2 and Compose v5, both of which are defined by the [Compose Specification](../../reference/compose-file/index.md).

The diagram provides a high-level comparison of file formats, command-line syntax, and supported top-level elements. This is covered in more detail in the following sections.

### Docker Compose CLI versioning

Compose v1 was first released in 2014. It was written in Python and invoked with `docker-compose`.
Typically, Compose v1 projects include a top-level `version` element in the `compose.yaml` file, with values ranging from `2.0` to `3.8`, which refer to the specific [file formats](#compose-file-format-versioning).

Compose v2, announced in 2020, is written in Go and is invoked with `docker compose`.
Unlike v1, Compose v2 ignores the `version` top-level element in the `compose.yaml` file and relies entirely on the Compose Specification to interpret the file.

Compose v5, released in 2025, is functionally identical to Compose v2. Its primary distinction is the introduction of an official [Go SDK](../compose-sdk.md). This SDK provides a comprehensive API that lets you integrate Compose functionality directly into your applications, allowing you to load, validate, and manage multi-container environments without relying on the Compose CLI. To avoid confusion with the legacy Compose file formats labeled “v2” and “v3,” the versioning was advanced directly to v5.

### Compose file format versioning

The Docker Compose CLIs are defined by specific file formats. 

Three major versions of the Compose file format for Compose v1 were released:
- Compose file format 1 with Compose 1.0.0 in 2014
- Compose file format 2.x with Compose 1.6.0 in 2016
- Compose file format 3.x with Compose 1.10.0 in 2017

Compose file format 1 is substantially different to all the following formats as it lacks a top-level `services` key.
Its usage is historical and files written in this format don't run with Compose v2 or v5.

Compose file format 2.x and 3.x are very similar to each other, but the latter introduced many new options targeted at Swarm deployments.

To address confusion around Compose CLI versioning, Compose file format versioning, and feature parity depending on whether Swarm mode was in use, file format 2.x and 3.x were merged into the [Compose Specification](../../reference/compose-file/index.md). 

Compose v2 and v5 uses the Compose Specification for project definition. Unlike the prior file formats, the Compose Specification is rolling and makes the `version` top-level element optional. Compose v2 and v5 also makes use of optional specifications - [Deploy](../../reference/compose-file/deploy.md), [Develop](../../reference/compose-file/develop.md), and [Build](../../reference/compose-file/build.md).

To make migration easier, Compose v2 and v5 has backwards compatibility for certain elements that have been deprecated or changed between Compose file format 2.x/3.x and the Compose Specification.

## What's next?

- [How Compose works](compose-application-model.md)
- [Compose Specification reference](../../reference/compose-file/index.md)


---

# Release notes

*Sección: Compose*

---
title: Release notes
weight: 90
params:
  sidebar:
    goto: "https://github.com/docker/compose/releases"
---


---

# Index

*Sección: Compose*

---
build:
  render: never
title: Support and feedback
weight: 80
---


---

# Frequently asked questions about Docker Compose

*Sección: Compose*

### What is the difference between `docker compose` and `docker-compose`

Version one of the Docker Compose command-line binary was first released in 2014. It was written in Python, and is invoked with `docker-compose`. Typically, Compose v1 projects include a top-level version element in the `compose.yaml` file, with values ranging from 2.0 to 3.8, which refer to the specific file formats.

Version two of the Docker Compose command-line binary was announced in 2020, is written in Go, and is invoked with `docker compose`. Compose v2 ignores the version top-level element in the compose.yaml file.

Compose v5, released in 2025, uses the same `docker compose` command and is functionally identical to Compose v2. Its primary distinction is the introduction of an official [Go SDK](../compose-sdk.md).

For further information, see [History and development of Compose](../intro/history.md).

### What's the difference between `up`, `run`, and `start`?

Typically, you want `docker compose up`. Use `up` to start or restart all the
services defined in a `compose.yaml`. In the default "attached"
mode, you see all the logs from all the containers. In "detached" mode (`-d`),
Compose exits after starting the containers, but the containers continue to run
in the background.

The `docker compose run` command is for running "one-off" or "adhoc" tasks. It
requires the service name you want to run and only starts containers for services
that the running service depends on. Use `run` to run tests or perform
an administrative task such as removing or adding data to a data volume
container. The `run` command acts like `docker run -ti` in that it opens an
interactive terminal to the container and returns an exit status matching the
exit status of the process in the container.

The `docker compose start` command is useful only to restart containers
that were previously created but were stopped. It never creates new
containers.

### Why do my services take 10 seconds to recreate or stop?

The `docker compose stop` command attempts to stop a container by sending a `SIGTERM`. It then waits
for a [default timeout of 10 seconds](/reference/cli/docker/compose/stop/). After the timeout,
a `SIGKILL` is sent to the container to forcefully kill it. If you
are waiting for this timeout, it means that your containers aren't shutting down
when they receive the `SIGTERM` signal.

There has already been a lot written about this problem of
[processes handling signals](https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86)
in containers.

To fix this problem, try the following:

- Make sure you're using the exec form of `CMD` and `ENTRYPOINT`
in your Dockerfile.

  For example use `["program", "arg1", "arg2"]` not `"program arg1 arg2"`.
  Using the string form causes Docker to run your process using `bash` which
  doesn't handle signals properly. Compose always uses the JSON form, so don't
  worry if you override the command or entrypoint in your Compose file.

- If you are able, modify the application that you're running to
add an explicit signal handler for `SIGTERM`.

- Set the `stop_signal` to a signal which the application knows how to handle:

  ```yaml
  services:
    web:
      build: .
      stop_signal: SIGINT
  ```

- If you can't modify the application, wrap the application in a lightweight init
system (like [s6](https://skarnet.org/software/s6/)) or a signal proxy (like
[dumb-init](https://github.com/Yelp/dumb-init) or
[tini](https://github.com/krallin/tini)).  Either of these wrappers takes care of
handling `SIGTERM` properly.

### How do I run multiple copies of a Compose file on the same host?

Compose uses the project name to create unique identifiers for all of a
project's containers and other resources. To run multiple copies of a project,
set a custom project name using the `-p` command line option
or the [`COMPOSE_PROJECT_NAME` environment variable](../how-tos/environment-variables/envvars.md#compose_project_name).

### Can I use JSON instead of YAML for my Compose file?

Yes. [YAML is a superset of JSON](https://stackoverflow.com/a/1729545/444646) so
any JSON file should be valid YAML. To use a JSON file with Compose,
specify the filename to use, for example:

```console
$ docker compose -f compose.json up
```

### Should I include my code with `COPY`/`ADD` or a volume?

You can add your code to the image using `COPY` or `ADD` directive in a
`Dockerfile`.  This is useful if you need to relocate your code along with the
Docker image, for example when you're sending code to another environment
(production, CI, etc).

Use a `volume` if you want to make changes to your code and see them
reflected immediately, for example when you're developing code and your server
supports hot code reloading or live-reload.

There may be cases where you want to use both. You can have the image
include the code using a `COPY`, and use a `volume` in your Compose file to
include the code from the host during development. The volume overrides
the directory contents of the image.


---

# Give feedback

*Sección: Compose*

There are many ways you can provide feedback on Docker Compose.

### Report bugs or problems on GitHub

To report bugs or problems, visit [Docker Compose on GitHub](https://github.com/docker/compose/issues)

### Feedback via Community Slack channels

You can also provide feedback through the `#docker-compose` [Docker Community Slack](https://dockr.ly/comm-slack) channel.


---

# Trust model for Compose files

*Sección: Compose*

Docker Compose treats every Compose file as trusted input. When a Compose file
requests elevated privileges, host filesystem access, or any other
configuration, Compose applies it as written. This is the same behavior as
passing flags directly to `docker run`.

This means that any Compose file you run, whether it lives on your local
filesystem, in a Git repository, or in an OCI registry, has full control over
how containers interact with your host. The security boundary is not where the file comes from but whether you trust the author.

Evaluating trust means asking: Who authored this file? Has it changed since you last reviewed it? Do you understand every privilege it requests?

## The dependency chain

A Compose application can be assembled from multiple sources. The
[`include`](../reference/compose-file/include.md) directive imports entire Compose
files, while [`extends`](../reference/compose-file/services.md#extends) inherits
configuration from a specific service in another file. Both support remote
references and can be chained:

```text
Your command
  └─ compose.yaml                                    (local or remote)
       ├─ services, volumes, networks                (direct config)
       ├─ include:
       │    └─ oci://registry.example.com/base:v2   (remote dependency)
       │         └─ services, volumes, networks      (indirect config)
       └─ services:
            └─ app:
                 └─ extends:
                      └─ file: oci://registry.example.com/templates:v1
                           └─ service: webapp        (inherited config)
```

Each level has the same capabilities. The top-level file you inspect may appear
safe while a nested `include` or `extends` introduces services with elevated
privileges, host bind mounts, or untrusted images. These dependencies can also
change independently. Risky settings can be introduced by a nested dependency that you never
see unless you inspect the fully resolved output.

> [!IMPORTANT]
>
> Compose warns you when a configuration references remote sources. Do not
> accept this without understanding every reference in the chain.

## Best practices

### Inspect the full configuration

To see exactly what Compose applies, including all resolved `includes`,
`extends`, merged overrides, and interpolated variables, use:

```console
$ docker compose config
```

For remote references:

```console
$ docker compose -f oci://registry.example.com/myapp:latest config
```

Review this output before running `up` or `create`, especially when the
configuration comes from a source you have not audited.

#### Fields to look out for

A Compose configuration has broad control over how containers interact with the
host. The following is a non-exhaustive list of fields that carry security
implications when set by an untrusted author:

| Field | Effect |
|-------|--------|
| `privileged` | Grants the container full access to the host |
| `cap_add` | Adds Linux capabilities such as `SYS_ADMIN` or `NET_RAW` |
| `security_opt` | Configures security profiles including seccomp and AppArmor |
| `volumes` / bind mounts | Mounts host directories into the container |
| `network_mode: host` | Shares the host network stack |
| `pid: host` | Shares the host PID namespace |
| `devices` | Exposes host devices to the container |
| `image` | Pulls and runs an arbitrary container image |
| `env_file`, `label_file`, `secrets`/`configs` (`file:`), `include`, `extends` | Read files from the host, directly or through symlinks resolved from a remote checkout, and can surface their contents during configuration loading |
| `provider` | Runs the binary named by `provider.type` on the host, outside any container, when you run `up`, `down`, or `stop` |

When in doubt, look up the effect of any unfamiliar field before running the configuration.

Like `volumes`, the file-reference fields read any file the user running Compose
can access, including through symlinks resolved from a remote checkout, and their
contents can appear in `docker compose config` output before any container starts.
Compose does not confine reads to the project directory. Treat a Compose project as
code you run, not data you inspect.

### CI/CD environments

Automated pipelines are particularly sensitive because they often run with
access to credentials, cloud provider tokens, or Docker sockets.

- Avoid referencing public or unverified Compose configurations in automated
  pipelines.
- Gate updates behind your normal code review process.
- Use read-only Docker socket mounts where possible to limit your risk.

### Pin remote references to digests

Tags are mutable, meaning anyone with push access to a registry can overwrite a tag silently, so a reference you reviewed last week may point to different content today.

Digests are immutable. Instead of referencing by tag, pin to the digest. 

```yaml
include:
  - oci://registry.example.com/base@sha256:a1b2c3d4...
```

Treat any update to a pinned digest as a code change. Make sure you review the new content before updating the reference.

### Other

- Use a private registry: Host OCI artifacts on a registry your
  organization controls. Restrict who can push to it.
- Audit transitive dependencies: Check every remote `include` and `extends`
  reference in the chain, not just the top-level file.
- Review all Compose confirmation prompts: When loading remote Compose files,
  Compose displays confirmation prompts for interpolation variables, environment
  values, and remote includes. Review these before accepting.

## Further reading

- [OCI artifact applications](how-tos/oci-artifact.md)
- [Use Compose in production](how-tos/production.md)
- [`include` reference](../reference/compose-file/include.md)
- [`extends` reference](../reference/compose-file/services.md#extends)
- [Manage secrets in Compose](how-tos/use-secrets.md)


---

# Docker Desktop

*Sección: Desktop*

Docker Desktop is a one-click-install application for your Mac, Linux, or Windows environment
that lets you build, share, and run containerized applications and microservices. 

It provides a straightforward GUI (Graphical User Interface) that lets you manage your containers, applications, and images directly from your machine. 

Docker Desktop reduces the time spent on complex setups so you can focus on writing code. It takes care of port mappings, file system concerns, and other default settings, and is regularly updated with bug fixes and security updates.

Docker Desktop integrates with your preferred development tools and languages, and gives you access to a vast ecosystem of trusted images and templates via Docker Hub. This empowers teams to accelerate development, automate builds, enable CI/CD workflows, and collaborate securely through shared repositories.

## Key features

* Ability to containerize and share any application on any cloud platform, in multiple languages and frameworks.
* Quick installation and setup of a complete Docker development environment.
* Includes the latest version of Kubernetes.
* On Windows, the ability to toggle between Linux and Windows containers to build applications.
* Fast and reliable performance with native Windows Hyper-V virtualization.
* Ability to work natively on Linux through WSL 2 on Windows machines.
* Volume mounting for code and data, including file change notifications and easy access to running containers on the localhost network.

## Products inside Docker Desktop

- [Docker MCP Toolkit and Catalog](../ai/mcp-catalog-and-toolkit/index.md)
- [Docker Model Runner](../ai/model-runner/index.md)
- [Gordon](../ai/gordon/index.md)
- [Docker Offload](../offload/index.md)
- [Docker Engine](../engine/index.md)
- Docker CLI client
- [Docker Build](../build/index.md)
- [Docker Compose](../compose/index.md)
- [Docker Scout](../scout/index.md)
- [Kubernetes](https://github.com/kubernetes/kubernetes/)

## Next steps

{{< grid >}}


---

# Resolve the recent Docker Desktop issue on macOS

*Sección: Desktop*

This guide provides steps to address a recent issue affecting some macOS users of Docker Desktop. The issue may prevent Docker Desktop from starting and in some cases, may also trigger inaccurate malware warnings. For more details about the incident, see the [blog post](https://www.docker.com/blog/incident-update-docker-desktop-for-mac/).

> [!NOTE]
>
> Docker Desktop versions 4.28 and earlier are not impacted by this issue. 

## Available solutions

There are a few options available depending on your situation:

### Upgrade to Docker Desktop version 4.37.2 (recommended)

The recommended way is to upgrade to the latest Docker Desktop version which is version 4.37.2. 

If possible, update directly through the app. If not, and you’re still seeing the malware pop-up, follow the steps below:

1. Kill the Docker process that cannot start properly:
   ```console
   $ sudo launchctl bootout system/com.docker.vmnetd 2>/dev/null || true
   $ sudo launchctl bootout system/com.docker.socket 2>/dev/null || true
    
   $ sudo rm /Library/PrivilegedHelperTools/com.docker.vmnetd || true
   $ sudo rm /Library/PrivilegedHelperTools/com.docker.socket || true
 
   $ ps aux | grep -i docker | awk '{print $2}' | sudo xargs kill -9 2>/dev/null
   ```
    
2. Make sure the malware pop-up is permanently closed. 

3. [Download and install version 4.37.2](release-notes.md#4372).

4. Launch Docker Desktop. A privileged pop-up message displays after 5 to 10 seconds.

5. Enter your password.

You should now see the Docker Desktop Dashboard.

> [!TIP]
>
> If the malware pop-up persists after completing these steps and Docker is in the Trash, try emptying the Trash and rerunning the steps.

### Install a patch if you have version 4.32 - 4.36

If you can’t upgrade to the latest version and you’re seeing the malware pop-up, follow the steps below:

1. Kill the Docker process that cannot start properly:
   ```console
   $ sudo launchctl bootout system/com.docker.vmnetd 2>/dev/null || true
   $ sudo launchctl bootout system/com.docker.socket 2>/dev/null || true
    
   $ sudo rm /Library/PrivilegedHelperTools/com.docker.vmnetd || true
   $ sudo rm /Library/PrivilegedHelperTools/com.docker.socket || true
 
   $ ps aux | grep docker | awk '{print $2}' | sudo xargs kill -9 2>/dev/null
   ```

2. Make sure the malware pop-up is permanently closed.

3. [Download and install the patched installer](release-notes.md) that matches your current base version. For example if you have version 4.36.0, install 4.36.1.

4. Launch Docker Desktop. A privileged pop-up message displays after 5 to 10 seconds.

5. Enter your password.

You should now see the Docker Desktop Dashboard.

> [!TIP]
>
> If the malware pop-up persists after completing these steps and Docker is in the Trash, try emptying the Trash and rerunning the steps.

## MDM script

If you are an IT administrator and your developers are seeing the malware pop-up:

1. Make sure your developers have a re-signed version of Docker Desktop version 4.32 or later.
2. Run the following script:

   ```console
   #!/bin/bash

   # Stop the docker services
   echo "Stopping Docker..."
   sudo pkill -i docker

   # Stop the vmnetd service
   echo "Stopping com.docker.vmnetd service..."
   sudo launchctl bootout system /Library/LaunchDaemons/com.docker.vmnetd.plist

   # Stop the socket service
   echo "Stopping com.docker.socket service..."
   sudo launchctl bootout system /Library/LaunchDaemons/com.docker.socket.plist

   # Remove vmnetd binary
   echo "Removing com.docker.vmnetd binary..."
   sudo rm -f /Library/PrivilegedHelperTools/com.docker.vmnetd

   # Remove socket binary
   echo "Removing com.docker.socket binary..."
   sudo rm -f /Library/PrivilegedHelperTools/com.docker.socket

   # Install new binaries
   echo "Install new binaries..."
   sudo cp /Applications/Docker.app/Contents/Library/LaunchServices/com.docker.vmnetd /Library/PrivilegedHelperTools/
   sudo cp /Applications/Docker.app/Contents/MacOS/com.docker.socket /Library/PrivilegedHelperTools/
   ```

## Homebrew casks

If you installed Docker Desktop using Homebrew casks, the recommended solution is to perform a full reinstall to resolve the issue.

To reinstall Docker Desktop, run the following commands in your terminal:

```console
$ brew update
$ brew reinstall --cask docker
```

These commands will update Homebrew and completely reinstall Docker Desktop, ensuring you have the latest version with the fix applied.


---

# Docker Desktop Enterprise

*Sección: Desktop*

Docker Desktop Enterprise (DDE) has been deprecated and is no longer in active development. Use [Docker Desktop](../../enterprise/enterprise-deployment/index.md) instead.

If you are an existing DDE customer, use the [Support form](https://hub.docker.com/support/desktop/) to request a transition to one of the new [subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopEnterprise).

If you are looking to deploy Docker Desktop at scale, contact us on [pricingquestions@docker.com](mailto:pricingquestions@docker.com).


---

# Index

*Sección: Desktop*

---
build:
  render: never
title: Features and capabilities
weight: 30
---


---

# containerd image store

*Sección: Desktop*

Docker Desktop uses containerd as its image store by default. The image store
is the component responsible for pushing, pulling, and storing images on your
filesystem. The containerd image store supports features like multi-platform
images, image attestations, and alternative snapshotters.

## What is `containerd`?

`containerd` is a container runtime that provides a lightweight, consistent
interface for container lifecycle and image management. It is used under the
hood by Docker Engine for creating, starting, and stopping containers.

## What is the `containerd` image store?

The image store is the component responsible for pushing, pulling,
and storing images on the filesystem.

The containerd image store extends the range of image types
that the Docker Engine can natively interact with.
While this is a low-level architectural change,
it's a prerequisite for unlocking a range of new use cases, including:

- [Build multi-platform images](#build-multi-platform-images) and images with attestations
- Support for using containerd snapshotters with unique characteristics,
  such as [stargz][1] for lazy-pulling images on container startup,
  or [nydus][2] and [dragonfly][3] for peer-to-peer image distribution.
- Ability to run [Wasm](wasm.md) containers

[1]: https://github.com/containerd/stargz-snapshotter
[2]: https://github.com/containerd/nydus-snapshotter
[3]: https://github.com/dragonflyoss/image-service

## Classic image store

The classic image store is Docker's legacy storage backend, replaced by the
containerd image store. It doesn't support image indices or manifest lists, so
you can't load multi-platform images locally or build images with attestations.

Most users have no reason to use the classic image store. It's available for
cases where you need to match older behavior or have compatibility
requirements.

## Switch image stores

The containerd image store is enabled by default in Docker Desktop version 4.34
and later. To switch between image stores:

1. Navigate to **Settings** in Docker Desktop.
2. In the **General** tab, check or clear the **Use containerd for pulling and storing images** option.
3. Select **Apply**.

> [!NOTE]
>
> Docker Desktop maintains separate image stores for the classic and containerd image stores.
> When switching between them, images and containers from the inactive store remain on disk but are hidden until you switch back.

## Build multi-platform images

The containerd image store lets you build multi-platform images
and load them to your local image store:

<script async id="asciicast-ZSUI4Mi2foChLjbevl2dxt5GD" src="https://asciinema.org/a/ZSUI4Mi2foChLjbevl2dxt5GD.js"></script>

Building multi-platform images with the classic image store is not supported:

```console
$ docker build --platform=linux/amd64,linux/arm64 .
[+] Building 0.0s (0/0)
ERROR: Multi-platform build is not supported for the docker driver.
Switch to a different driver, or turn on the containerd image store, and try again.
Learn more at https://docs.docker.com/go/build-multi-platform/
```


---

# Use the Docker Desktop CLI

*Sección: Desktop*

The Docker Desktop CLI lets you perform key operations such as starting, stopping, restarting, and updating Docker Desktop directly from the command line.

The Docker Desktop CLI provides:

- Simplified automation for local development: Execute Docker Desktop operations more efficiently in scripts and tests. 
- An improved developer experience: Restart, quit, or reset Docker Desktop from the command line, reducing dependency on the Docker Desktop Dashboard and improving flexibility and efficiency.

## Usage

```console
docker desktop COMMAND [OPTIONS]
```

## Commands

| Command              | Description                              |
|:---------------------|:-----------------------------------------|
| `start`              | Starts Docker Desktop                    |
| `stop`               | Stops Docker Desktop                     |
| `restart`            | Restarts Docker Desktop                  |
| `status`             | Displays whether Docker Desktop is running or stopped.       |
| `engine ls`          | Lists available engines (Windows only)   |
| `engine use`         | Switch between Linux and Windows containers (Windows only) |
| `update`             | Manage Docker Desktop updates. |
| `logs`               | Print log entries                        |
| `disable`            | Disable a feature                        |
| `enable`             | Enable a feature                         | 
| `version`            | Show the Docker Desktop CLI plugin version information |
| `kubernetes`         | List Kubernetes images used by Docker Desktop or restart the cluster. Available with Docker Desktop version 4.44 and later.          |
| `diagnose`           | Diagnose Docker Desktop and upload the diagnostics. Available with Docker Desktop 4.60 and later. |

For more details on each command, see the [Docker Desktop CLI reference](/reference/cli/docker/desktop/).


---

# GPU support in Docker Desktop for Windows

*Sección: Desktop*

> [!NOTE]
>
> GPU support in Docker Desktop is only available on Windows with the WSL2 backend.

Docker Desktop for Windows supports NVIDIA GPU Paravirtualization (GPU-PV) on NVIDIA GPUs, allowing containers to access GPU resources for compute-intensive workloads like AI, machine learning, or video processing.

## Prerequisites

To enable WSL 2 GPU Paravirtualization, you need:

- A Windows machine with an NVIDIA GPU
- Up to date Windows 10 or Windows 11 installation
- [Up to date drivers](https://developer.nvidia.com/cuda/wsl) from NVIDIA supporting WSL 2 GPU Paravirtualization
- The latest version of the WSL 2 Linux kernel. Use `wsl --update` on the command line
- To make sure the [WSL 2 backend is turned on](wsl/index.md#turn-on-docker-desktop-wsl-2) in Docker Desktop

## Validate GPU support

To confirm GPU access is working inside Docker, run the following:

```console
$ docker run --rm -it --gpus=all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark
```

This runs an n-body simulation benchmark on the GPU. The output will be similar to:

```console
Run "nbody -benchmark [-numbodies=<numBodies>]" to measure performance.
        -fullscreen       (run n-body simulation in fullscreen mode)
        -fp64             (use double precision floating point values for simulation)
        -hostmem          (stores simulation data in host memory)
        -benchmark        (run benchmark to measure performance)
        -numbodies=<N>    (number of bodies (>= 1) to run in simulation)
        -device=<d>       (where d=0,1,2.... for the CUDA device to use)
        -numdevices=<i>   (where i=(number of CUDA devices > 0) to use for simulation)
        -compare          (compares simulation results running once on the default GPU and once on the CPU)
        -cpu              (run n-body simulation on the CPU)
        -tipsy=<file.bin> (load a tipsy model file for simulation)

> NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
MapSMtoCores for SM 7.5 is undefined.  Default to use 64 Cores/SM
GPU Device 0: "GeForce RTX 2060 with Max-Q Design" with compute capability 7.5

> Compute 7.5 CUDA device: [GeForce RTX 2060 with Max-Q Design]
30720 bodies, total time for 10 iterations: 69.280 ms
= 136.219 billion interactions per second
= 2724.379 single-precision GFLOP/s at 20 flops per interaction
```

## Run a real-world model: SmolLM2 with Docker Model Runner

Use Docker Model Runner to run the SmolLM2 LLM with vLLM and GPU acceleration:

```console
$ docker model install-runner --backend vllm --gpu cuda
```

Check it's correctly installed:

```console
$ docker model status
Docker Model Runner is running

Status:
llama.cpp: running llama.cpp version: c22473b
vllm: running vllm version: 0.11.0
```

Run the model:

```console
$ docker model run ai/smollm2-vllm hi
Hello! I'm sure everything goes smoothly here. How can I assist you today?
```


---

# Networking on Docker Desktop

*Sección: Desktop*

This page explains how Docker Desktop routes network traffic and file I/O between containers, the VM, and the host, and how this behavior is visible to firewalls and endpoint protection tools.

## Overview

Docker Desktop runs the Docker Engine inside a lightweight Linux virtual machine (VM). Depending on your system configuration and operating system, Docker Desktop routes network and file operations between the Docker VM and the host using different backend components.

### Backend components and responsibilities

The backend acts as:

- Network proxy: Translates traffic between the host and Linux VM.
  - On Windows and Mac, this is handled by the `com.docker.backend` process.
  - On Linux, the `qemu` process performs this function.
- File server: Handles file access from containers to the host filesystem.
  - When using gRPC FUSE, the backend performs the file sharing.
  - When using `virtiofs`, or `krun`, file access is handled by those respective daemons rather than the backend process.
- Control plane: Manages Docker API calls, port forwarding, and proxy configuration.

The following table summarizes typical setups in more detail:

| Platform        | Setup                                 | Networking handled by    | File sharing handled by                | Notes                                                      |
| --------------- | ------------------------------------- | ------------------------ | -------------------------------------- | ---------------------------------------------------------- |
| Windows         | Hyper-V                               | `com.docker.backend.exe` | `com.docker.backend.exe`               | Simplest setup with full visibility to EDR/firewall tools  |
| Windows (WSL 2) | WSL 2                                 | `com.docker.backend.exe` | WSL 2 kernel (no visibility from host) | Recommended only when WSL 2 integration is needed          |
| Mac             | Virtualization framework + gRPC FUSE  | `com.docker.backend`     | `com.docker.backend`                   | Recommended for performance and visibility                 |
| Mac             | Virtualization framework + `virtiofs` | `com.docker.backend`     | Apple's Virtualization framework       | Higher performance but no file access visibility from host |
| Mac             | DockerVMM + `virtiofs`                | `com.docker.backend`     | `krun`                                 | Currently in Beta                                          |
| Linux           | Native Linux VM                       | `qemu`                   | `virtiofsd`                            | No `com.docker.backend` process on Linux                   |

## How containers connect to the internet

Each Linux container in Docker Desktop runs inside a small virtual network managed by Docker and every container is attached to a Docker-managed network and receives its own internal IP address. You can view and manage these networks with `docker network ls`, `docker network create`, and `docker network inspect`. They are managed by the [`daemon.json`](../../../engine/daemon/index.md).

When a container initiates a network request, for example with `apt-get update` or `docker pull`:

- The container’s `eth0` interface connects to a virtual bridge (`docker0`) inside the VM.
- Outbound traffic from the container is sent through Network Address Translation (NAT) using a virtual adapter (typically with an internal IP such as `192.168.65.3`). You can view or change this with the [Docker Desktop settings](../../settings-and-maintenance/settings.md#network).
- The traffic is transferred to the host system over a shared-memory channel rather than through a traditional virtual network interface. This approach ensures reliable communication and avoids conflicts with host-level network adapters or firewall configurations.
- On the host, Docker Desktop’s backend process receives the traffic and creates standard TCP/IP connections using the same networking APIs as other applications.

All outbound container network traffic originates from the `com.docker.backend` process. Firewalls, VPNs, and security tools, like CrowdStrike, see traffic coming from this process — not from a VM or unknown source so firewall and endpoint security software can apply rules directly to `com.docker.backend`.

## How exposed ports work

When you publish a container port using the `-p` or `--publish` flag, Docker Desktop makes that container port accessible from your host system or local network.

For example, with `docker run -p 80:80 nginx`:

- Docker Desktop's backend process listens on the specified host port, in this case, port `80`.
- When an application such as a web browser connects to that port, Docker Desktop forwards the connection into the Linux VM where the container is running over a shared-memory channel.
- Inside the VM, the connection is routed to the container’s internal IP address and port, for example `172.17.0.2:80`.
- The container responds through the same path, so you can access it from your host just like any other local service.

By default, `docker run -p` listens on all network interfaces (`0.0.0.0`), but you can restrict it to a specific address, such as `127.0.0.1` (`localhost`) or a particular network adapter. This behavior can be modified to bind to `localhost` by default in [Docker Desktop's network settings](../../settings-and-maintenance/settings.md#network)

Host firewalls can permit or deny inbound connections by filtering on `com.docker.backend`.

## Using Docker Desktop with a proxy

Docker Desktop can use your system’s default proxy settings or custom settings that you configure with [Docker Desktop’s proxy setting](../../settings-and-maintenance/settings.md#proxies).

Docker Desktop routes traffic through two separate proxies. The Containers proxy governs all `docker image pull` operations, as well as running container traffic when air-gapped container enforcement is enabled. The Docker Desktop proxy governs host-level traffic - the Desktop application, Docker CLI, and extensions — and is a fallback for image pulls only when the Containers proxy is not explicitly configured.

Note that:

- The proxy honors system or manual proxy configuration.
- On Windows, Basic, NTLM, and Kerberos authentication is supported.
- For Mac, NTLM/Kerberos is not supported natively. Run a local proxy on `localhost` as a workaround.
- CLI plugins and other tools that use the Docker API directly must be configured separately with the `HTTP_PROXY`, `HTTPS_PROXY`, and `NO_PROXY` environment variables.

## Firewalls and endpoint visibility

To restrict VM or container networking apply rules to `com.docker.backend.exe` (Windows) `com.docker.backend` (Mac) or `qemu` (Linux) as all VM networking is funneled through these processes.

Use Windows Defender Firewall or enterprise endpoint firewalls for control. This enables traffic inspection and restriction at the host level without modifying the Docker Engine.

CrowdStrike and similar tools can observe all traffic and file access that passes through the backend process.

| Action                                       | Visible to host EDR? | Reason                                 |
| -------------------------------------------- | -------------------- | -------------------------------------- |
| Container reads host files                   | Yes                  | Access handled by `com.docker.backend` |
| Container writes host files                  | Yes                  | Same process performs the write        |
| Container accesses its own filesystem layers | No                   | Exists only inside the VM              |


---

# Explore networking how-tos on Docker Desktop

*Sección: Desktop*

This page explains how to configure and use networking features, connect containers to host services, work behind proxies or VPNs, and troubleshoot common issues.

For details on how Docker Desktop routes network traffic and file I/O between containers, the VM, and the host, see [Network overview](index.md#overview).

## Core networking how-tos

### Connect a container to a service on the host

The host has a changing IP address, or none if you have no network access. To connect to services running on your host, use the special DNS name:

| Name                      | Description                                      |
| ------------------------- | ------------------------------------------------ |
| `host.docker.internal`    | Resolves to the internal IP address of your host |
| `gateway.docker.internal` | Resolves to the gateway IP of the Docker VM      |


#### Example

Run a simple HTTP server on port `8000`:

```console
$ python -m http.server 8000
```

Then run a container, install `curl`, and try to connect to the host using the following commands:

```console
$ docker run --rm -it alpine sh
# apk add curl
# curl http://host.docker.internal:8000
# exit
```

### Connect to a container from the host

To access containerized services from your host or local network, publish ports with the `-p` or `--publish` flag. For example:

```console
$ docker run -d -p 80:80 --name webserver nginx
```

Docker Desktop makes whatever is running on port `80` in the container, in
this case, `nginx`, available on port `80` of `localhost`. 

> [!TIP]
>
> The syntax for `-p` is `HOST_PORT:CLIENT_PORT`.

To publish all ports, use the `-P` flag. For example, the following command
starts a container (in detached mode) and the `-P` flag publishes all exposed ports of the
container to random ports on the host.

```console
$ docker run -d -P --name webserver nginx
``` 

Alternatively, you can also use [host networking](../../../engine/network/drivers/host.md#docker-desktop)
to give the container direct access to the network stack of the host.

See the [run command](/reference/cli/docker/container/run/) for more details on
publish options used with `docker run`.

All inbound connections pass through the Docker Desktop backend process (`com.docker.backend` (Mac), `com.docker.backend.exe` (Windows), or `qemu` (Linux)), which handles port forwarding into the VM.
For more details, see [How exposed ports work](index.md#how-exposed-ports-work)

### Working with VPNs

Docker Desktop networking can work when attached to a VPN. 

To do this, Docker Desktop intercepts traffic from the containers and injects it into
the host as if it originated from the Docker application.

For details about how this traffic appears to host firewalls and endpoint detection systems, see [Firewalls and endpoint visibility](index.md#firewalls-and-endpoint-visibility).

### Working with proxies

Docker Desktop can use your system proxy or a manual configuration.
To configure proxies:

1. Navigate to the **Resources** tab in **Settings**. 
2. From the dropdown menu select **Proxies**.
3. Switch on the **Manual proxy configuration** toggle.
4. Enter your HTTP, HTTPS or SOCKS5 proxy URLS.

For more details on proxies and proxy configurations, see the [Proxy settings documentation](../../settings-and-maintenance/settings.md#proxies).

## Network how-tos for Mac and Windows

You can control how Docker handles container networking and DNS resolution to better support a range of environments — from IPv4-only to dual-stack and IPv6-only systems. These settings help prevent timeouts and connectivity issues caused by incompatible or misconfigured host networks.

You can set the following settings on the **Network** tab in the Docker Desktop Dashboard settings, or if you're an admin, with Settings Management via the [`admin-settings.json` file](../../../enterprise/security/hardened-desktop/settings-management/configure-json-file.md#networking), or [Docker Home](../../../enterprise/security/hardened-desktop/settings-management/configure-admin-console.md)

> [!NOTE]
>
> These settings can be overridden on a per-network basis using CLI flags or Compose file options.

### Default networking mode

Choose the default IP protocol used when Docker creates new networks. This allows you to align Docker with your host’s network capabilities or organizational requirements, such as enforcing IPv6-only access.

| Mode                         | Description                                 |
| ---------------------------- | ------------------------------------------- |
| **Dual IPv4/IPv6 (default)** | Supports both IPv4 and IPv6. Most flexible. |
| **IPv4 only**                | Uses only IPv4 addressing.                  |
| **IPv6 only**                | Uses only IPv6 addressing.                  |

### DNS resolution behavior 

Control how Docker filters DNS records returned to containers, improving reliability in environments where only IPv4 or IPv6 is supported. This setting is especially useful for preventing apps from trying to connect using IP families that aren't actually available, which can cause avoidable delays or failures.

| Option                         | Description                                                                 |
| ------------------------------ | --------------------------------------------------------------------------- |
| **Auto (recommended)**         | Automatically filters unsupported record types. (A for IPv4, AAAA for IPv6) |
| **Filter IPv4 (A records)**    | Blocks IPv4 lookups. Only available in dual-stack mode.                     |
| **Filter IPv6 (AAAA records)** | Blocks IPv6 lookups. Only available in dual-stack mode.                     |
| **No filtering**               | Returns both A and AAAA records.                                            |

> [!IMPORTANT]
>
> Switching the default networking mode resets the DNS filter to Auto.

## Network how-tos for Mac and Linux

### SSH agent forwarding

Docker Desktop for Mac and Linux lets you use the host’s SSH agent inside a container. To do this:

1. Bind mount the SSH agent socket by adding the following parameter to your `docker run` command:

   ```console
   $--mount type=bind,src=/run/host-services/ssh-auth.sock,target=/run/host-services/ssh-auth.sock
   ```

2. Add the `SSH_AUTH_SOCK` environment variable in your container:

    ```console
    $ -e SSH_AUTH_SOCK="/run/host-services/ssh-auth.sock"
    ```

To enable the SSH agent in Docker Compose, add the following flags to your service:

 ```yaml
services:
  web:
    image: nginx:alpine
    volumes:
      - type: bind
        source: /run/host-services/ssh-auth.sock
        target: /run/host-services/ssh-auth.sock
    environment:
      - SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock
 ```

## Known limitations

### Changing internal IP addresses

The internal IP addresses used by Docker can be changed from **Settings**. After changing IPs, you need to reset the Kubernetes cluster and to leave any active Swarm.

### There is no `docker0` bridge on the host

Because of the way networking is implemented in Docker Desktop, you cannot
see a `docker0` interface on the host. This interface is actually within the
virtual machine.

### I cannot ping my containers

Docker Desktop can't route traffic to Linux containers. However if you're a Windows user, you can
ping the Windows containers.

### Per-container IP addressing is not possible

This is because the Docker `bridge` network is not reachable from the host.
However if you are a Windows user, per-container IP addressing is possible with Windows containers.


---

# Synchronized file shares

*Sección: Desktop*

{{< summary-bar feature_name="Synchronized file sharing" >}}

Synchronized file shares is an alternative file sharing mechanism that provides fast and flexible host-to-VM file sharing, enhancing bind mount performance through the use of synchronized filesystem caches. 
 
## Who is it for?

Synchronized file shares is ideal for developers who: 
- Have large repositories or monorepos with 100 000 files or more totaling hundreds of megabytes or even gigabytes.
- Are using virtual filesystems, such as VirtioFS and gRPC FUSE which are no longer scaling well with their codebases. 
- Regularly encounter performance limitations.
- Don't want to worry about file ownership or spend time resolving conflicting file-ownership information when modifying multiple containers.

## How does Synchronized file shares work?

A Synchronized file share behaves just like a virtual file share, but takes advantage of a high-performance, low-latency code synchronization engine to create a synchronized cache of the host files on an ext4 filesystem within the Docker Desktop VM. If you make filesystem changes on the host or in the VM’s containers, it propagates via bidirectional synchronization.

After creating a file share instance, any container using a bind mount that points to a location on the host filesystem matching the specified synchronized file share location, or a subdirectory within it,  utilizes the Synchronized File Shares feature. Bind mounts that don't satisfy this condition are passed to the normal virtual filesystem [bind-mounting mechanism](../../engine/storage/bind-mounts.md), for example VirtioFS or gRPC-FUSE.

> [!NOTE]
>
> Synchronized file shares is not used by Kubernetes' `hostPath` volumes in Docker Desktop.

> [!IMPORTANT]
>
> Synchronized file shares isn't available when using Windows containers. 

## Create a file share instance 

To create a file share instance:
1. Sign in to Docker Desktop.
2. In **Settings**, navigate to the **File sharing** tab within the **Resources** section. 
3. In the **Synchronized file shares** section, select **Create share**.
4. Select a host folder to share. The synchronized file share should initialize and be usable.

File shares take a few seconds to initialize as files are copied into the Docker Desktop VM. During this time, the status indicator displays **Preparing**. There is also a status icon in the footer of the Docker Desktop Dashboard that keeps you updated.

When the status indicator displays **Watching for filesystem changes**, your files are available to the VM through all the standard bind mount mechanisms, whether that's `-v` in the command line or specified in your `compose.yml` file.

> [!NOTE]
>
> When you create a new service, setting the [bind mount option consistency](/reference/cli/docker/service/create/#options-for-bind-mounts) to `:consistent` bypasses Synchronized file shares. 

## Explore your file share instance

The **Synchronized file shares** section displays all your file share instances and provides useful information about each instance including:
- The origin of the file share content
- A status update
- How much space each file share is using
- The number of filesystem entry counts
- The number of symbolic links
- Which container(s) is using the file share instance

Selecting a file share instance expands the dropdown and exposes this information.

## Use `.syncignore`

You can use a `.syncignore` file at the root of each file share, to exclude local files from your file share instance. It supports the same syntax as `.dockerignore` files and excludes, and/or re-includes, paths from synchronization. `.syncignore` files are ignored at any location other than the root of the file share.
 
Some example of things you might want to add to your `.syncignore` file are:
- Large dependency directories, for example `node_modules` and `composer` directories (unless you rely on accessing them via a bind mount)
- `.git` directories (again, unless you need them)

In general, use your `.syncignore` file to exclude items that aren't critical to your workflow, especially those that would be slow to sync or use significant storage.

## Known issues

- Changes made to `.syncignore` don't lead to immediate deletions unless the file share is recreated. In other words, files that are newly ignored due to modifications in the `.syncignore` file remain in their current location, but are no longer updated during synchronization.

- File share instances are limited to approximately 2 million files per share. For best performance, if you have a file share instance of this size, try to decompose it into multiple shares corresponding to individual bind mount locations.

- Case conflicts, due to Linux being case-sensitive and macOS/Windows only being case-preserving, display as **File exists** problems in the GUI. These can be ignored. However, if they persist, you can report the issue.

- Synchronized file shares proactively reports temporary issues, which can result in occasional **Conflict** and **Problem** indicators appearing in the GUI during synchronization. These can be ignored. However, if they persist, you can report the issue.

- If you switch from WSL2 to Hyper-V on Windows, Docker Desktop needs to be fully restarted.

- POSIX-style Windows paths are not supported. Avoid setting the [`COMPOSE_CONVERT_WINDOWS_PATHS`](../../compose/how-tos/environment-variables/envvars.md#compose_convert_windows_paths) environment variable in Docker Compose.

- If you don't have the correct permissions to create symbolic links and your container attempts to create symbolic links in your file share instance, an **unable to create symbolic link** error message displays. For Windows users, see Microsoft's [Create symbolic links documentation](https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/create-symbolic-links) for best practices and location of the **Create symbolic links** security policy setting. For Mac and Linux users, check that you have write permissions on the folder.


---

# Using USB/IP with Docker Desktop

*Sección: Desktop*

{{< summary-bar feature_name="USB/IP support" >}}

USB/IP enables you to share USB devices over the network, which can then be accessed from within Docker containers. This page focuses on sharing USB devices connected to the machine you run Docker Desktop on. You can repeat the following process to attach and use additional USB devices as needed.

> [!NOTE]
>
> Docker Desktop includes built-in drivers for many common USB devices but Docker can't guarantee every possible USB device works with this setup.

## Setup and use

### Step one: Run a USB/IP server

To use USB/IP, you need to run a USB/IP server. For this guide, the implementation provided by [jiegec/usbip](https://github.com/jiegec/usbip) will be used.

1. Clone the repository.

    ```console
    $ git clone https://github.com/jiegec/usbip
    $ cd usbip
    ```

2. Run the emulated Human Interface Device (HID) device example.

    ```console
    $ env RUST_LOG=info cargo run --example hid_keyboard
    ```

### Step two: Start a privileged Docker container

To attach the USB device, start a privileged Docker container with the PID namespace set to `host`:

```console
$ docker run --rm -it --privileged --pid=host alpine
```

`--privileged` gives the container full access to the host, and `--pid=host` allows it to share the host’s process namespace.

### Step three: Enter the mount namespace of PID 1

Inside the container, enter the mount namespace of the `init` process to gain access to the pre-installed USB/IP tools:

```console
$ nsenter -t 1 -m
```

### Step four: Use the USB/IP tools

Now you can use the USB/IP tools as you would on any other system:

#### List USB devices

To list exportable USB devices from the host:

```console
$ usbip list -r host.docker.internal
```

Expected output:

```console
Exportable USB devices
======================
 - host.docker.internal
      0-0-0: unknown vendor : unknown product (0000:0000)
           : /sys/bus/0/0/0
           : (Defined at Interface level) (00/00/00)
           :  0 - unknown class / unknown subclass / unknown protocol (03/00/00)
```

#### Attach a USB device

To attach a specific USB device, or the emulated keyboard in this case:

```console
$ usbip attach -r host.docker.internal -d 0-0-0
```

#### Verify device attachment

After attaching the emulated keyboard, check the `/dev/input` directory for the device node:

```console
$ ls /dev/input/
```

Example output:

```console
event0  mice
```

### Step five: Access the device from another container

While the initial container remains running to keep the USB device operational, you can access the attached device from another container. For example:

1. Start a new container with the attached device.

    ```console
    $ docker run --rm -it --device "/dev/input/event0" alpine
    ```

2. Install a tool like `evtest` to test the emulated keyboard.

    ```console
    $ apk add evtest
    $ evtest /dev/input/event0
    ```

3. Interact with the device, and observe the output.

    Example output:

    ```console
    Input driver version is 1.0.1
    Input device ID: bus 0x3 vendor 0x0 product 0x0 version 0x111
    ...
    Properties:
    Testing ... (interrupt to exit)
    Event: time 1717575532.881540, type 4 (EV_MSC), code 4 (MSC_SCAN), value 7001e
    Event: time 1717575532.881540, type 1 (EV_KEY), code 2 (KEY_1), value 1
    Event: time 1717575532.881540, -------------- SYN_REPORT ------------
    ...
    ```

> [!IMPORTANT]
>
> The initial container must remain running to maintain the connection to the USB device. Exiting the container will stop the device from working.


---

# Virtual Machine Manager

*Sección: Desktop*

Docker Desktop supports multiple Virtual Machine Managers (VMMs) to power the Linux VM that runs containers. The options available depend on your platform.

## Docker VMM

{{< summary-bar feature_name="VMM" >}}

Docker VMM is a container-optimized hypervisor. From Docker Desktop 4.86, Docker VMM uses Docker's own hypervisor, replacing `libkrun` used in version 4.35 - 4.85 for Mac users. Built specifically for container workloads, Docker VMM:

- Returns idle memory to the host when containers aren't active, so Docker Desktop doesn't hold RAM it's not using
- Improves file I/O between container and host, reducing latency in the edit-compile-test loop
- Reduces engine and container start-up time

Because Docker controls the virtualization layer, it can be monitored and governed in ways that aren't possible with third-party backends. On Windows, Docker VMM provides a stable alternative to WSL 2 with a real VM boundary between the container environment and the host.

### Switch to Docker VMM

Docker VMM requires a minimum of 4 GB of memory allocated to the Docker Linux VM. Increase memory in **Settings** > **Resources** before switching.

{{< tabs >}}
{{< tab name="Mac (Apple Silicon)" >}}

1. Go to **Settings** > **General** > **Virtual Machine Manager**.
2. Select **Docker VMM**.
3. Select **Apply & restart**.

If you previously had Docker VMM selected, which engine runs depends on your version:

- Docker Desktop 4.35 and earlier is backed by `libkrun`
- Docker Desktop 4.86 and later is backed by Docker's own hypervisor

If you're upgrading from version 4.35 onwards, your setting is preserved and Docker Desktop switches to the new Docker VMM automatically on restart.

{{< /tab >}}
{{< tab name="Windows" >}}

1. Go to **Settings** > **General** > **Virtual Machine Manager**.
2. Select **Docker VMM**.
3. Select **Apply & restart**.

{{< /tab >}}
{{< /tabs >}}

### Known issues

- A restart of Docker Desktop may be required after switching to Docker VMM.
- Docker VMM does not support bind mount auto-shares. If you see a `file is not shared from the host` error, go to **Settings** > **Resources** > **File sharing** and add the directory you want to share.

#### Mac only

- Docker VMM does not currently support Rosetta, so emulation of amd64 architectures is slow. Docker is exploring potential solutions.
- Certain databases, such as MongoDB and Cassandra, may fail when using virtiofs with Docker VMM. This issue is expected to be resolved in a future release.

## Alternative VMMs for Mac

### Apple Virtualization framework

The Apple Virtualization framework is a stable and well-established option for managing virtual machines on Mac. It has been a reliable choice for many Mac users over the years.

### HyperKit (Legacy) for Intel-based Macs

> [!NOTE]
>
> HyperKit is deprecated. Docker recommends switching to the Apple Virtualization framework.

HyperKit is a legacy virtualization option for Intel-based Macs. Docker recommends switching to modern alternatives for better performance and to future-proof your setup.

## Alternative VMMs for Windows

### WSL 2

WSL 2 (Windows Subsystem for Linux 2) is the default Windows backend for Docker Desktop. It runs a full Linux kernel inside a lightweight VM with tight integration into the Windows host file system and networking. WSL 2 is available in both per-user and all-users installation modes and does not require administrator privileges.

For more information, see [Docker Desktop WSL 2 backend](wsl/index.md).

### Hyper-V

Hyper-V is Windows' native hypervisor. It runs the Docker Linux VM in a fully isolated virtual machine, providing a strong boundary between the container environment and the Windows host. Hyper-V is only available in all-users installation mode and requires administrator privileges.


---

# Wasm workloads

*Sección: Desktop*

{{< summary-bar feature_name="Wasm workloads" >}}

> [!IMPORTANT]
>
> Wasm workloads are deprecated and will be removed in a future Docker Desktop release. This feature is no longer actively maintained. 

WebAssembly (Wasm) is a fast, light alternative to Linux and
Windows containers.  With Docker Desktop, you can now run Wasm workloads side by side with traditional containers.

This page provides information about the ability to run Wasm applications
alongside your Linux containers in Docker.

> [!TIP]
>
> Learn more about Wasm use cases and tradeoffs in the [Docker Wasm technical preview blog post](https://www.docker.com/blog/docker-wasm-technical-preview/).

## Turn on Wasm workloads

Wasm workloads require the [containerd image store](containerd.md)
feature to be turned on. If you’re not already using the containerd image store,
then pre-existing images and containers will be inaccessible.

1. Navigate to **Settings** in Docker Desktop.
2. In the **General** tab, check **Use containerd for pulling and storing images**.
3. Go to **Features in development** and check the **Enable Wasm** option.
4. Select **Apply** to save the settings.
5. In the confirmation dialog, select **Install** to install the Wasm runtimes.

Docker Desktop downloads and installs the following runtimes: 
- `io.containerd.slight.v1`
- `io.containerd.spin.v2`
- `io.containerd.wasmedge.v1`
- `io.containerd.wasmtime.v1`
- `io.containerd.lunatic.v1`
- `io.containerd.wws.v1`
- `io.containerd.wasmer.v1`

## Usage examples

### Running a Wasm application with `docker run`

The following `docker run` command starts a Wasm container on your system:

```console
$ docker run \
  --runtime=io.containerd.wasmedge.v1 \
  --platform=wasi/wasm \
  secondstate/rust-example-hello
```

After running this command, you can visit [http://localhost:8080/](http://localhost:8080/) to see the "Hello world" output from this example module.

If you are receiving an error message, see the [troubleshooting section](#troubleshooting) for help.

Note the `--runtime` and `--platform` flags used in this command:

- `--runtime=io.containerd.wasmedge.v1`: Informs Docker Engine that you want
  to use the Wasm containerd shim instead of the standard Linux container
  runtime
- `--platform=wasi/wasm`: Specifies the architecture of the image you want to
  use. By leveraging a Wasm architecture, you don’t need to build separate
  images for the different machine architectures. The Wasm runtime takes care of
  the final step of converting the Wasm binary to machine instructions.

### Running a Wasm application with Docker Compose

The same application can be run using the following Docker Compose file:

```yaml
services:
  app:
    image: secondstate/rust-example-hello
    platform: wasi/wasm
    runtime: io.containerd.wasmedge.v1
```

Start the application using the normal Docker Compose commands:

   ```console
   $ docker compose up
   ```

### Running a multi-service application with Wasm

Networking works the same as you'd expect with Linux containers, giving you the
flexibility to combine Wasm applications with other containerized workloads,
such as a database, in a single application stack.

In the following example, the Wasm application leverages a MariaDB database
running in a container.

1. Clone the repository.

   ```console
   $ git clone https://github.com/second-state/microservice-rust-mysql.git
   Cloning into 'microservice-rust-mysql'...
   remote: Enumerating objects: 75, done.
   remote: Counting objects: 100% (75/75), done.
   remote: Compressing objects: 100% (42/42), done.
   remote: Total 75 (delta 29), reused 48 (delta 14), pack-reused 0
   Receiving objects: 100% (75/75), 19.09 KiB | 1.74 MiB/s, done.
   Resolving deltas: 100% (29/29), done.
   ```

2. Navigate into the cloned project and start the project using Docker Compose.

   ```console
   $ cd microservice-rust-mysql
   $ docker compose up
   [+] Running 0/1
   ⠿ server Warning                                                                                                  0.4s
   [+] Building 4.8s (13/15)
   ...
   microservice-rust-mysql-db-1      | 2022-10-19 19:54:45 0 [Note] mariadbd: ready for connections.
   microservice-rust-mysql-db-1      | Version: '10.9.3-MariaDB-1:10.9.3+maria~ubu2204'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution
   ```

   If you run `docker image ls` from another terminal window, you can see the
   Wasm image in your image store.

   ```console
   $ docker image ls
   REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
   server       latest    2c798ddecfa1   2 minutes ago   3MB
   ```

   Inspecting the image shows the image has a `wasi/wasm` platform, a
   combination of OS and architecture:

   ```console
   $ docker image inspect server | grep -A 3 "Architecture"
           "Architecture": "wasm",
           "Os": "wasi",
           "Size": 3001146,
           "VirtualSize": 3001146,
   ```

3. Open the URL `http://localhost:8090` in a browser and create a few sample
   orders. All of these are interacting with the Wasm server.

4. When you're all done, tear everything down by hitting `Ctrl+C` in the
   terminal you launched the application.

### Building and pushing a Wasm module

1. Create a Dockerfile that builds your Wasm application.

   Exactly how to do this varies depending on the programming language you use.

2. In a separate stage in your `Dockerfile`, extract the module and set it as
   the `ENTRYPOINT`.

   ```dockerfile
   # syntax=docker/dockerfile:1
   FROM scratch
   COPY --from=build /build/hello_world.wasm /hello_world.wasm
   ENTRYPOINT [ "/hello_world.wasm" ]
   ```

3. Build and push the image specifying the `wasi/wasm` architecture. Buildx
   makes this easy to do in a single command.

   ```console
   $ docker buildx build --platform wasi/wasm -t username/hello-world .
   ...
   => exporting to image                                                                             0.0s
   => => exporting layers                                                                            0.0s
   => => exporting manifest sha256:2ca02b5be86607511da8dc688234a5a00ab4d58294ab9f6beaba48ab3ba8de56  0.0s
   => => exporting config sha256:a45b465c3b6760a1a9fd2eda9112bc7e3169c9722bf9e77cf8c20b37295f954b    0.0s
   => => naming to docker.io/username/hello-world:latest                                            0.0s
   => => unpacking to docker.io/username/hello-world:latest                                         0.0s
   $ docker push username/hello-world
   ```

## Troubleshooting

This section contains instructions on how to resolve common issues.

### Unknown runtime specified

If you try to run a Wasm container without the [containerd image
store](containerd.md), an error similar to the following displays:

```text
docker: Error response from daemon: Unknown runtime specified io.containerd.wasmedge.v1.
```

[Turn on the containerd feature](containerd.md#enable-the-containerd-image-store)
in Docker Desktop settings and try again.

### Failed to start shim: failed to resolve runtime path

If you use an older version of Docker Desktop that doesn't support running Wasm
workloads, you will see an error message similar to the following:

```text
docker: Error response from daemon: failed to start shim: failed to resolve runtime path: runtime "io.containerd.wasmedge.v1" binary not installed "containerd-shim-wasmedge-v1": file does not exist: unknown.
```

Update your Docker Desktop to the latest version and try again.

## Known issues

- Docker Compose may not exit cleanly when interrupted. As a workaround, clean up `docker-compose` processes by sending them a SIGKILL (`killall -9 docker-compose`).
- Pushes to Docker Hub might give an error stating `server message: insufficient_scope: authorization failed`, even after signing in through Docker Desktop. As a workaround, run `docker login` in the CLI


---

# Docker Desktop WSL 2 backend on Windows

*Sección: Desktop*

Windows Subsystem for Linux (WSL) 2 is a full Linux kernel built by Microsoft that lets Linux distributions run without managing virtual machines. With Docker Desktop running on WSL 2, users can leverage Linux workspaces and avoid maintaining both Linux and Windows build scripts. In addition, WSL 2 provides improvements to file system sharing, faster cold-start times, and dynamic resource allocation.

Because WSL 2 uses dynamic memory allocation, Docker Desktop requests only the CPU and memory it actually needs — freeing resources for the rest of your system, while still letting memory-intensive tasks such as multi-stage image builds run at full speed.

## Prerequisites

Before you turn on the Docker Desktop WSL 2 feature, ensure you have:

- At a minimum WSL version 2.1.5, but ideally the latest version of WSL to [avoid Docker Desktop not working as expected](best-practices.md).
- Met the Docker Desktop for Windows' [system requirements](../../setup/install/windows-install.md#system-requirements).
- Installed the WSL 2 feature on Windows. For detailed instructions, refer to the [Microsoft documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10).

> [!TIP]
>
> Consider enabling the WSL [autoMemoryReclaim](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#experimental-settings) setting, available since WSL 1.3.10 (experimental).
>This setting allows Windows to reclaim unused memory from the WSL virtual machine, preventing the Linux kernel's page cache from holding onto large amounts of RAM after container image builds complete. The result is better memory availability for other applications on the host. 

## Turn on Docker Desktop WSL 2

Before installing Docker Desktop, uninstall any version of Docker Engine or the Docker CLI
that was installed directly inside a WSL Linux distribution. Running both can cause conflicts.

1. [Install Docker Desktop for Windows](../../setup/install/windows-install.md).
2. During installation, Docker Desktop may prompt you to turn on WSL 2. Read the information displayed on the screen and turn on the WSL 2 feature to continue.
3. Start Docker Desktop from the **Windows Start** menu.
4. Navigate to **Settings**.
5. From the **General** tab, select **Use WSL 2 based engine**.

    If you have installed Docker Desktop on a system that supports WSL 2, this option is turned on by default and the setting is not visible. 
6. Select **Apply**.

`docker` commands are now available from any Windows terminal using the WSL 2 engine.

> [!TIP]
>
> By default, Docker Desktop stores the data for the WSL 2 engine at `C:\Users\[USERNAME]\AppData\Local\Docker\wsl`.
> If you want to change the location, go to `Settings -> Resources -> Advanced` page from the Docker Dashboard.
> Read more about this and other Windows settings at [Changing settings](../../settings-and-maintenance/settings.md)

## Enable Docker in a WSL 2 distribution

WSL 2 lets multiple Linux distributions run side-by-side on a single shared kernel. Docker Desktop doesn't require a particular distribution to be installed, and `docker` commands work from Windows without one. However, enabling WSL integration for a distribution gives you direct access to `docker` commands from that distribution's terminal — which is useful for Linux-native development workflows.

1. Ensure the distribution runs in WSL 2 mode. WSL can run distributions in both v1 or v2 mode.

    To check the WSL mode, run:

     ```console
     $ wsl.exe -l -v
     ```

    To upgrade the Linux distribution to v2, run:

    ```console
    $ wsl.exe --set-version (distribution name) 2
    ```

    To set v2 as the default version for future installations, run:

    ```console
    $ wsl.exe --set-default-version 2
    ```

2. When Docker Desktop starts, go to **Settings** > **Resources** > **WSL Integration**.

    The Docker-WSL integration is enabled on the default WSL distribution, which is [Ubuntu](https://learn.microsoft.com/en-us/windows/wsl/install). To change your default WSL distribution, run:
     ```console
    $ wsl.exe --set-default <distribution name>
    ```
   If **WSL integrations** isn't available under **Resources**, Docker may be in Windows container mode. In your taskbar, select the Docker menu and then **Switch to Linux containers**.

3. Select **Apply**.

## WSL 2 security in Docker Desktop

Docker Desktop's WSL 2 integration works within WSL's existing security model and does not introduce security risks beyond standard WSL behavior.

Docker Desktop runs inside its own `docker-desktop` WSL distribution, isolated from other distributions in the same way any two WSL distributions are isolated from each other. Interaction between Docker Desktop and other distributions only occurs when you explicitly enable WSL integration for those distributions. This feature allows easy access to the Docker CLI from integrated distributions. 

WSL is designed to aid interoperability between Windows and Linux environments. Its file system is accessible from the Windows host `\\wsl$`, meaning Windows processes can read and modify files within WSL. This behavior is not specific to Docker Desktop, but rather a core aspect of WSL itself.

For environments that require stricter isolation:

- Run Docker Desktop in Hyper-V mode instead of WSL 2 to avoid the shared-kernel model entirely.
- Enable [Enhanced Container Isolation](../../../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md) to add an additional layer of protection around container workloads regardless of backend.

## Additional resources

- [Explore best practices](best-practices.md)
- [Understand how to develop with Docker and WSL 2](use-wsl.md)
- [Learn about GPU support with WSL 2](../gpu.md)
- [Custom kernels on WSL](custom-kernels.md)


---

# WSL 2 best practices for Docker Desktop on Windows

*Sección: Desktop*

This page covers recommendations when running Docker Desktop on Windows using WSL 2, including version requirements and file system performance.

## Keep WSL up to date

Always use the latest version of WSL. 

At a minimum you must use WSL version 2.1.5, otherwise Docker Desktop may not work as expected. Additionally, if you intend to use Enhanced Container Isolation, ensure you’re using WSL version 2.6 or later. This is required because ECI depends on a Linux kernel version of at least 6.3.0, and WSL 2.6+ bundles Linux kernel version 6.6. Testing, development, and documentation is based on the newest kernel versions. Older versions of WSL can cause:
- Docker Desktop to hang periodically or when upgrading
- Deployment via SCCM to fail
- The `vmmem.exe` to consume all memory 
- Network filter policies to be applied globally, not to specific objects
- GPU failures with containers

## Optimise file system performance with bind mounts

To get the best out of the file system performance when bind-mounting files, store source code and other data that is bind-mounted into Linux containers. For instance, use `docker run -v <host-path>:<container-path>` in the Linux file system, rather than the Windows file system. You can also refer to [Microsoft's recommendation](https://learn.microsoft.com/en-us/windows/wsl/compare-versions).

Linux containers only receive file change events, “inotify events”, if the original files are stored in the Linux filesystem. For example, some web development workflows rely on inotify events for automatic reloading when files have changed.

Performance is much higher when files are bind-mounted from the Linux filesystem, rather than accessed from the Windows host filesystem. Therefore avoid `docker run -v /mnt/c/users:/users` where `/mnt/c` is mounted from Windows.

Instead, from a Linux shell use a command like `docker run -v ~/my-project:/sources <my-image>` where `~` is expanded by the Linux shell to `$HOME`.

## Limit CPU and memory usage

If you have concerns about CPU or memory usage, configure limits on the memory, CPU, and swap size allocated to the [WSL 2 utility VM](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#global-configuration-options-with-wslconfig).


---

# Custom kernels on WSL

*Sección: Desktop*

> [!WARNING]
>
> Using a custom kernel with Docker Desktop on WSL 2 is not officially supported
and may cause issues with Docker Desktop startup or operation.

Docker Desktop depends on several kernel features built into the default
WSL 2 Linux kernel distributed by Microsoft.

However, in some cases it may be necessary
to run custom kernels; Docker Desktop does not block their use, and
some users have reported success using them.

## Recommendations if you must use a custom kernel

If you choose to use a custom kernel, start
from the kernel tree distributed by Microsoft from their [official
repository](https://github.com/microsoft/WSL2-Linux-Kernel) and then add
the features you need on top of that.

Also:
- Use the same kernel version as the one distributed by the latest WSL2
release. You can find the version by running `wsl.exe --system uname -r`
in a terminal.
- Make sure that your kernel build environment includes `pahole` and
its version is properly reflected in the corresponding kernel config
(`CONFIG_PAHOLE_VERSION`).


---

# Develop with Docker Desktop using WSL 2 on Windows

*Sección: Desktop*

The following section describes how to start developing your applications using Docker and WSL 2. 

For the best development experience, store your code inside your default Linux distribution. After you have turned on the WSL 2 feature on Docker Desktop, you can start working with your code inside the Linux distribution and ideally with your IDE still in Windows. This workflow is straightforward if you are using [VS Code](https://code.visualstudio.com/download).

## Develop with Docker and WSL 2

Before you begin, make sure you have enabled WSL 2 integration in Docker Desktop under **Settings** > **Resources** > **WSL Integration**.

1. Open VS Code and install the [WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) extension. This extension lets you work with a remote server in the Linux distribution and your IDE client still on Windows.
2. Open your terminal and type:

    ```console
    $ wsl
    ```
3. Navigate to your project directory and then type:

    ```console
    $ code .
    ```

    This opens a new VS Code window connected remotely to your default Linux distribution which you can check in the bottom corner of the screen.


Alternatively, you can open your default Linux distribution from the **Start** menu, navigate to your project directory, and then run `code .`


---

# Docker Desktop for Mac 2.x release notes

*Sección: Desktop*

This page contains release notes for Docker Desktop for Mac 2.x.

## Docker Desktop Community 2.5.0.1 
2020-11-10

### Upgrades

- [Compose CLI v1.0.2](https://github.com/docker/compose-cli/releases/tag/v1.0.2)
- [Snyk v1.424.4](https://github.com/snyk/snyk/releases/tag/v1.424.4)

### Bug fixes and minor changes
- Fixed an issue that caused Docker Desktop to crash on MacOS 11.0 (Big Sur) when VirtualBox was also installed. See [docker/for-mac#4997](https://github.com/docker/for-mac/issues/4997).

## Docker Desktop Community 2.5.0.0
2020-11-02

Docker Desktop 2.5.0.0 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### New

- Users with a paid Docker subscription can now see the vulnerability scan report on the Remote repositories tab in Docker Desktop.
- Docker Desktop introduces a support option for users with a paid Docker subscription.

### Security

- Fixed local privilege escalation vulnerability caused by inadequate certificate checking. See [CVE-2021-3162](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3162).

### Upgrades

- [Linux kernel 5.4.39](https://hub.docker.com/layers/linuxkit/kernel/5.4.39-f39f83d0d475b274938c86eaa796022bfc7063d2/images/sha256-8614670219aca0bb276d4749e479591b60cd348abc770ac9ecd09ee4c1575405?context=explore)
- [Docker Compose CLI 1.0.1](https://github.com/docker/compose-cli/releases/tag/v1.0.1)
- [Snyk v1.421.1](https://github.com/snyk/snyk/releases/tag/v1.421.1)
- [Go 1.15.2](https://github.com/golang/go/releases/tag/go1.15.2)
- [Kubernetes 1.19.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.3)

### Bug fixes and minor changes

- Renamed 'Run Diagnostics' to 'Get support'.
- Removed BlueStacks warning message. Fixes [docker/for-mac#4863](https://github.com/docker/for-mac/issues/4863).
- Made container start faster in cases where shared volumes have lots of files. Fixes [docker/for-mac#4957](https://github.com/docker/for-mac/issues/4957).
- File sharing: fixed changing ownership of read-only files. Fixes [docker/for-mac#4989](https://github.com/docker/for-mac/issues/4989), [docker/for-mac#4964](https://github.com/docker/for-mac/issues/4964).
- File sharing: generated `ATTRIB` inotify events as well as `MODIFY`. Fixes [docker/for-mac#4962](https://github.com/docker/for-mac/issues/4962).
- File sharing: returned `EOPNOTSUPP` from `fallocate` for unsupported modes. Fixes `minio`. Fixes [docker/for-mac#4964](https://github.com/docker/for-mac/issues/4964).
- File sharing: fixed a possible premature file handle close.
- When sharing Linux directories (`/var`, `/bin`, etc) with containers, Docker Desktop avoids watching paths in the host file system.
- When sharing a file into a container (e.g. `docker run -v ~/.gitconfig`) Docker Desktop does not watch the parent directory. Fixes [docker/for-mac#4981](https://github.com/docker/for-mac/issues/4981), [docker/for-mac#4975](https://github.com/docker/for-mac/issues/4975).
- Fixed an issue related to NFS mounting. Fixes [docker/for-mac#4958](https://github.com/docker/for-mac/issues/4958).
- Allow symlinks to point outside of shared volumes. Fixes [docker/for-mac#4862](https://github.com/docker/for-mac/issues/4862).
- Diagnostics: avoid hanging when Kubernetes is in a broken state.
- Docker Desktop now supports `S_ISUID`, `S_ISGID` and `S_ISVTX` in calls to `chmod(2)` on shared filesystems. Fixes [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).

## Docker Desktop Community 2.4.0.0
2020-09-30

Docker Desktop 2.4.0.0 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### New

- [Docker Compose CLI - 0.1.18](https://github.com/docker/compose-cli), enabling use of volumes with Compose and the Cloud through ECS and ACI.
- Docker introduces the new Images view in the Docker Dashboard. The images view allows users to view the Hub images, pull them and manage their local images on disk including cleaning up unwanted and unused images. To access the new Images view, from the Docker menu, select **Dashboard** > **Images**.
- Docker Desktop now enables BuildKit by default after a reset to factory defaults. To revert to the old `docker build` experience, go to **Preferences** > **Docker Engine** and then disable the BuildKit feature.
- [Amazon ECR Credential Helper](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.4.0)
- Docker Desktop now uses much less CPU when there are lots of file events on the host and when running Kubernetes, see [docker/roadmap#12](https://github.com/docker/roadmap/issues/12).
- Docker Desktop now uses gRPC-FUSE for file sharing by default. This uses much less CPU than osxfs, especially when there are lots of file events on the host. To switch back to `osxfs`, go to **Preferences** > **General** and disable gRPC-FUSE.

### Upgrades

- [Docker 19.03.13](https://github.com/docker/docker-ce/releases/tag/v19.03.13)
- [Docker Compose 1.27.4](https://github.com/docker/compose/releases/tag/1.27.4)
- [Go 1.14.7](https://github.com/golang/go/releases/tag/go1.14.7)
- [Alpine 3.12](https://alpinelinux.org/posts/Alpine-3.12.0-released.html)
- [Kubernetes 1.18.8](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.8)
- [Qemu 4.2.0](https://git.qemu.org/?p=qemu.git;a=tag;h=1e4aa2dad329852aa6c3f59cefd65c2c2ef2062c)

### Bug fixes and minor changes

- Docker Desktop on macOS 10.13 is now deprecated.
- Removed the legacy Kubernetes context `docker-for-desktop`. The context `docker-desktop` should be used instead. Fixes [docker/for-win#5089](https://github.com/docker/for-win/issues/5089) and [docker/for-mac#4089](https://github.com/docker/for-mac/issues/5089).
- Adding the application to the dock and clicking on it will launch the container view if Docker is already running.
- Added support for emulating Risc-V via Qemu 4.2.0.
- Removed file descriptor limit (`setrlimit`) of `10240`. We now rely on the kernel to impose limits via `kern.maxfiles` and `kern.maxfilesperproc`.
- Fixed a Mac CPU usage bug by removing the serial console from `hyperkit`, see [docker/roadmap#12]( https://github.com/docker/roadmap/issues/12#issuecomment-663163280). To open a shell in the VM use either `nc -U ~/Library/Containers/com.docker.docker/Data/debug-shell.sock`.
- Copy container logs without ansi colors to clipboard. Fixes [docker/for-mac#4786](https://github.com/docker/for-mac/issues/4786).
- Fixed automatic start on log in. See [docker/for-mac#4877] and [docker/for-mac#4890].
- Fixed bug where the application won't start if the username is too long.
- Fixed a bug where adding directories like `/usr` to the filesharing list prevents Desktop from starting. Fixes [docker/for-mac#4488](https://github.com/docker/for-mac/issues/4488)
- Fixed application startup if `hosts` is specified inside the Docker `daemon.json`. See [docker/for-win#6895](https://github.com/docker/for-win/issues/6895#issuecomment-637429117)
- Docker Desktop always flushes filesystem caches synchronously on container start. See [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).
- Compose-on-Kubernetes is no longer included in the Docker Desktop installer. You can download it separately from the compose-on-kubernetes [release page](https://github.com/docker/compose-on-kubernetes/releases).

### Known issues

-  There is a known issue when using `docker-compose` with named volumes and gRPC FUSE: second and subsequent calls to `docker-compose up` will fail due to the volume path having the prefix `/host_mnt`. To work around this issue, switch back to `osxfs` in Settings. See [docker/for-mac#4859](https://github.com/docker/for-mac/issues/4859).
- There is a known issue when enabling Kubernetes where the settings UI fails to update the Kubernetes state. To work around this issue, close and re-open the window.
- There is a rare known issue when switching users where the images view continues to show the repositories of the previous user. To work around this issue, close and re-open the window.

## Docker Desktop Community 2.3.0.5
2020-09-15

### New

- The new Cloud integration in Docker CLI makes it easy to run containers in the cloud using either Amazon ECS or Microsoft ACI. 
### Upgrades

- [Docker Compose 1.27.2](https://github.com/docker/compose/releases/tag/1.27.2)
- [Cloud integration v0.1.15](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.15)

### Bug fixes and minor changes

- Fixed automatic start on log in. See [docker/for-mac#4877](https://github.com/docker/for-mac/issues/4877) and [docker/for-mac#4890](https://github.com/docker/for-mac/issues/4890)

### Known issues

- The `clock_gettime64` system call returns `EPERM` rather than `ENOSYS`
  in i386 images. To work around this issue, disable `seccomp` by using
  the `--privileged` flag. See [docker/for-win#8326](https://github.com/docker/for-win/issues/8326).

## Docker Desktop Community 2.3.0.4
2020-07-27

### Upgrades

- [Docker 19.03.12](https://github.com/docker/docker-ce/releases/tag/v19.03.12)
- [Docker Compose 1.26.2](https://github.com/docker/compose/releases/tag/1.26.2)
- [Go 1.13.14](https://github.com/golang/go/issues?q=milestone%3AGo1.13.14+label%3ACherryPickApproved)

### Bug fixes and minor changes

- Fixed a privilege escalation vulnerability in `com.docker.vmnetd`. See [CVE-2020-15360](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15360)
- Fixed an issue with startup when the Kubernetes certificates have expired. See [docker/for-mac#4594](https://github.com/docker/for-mac/issues/4594)
- Fix an incompatibility between `hyperkit` and [osquery](https://osquery.io) which resulted in excessive `hyperkit` CPU usage. See [docker/for-mac#3499](https://github.com/docker/for-mac/issues/3499#issuecomment-619544836)
- Dashboard: Fixed containers logs which were sometimes truncated. Fixes [docker/for-win#5954](https://github.com/docker/for-win/issues/5954)

## Docker Desktop Community 2.3.0.3
2020-05-27

### Upgrades

- [Linux kernel 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-83885d3b4cff391813f4262099b36a529bca2df8-amd64/images/sha256-0214b82436af70054e013ea51cb1fea72bd943d0d6245b6521f1ff09a505c40f?context=repo)

### Bug fixes and minor changes

- Re-added device-mapper to the embedded Linux kernel. Fixes [docker/for-mac#4549](https://github.com/docker/for-mac/issues/4549).
- Fixed `hyperkit` on newer Macs and newer versions of `Hypervisor.framework`. Fixes [docker/for-mac#4562](https://github.com/docker/for-mac/issues/4562).

## Docker Desktop Community 2.3.0.2
2020-05-11


### New

Docker Desktop introduces a new onboarding tutorial upon first startup. The Quick Start tutorial guides users to get started with Docker in a few easy steps. It includes a simple exercise to build an example Docker image, run it as a container, push and save the image to Docker Hub.

### Upgrades

- [Docker Compose 1.25.5](https://github.com/docker/compose/releases/tag/1.25.5)
- [Go 1.13.10](https://github.com/golang/go/issues?q=milestone%3AGo1.13.10+label%3ACherryPickApproved)
- [Linux kernel 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-ce15f646db9b062dc947cfc0c1deab019fa63f96-amd64/images/sha256-6c252199aee548e4bdc8457e0a068e7d8e81c2649d4c1e26e4150daa253a85d8?context=repo)
- LinuxKit [init](https://hub.docker.com/layers/linuxkit/init/1a80a9907b35b9a808e7868ffb7b0da29ee64a95/images/sha256-64cc8fa50d63940dbaa9979a13c362c89ecb4439bcb3ab22c40d300b9c0b597e?context=explore), [runc](https://hub.docker.com/layers/linuxkit/runc/69b4a35eaa22eba4990ee52cccc8f48f6c08ed03/images/sha256-57e3c7cbd96790990cf87d7b0f30f459ea0b6f9768b03b32a89b832b73546280?context=explore) and [containerd](https://hub.docker.com/layers/linuxkit/containerd/09553963ed9da626c25cf8acdf6d62ec37645412/images/sha256-866be7edb0598430709f88d0e1c6ed7bfd4a397b5ed220e1f793ee9067255ff1?context=explore)

### Bug fixes and minor changes

- Reduced the size of the Docker Desktop installer from 708 MB to 456 MB.
- Fixed bug where containers disappeared from the UI when Kubernetes context is invalid. Fixes [docker/for-win#6037](https://github.com/docker/for-win/issues/6037).
- Fixed a file descriptor leak in `vpnkit-bridge`. Fixes [docker/for-win#5841](https://github.com/docker/for-win/issues/5841).
- Added a link to the Edge channel from the UI.
- Made the embedded terminal resizable.
- Fixed a bug where diagnostic upload would fail if the username contained spaces.
- Fixed a bug where the Docker UI could be started without the engine.
- Switched from `ahci-hd` to `virtio-blk` to avoid an AHCI deadlock, see [moby/hyperkit#94](https://github.com/moby/hyperkit/issues/94) and [docker/for-mac#1835](https://github.com/docker/for-mac/issues/1835).
- Fixed an issue where a container port could not be exposed on a specific host IP. See [docker/for-mac#4209](https://github.com/docker/for-mac/issues/4209).
- Removed port probing from dashboard, just unconditionally showing links to ports that should be available. Fixes [docker/for-mac#4264](https://github.com/docker/for-mac/issues/4264).
- Docker Desktop now shares `/var/folders` by default as it stores per-user temporary files and caches.
- Ceph support has been removed from Docker Desktop to save disk space.
- Fixed a performance regression when using shared volumes in 2.2.0.5. Fixes [docker/for-mac#4423].

## Docker Desktop Community 2.2.0.5
2020-04-02

### Bug fixes and minor changes

- Removed dangling `/usr/local/bin/docker-machine` symlinks which avoids custom installs of  Docker Machine being accidentally deleted in future upgrades. Note that if you have installed Docker Machine manually, then the install might have followed the symlink and installed Docker Machine in `/Applications/Docker.app`. In this case, you must manually reinstall Docker Machine after installing this version of Docker Desktop. Fixes [docker/for-mac#4208](https://github.com/docker/for-mac/issues/4208).

## Docker Desktop Community 2.2.0.4
2020-03-13

### Upgrades

- [Docker 19.03.8](https://github.com/docker/docker-ce/releases/tag/v19.03.8)

### Bug fixes and minor changes

- Kubernetes: Persistent volumes created by claims are now stored in the virtual machine. Fixes [docker/for-win#5665](https://github.com/docker/for-win/issues/5665).
- Fixed an issue which caused Docker Desktop Dashboard to attempt connecting to all exposed ports inside a container. Fixes [docker/for-mac#4264](https://github.com/docker/for-mac/issues/4264).

## Docker Desktop Community 2.2.0.3
2020-02-11

### Upgrades

- [Docker Compose 1.25.4](https://github.com/docker/compose/releases/tag/1.25.4)
- [Go 1.12.16](https://golang.org/doc/devel/release.html#go1.12)

## Docker Desktop Community 2.2.0.0
2020-01-21

Docker Desktop 2.2.0.0 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker Compose 1.25.2](https://github.com/docker/compose/releases/tag/1.25.2)
- [Kubernetes 1.15.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.15.5)
- Linux kernel 4.19.76
- [QEMU 4.0.1](https://github.com/docker/binfmt)

### New

- **Docker Desktop Dashboard:** The new Docker Desktop **Dashboard** provides a user-friendly interface which enables you to interact with containers and applications, and manage the lifecycle of your applications directly from the UI. In addition, it allows you to access the logs, view container details, and monitor resource utilization to explore the container behavior.
  For detailed information about the new Dashboard UI, see [Docker Desktop Dashboard](../index.md).

- Introduced a new user interface for the Docker Desktop **Preferences** menu.
- The Restart, Reset, and Uninstall options are now available on the **Troubleshoot** menu.
- Added the ability to start and stop existing Compose-based applications and view combined logs in the Docker Desktop **Dashboard** UI.

### Bug fixes and minor changes

- Added missing completions for the `fish` shell for Docker Compose. Fixes [docker/for-mac#3795](https://github.com/docker/for-mac/issues/3795).
- Fixed a bug that did not allow users to copy and paste text in the **Preferences** > **Daemon** window. Fixes [docker/for-mac#3798](https://github.com/docker/for-mac/issues/3798).
- Added support for `Expect: 100-continue` headers in the Docker API proxy. Some HTTP clients such as `curl` send this header when the payload is large, for example, when creating containers. Fixes [moby/moby#39693](https://github.com/moby/moby/issues/39693).
- Added a loading overlay to the **Settings** and **Troubleshoot** windows to prevent editing conflicts.
- Deactivated the **Reset Kubernetes** button when Kubernetes is not activated.
- Improved the navigation in **Settings** and **Troubleshoot** UI.
- Fixed a bug in the UEFI boot menu that sometimes caused Docker Desktop to hang during restart. Fixes [docker/for-mac#2655](https://github.com/docker/for-mac/issues/2655) and [docker/for-mac#3921](https://github.com/docker/for-mac/issues/3921).
- Docker Desktop now allows users to access the host’s SSH agent inside containers. Fixes [docker/for-mac#410](https://github.com/docker/for-mac/issues/410)
- Docker Machine is no longer included in the Docker Desktop installer. You can download it separately from the [Docker Machine releases](https://github.com/docker/machine/releases) page.
- Fixed an issue that caused VMs running on older hardware with macOS Catalina to fail on startup with the error `processor does not support desired secondary processor-based controls`.
- Fixed port forwarding when containers are using `overlay` networks.
- Fixed a container start error when a container has more than one port with an arbitrary or not-yet-configured external port number. For example, `docker run -p 80 -p 443 nginx`. Fixes [docker/for-win#4935](https://github.com/docker/for-win/issues/4935) and [docker/compose#6998](https://github.com/docker/compose/issues/6998).
- Fixed an issue that occurs when sharing overlapping directories.
- Fixed a bug that prevented users from changing the location of the VM disk image.
- Docker Desktop does not inject `inotify` events on directories anymore as these can cause mount points to disappear inside containers. Fixes [docker/for-mac#3976](https://github.com/docker/for-mac/issues/3976).
- Fixed an issue that caused Docker Desktop to fail on startup when there is an incomplete Kubernetes config file.
- Fixed an issue where attempts to log into Docker through Docker Desktop could sometimes fail with the `Incorrect authentication credentials` error. Fixes [docker/for-mac#4010](https://github.com/docker/for-mac/issues/4010).

### Known issues

- When you start a Docker Compose application and then start a Docker App which has the same name as the Compose application, Docker Desktop displays only one application on the Dashboard. However, when you expand the application, containers that belong to both applications are displayed on the Dashboard.

- When you deploy a Docker App with multiple containers on Kubernetes, Docker Desktop displays each Pod as an application on the Dashboard.

## Docker Desktop Community 2.1.0.5
2019-11-18

Docker Desktop 2.1.0.5 contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker 19.03.5](https://github.com/docker/docker-ce/releases/tag/v19.03.5)
- [Kubernetes 1.14.8](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.8)
- [Go 1.12.13](https://golang.org/doc/devel/release.html#go1.12)

## Docker Desktop Community 2.1.0.4
2019-10-21

### Upgrades

- [Docker 19.03.4](https://github.com/docker/docker-ce/releases/tag/v19.03.4)
- [Kubernetes 1.14.7](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.7)
- [Go 1.12.10](https://github.com/golang/go/issues?q=milestone%3AGo1.12.10+label%3ACherryPickApproved)
- [Kitematic 0.17.9](https://github.com/docker/kitematic/releases/tag/v0.17.9)

### New

Docker Desktop now enables you to sign into Docker Hub using two-factor authentication.


## Docker Desktop Community 2.1.0.3
2019-09-16

### Upgrades

- [Kitematic 0.17.8](https://github.com/docker/kitematic/releases/tag/v0.17.8)

### Bug fixes and minor changes

- All binaries included in Docker Desktop are now notarized so that they can run on macOS Catalina. For more information, see [Notarization Requirement for Mac Software](https://developer.apple.com/news/?id=06032019i).

## Docker Desktop Community 2.1.0.2
2019-09-04

Docker Desktop 2.1.0.2 contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker 19.03.2](https://github.com/docker/docker-ce/releases/tag/v19.03.2)
- [Kubernetes 1.14.6](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.6)
- [Go 1.12.9](https://github.com/golang/go/issues?q=milestone%3AGo1.12.9+label%3ACherryPickApproved)
- [Docker Machine 0.16.2](https://github.com/docker/machine/releases/tag/v0.16.2)

## Docker Desktop Community 2.1.0.1
2019-08-08

Note that you must sign in and create a Docker ID in order to download Docker Desktop.

### Upgrades

* [Docker 19.03.1](https://github.com/docker/docker-ce/releases/tag/v19.03.1)
* [Docker Compose 1.24.1](https://github.com/docker/compose/releases/tag/1.24.1)
* [Kubernetes 1.14.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.3)
* [Compose on Kubernetes 0.4.23](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.23)
* [Docker Machine 0.16.1](https://github.com/docker/machine/releases/tag/v0.16.1)
* [linuxkit v0.7](https://github.com/linuxkit/linuxkit/releases/tag/v0.7)
* Linux Kernel 4.9.184
* [Kitematic 0.17.6](https://github.com/docker/kitematic/releases/tag/v0.17.6)
* [Qemu 4.0.0](https://github.com/docker/binfmt) for cross compiling for ARM
* [Alpine 3.10](https://alpinelinux.org/posts/Alpine-3.10.0-released.html)
* [Docker Credential Helpers 0.6.3](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.3)
* [Hyperkit v0.20190802](https://github.com/moby/hyperkit/releases/tag/v0.20190802)

### New

* Selecting the ‘Experimental features’ checkbox in the Daemon **Preferences** menu turns on experimental features for Docker daemon and Docker CLI.
* Improved the reliability of `com.docker.osxfs trace` performance profiling command. Users can now run the `com.docker.osxfs trace --summary` option for a high-level summary of operations, instead of receiving a trace of all operations.
* Docker Desktop now supports large lists of DNS resource records on Mac.  Fixes [docker/for-mac#2160](https://github.com/docker/for-mac/issues/2160#issuecomment-431571031).

### Experimental

> Experimental features provide early access to future product functionality. These features are intended for testing and feedback only as they may change between releases without warning or can be removed entirely from a future release. Experimental features must not be used in production environments. Docker does not offer support for experimental features.

Docker Desktop Community 2.1.0.0 contains the following experimental features.

* Docker App: Docker App is a CLI plugin that helps configure, share, and install applications.
* Docker Buildx: Docker Buildx is a CLI plugin for extended build capabilities with BuildKit. For more information, see the [Build page](../../build/index.md).

### Bug fixes and minor changes

* Docker Desktop now allows users to expose privileged UDP ports. [docker/for-mac#3775](https://github.com/docker/for-mac/issues/3775)
* Fixed an issue where running some Docker commands can fail if you are not using Credential Helpers. [docker/for-mac#3785](https://github.com/docker/for-mac/issues/3785)
* Changed the host's kubernetes context so that `docker run -v .kube:kube ... kubectl` works.
* Restricted the `cluster-admin` role on local Kubernetes cluster to `kube-system` namespace.
* Reduced the VM startup time. swap is not created every time a virtual machine boots.
* Fixed Kubernetes installation with VPNkit subnet.
* Fixed a bug where the process output was not redirected to stdout when gathering diagnostics on Windows, which sometimes resulted in a crash.
* Added `/etc/machine-id` to the virtual machine. Fixes [docker/for-mac#3554](https://github.com/docker/for-mac/issues/3554).
* Docker Desktop does not send DNS queries for `docker-desktop.<domain>` every 10s. It now relies on the host’s DNS domain search order rather than trying to replicate it inside the VM.
* Removed the ability to log in using email address as a username as the Docker command line does not support this.
* Docker Desktop now allows running a Docker registry inside a container. Fixes [docker/for-mac#3611](https://github.com/docker/for-mac/issues/3611).
* Fixed a stability issue with the DNS resolver.
* Docker Desktop truncates UDP DNS responses which are over 512 bytes in sizes.
* Fixed port 8080 that was used on localhost when starting Kubernetes. Fixes [docker/for-mac#3522](https://github.com/docker/for-mac/issues/3522).
* Improved error messaging: Docker Desktop does not prompt users to run diagnostics, or to reset to factory default when it is not appropriate.
* Kubernetes: Docker Desktop now uses the default maximum number of pods for kubelet. [docker/for-mac#3453](https://github.com/docker/for-mac/issues/3453).
* Fixed DockerHelper crash. [docker/for-mac#3470](https://github.com/docker/for-mac/issues/3470).
* Fixed binding of privileged ports with specified IP. [docker/for-mac#3464](https://github.com/docker/for-mac/issues/3464)
* Fixed service log collection in diagnostics.
* Docker Desktop now gathers `/etc/hosts` to help with diagnostics.
* When two services have a common exposed port, Docker Desktop now exposes the available ports for the second service. [docker/for-mac#3438](https://github.com/docker/for-mac/issues/3438).
* Docker Desktop ensures localhost resolves to 127.0.0.1. This is related to [docker/for-mac#2990](https://github.com/docker/for-mac/issues/2990#issuecomment-443097942), [docker/for-mac#3383](https://github.com/docker/for-mac/issues/3383).

### Docker Community Edition 2.0.0.3 2019-02-15

* Upgrades
  - [Docker 18.09.2](https://github.com/docker/docker-ce/releases/tag/v18.09.2), fixes [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736)

### Docker Community Edition 2.0.0.2 2019-01-16

* Upgrades
  - [Docker 18.09.1](https://github.com/docker/docker-ce/releases/tag/v18.09.1)
  - [Docker Machine 0.16.1](https://github.com/docker/machine/releases/tag/v0.16.1)
  - [Kubernetes 1.10.11](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.10.md#v11011), fixes [CVE-2018-1002105](https://github.com/kubernetes/kubernetes/issues/71411)
  - [Kitematic 0.17.6](https://github.com/docker/kitematic/releases/tag/v0.17.6)
  - Golang 1.10.6, fixes CVEs: [CVE-2018-16875](https://www.cvedetails.com/cve/CVE-2018-16875), [CVE-2018-16873](https://www.cvedetails.com/cve/CVE-2018-16873) and [CVE-2018-16874](https://www.cvedetails.com/cve/CVE-2018-16874)

* Bug fixes and minor changes
  - Add 18.09 missing daemon options

### Docker Community Edition 2.0.0.0-mac81 2018-12-07


* Upgrades
  - [Docker compose 1.23.2](https://github.com/docker/compose/releases/tag/1.23.2)

### Docker Community Edition 2.0.0.0-mac78 2018-11-19


* Upgrades
  - [Docker 18.09.0](https://github.com/docker/docker-ce-packaging/releases/tag/v18.09.0)
  - [Docker compose 1.23.1](https://github.com/docker/compose/releases/tag/1.23.1)
  - [Docker Machine 0.16.0](https://github.com/docker/machine/releases/tag/v0.16.0)
  - [Kitematic 0.17.5](https://github.com/docker/kitematic/releases/tag/v0.17.5)
  - Linux Kernel 4.9.125

* New
  - New version scheme

* Deprecation
  - Removed support of AUFS
  - Removed support of OSX 10.11

* Bug fixes and minor changes
  - Fix appearance in dark mode for OSX 10.14 (Mojave)
  - VPNKit: Improved scalability of port forwarding. Related to [docker/for-mac#2841](https://github.com/docker/for-mac/issues/2841)
  - VPNKit: Limit the size of the UDP NAT table. This ensures port forwarding and regular TCP traffic continue even when running very chatty UDP protocols.
  - Ensure Kubernetes can be installed when using a non-default internal IP subnet.
  - Fix panic in diagnose


---

# Docker for Windows 2.x release notes

*Sección: Desktop*

This page contains release notes for Docker Desktop for Windows 2.x. 

## Docker Desktop Community 2.5.0.1
2020-11-10

### Upgrades

- [Compose CLI v1.0.2](https://github.com/docker/compose-cli/releases/tag/v1.0.2)
- [Snyk v1.424.4](https://github.com/snyk/snyk/releases/tag/v1.424.4)

## Docker Desktop Community 2.5.0.0
2020-11-02

Docker Desktop 2.5.0.0 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### New

- Users with a paid Docker subscription can now see the vulnerability scan report on the Remote repositories tab in Docker Desktop.
- Docker Desktop introduces a support option for users who have a paid Docker subscription.

### Upgrades

- [Linux kernel 5.4.39](https://hub.docker.com/layers/linuxkit/kernel/5.4.39-f39f83d0d475b274938c86eaa796022bfc7063d2/images/sha256-8614670219aca0bb276d4749e479591b60cd348abc770ac9ecd09ee4c1575405?context=explore)
- [Docker Compose CLI 1.0.1](https://github.com/docker/compose-cli/releases/tag/v1.0.1)
- [Snyk v1.421.1](https://github.com/snyk/snyk/releases/tag/v1.421.1)
- [Go 1.15.2](https://github.com/golang/go/releases/tag/go1.15.2)
- [Kubernetes 1.19.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.3)

### Deprecation

- Docker Desktop cannot be installed on Windows 1703 (build 15063) anymore.

### Bug fixes and minor changes

- Renamed 'Run Diagnostics' to 'Get support'.
- Fixed an issue that intermittently made the WSL 2 backend fail to start.
- Fixed an issue related to NFS mounting. See [docker/for-mac#4958](https://github.com/docker/for-mac/issues/4958).
- Fixed an issue where bash in WSL would not find the docker CLI when it is started before Docker Desktop.
- Fixed an issue with HTTP proxy exclude lists containing entries such as `localhost` or `127.0.0.1`. Fixes [docker/for-win#8750](https://github.com/docker/for-win/issues/8750).
- When the WSL integration process unexpectedly stops, the user is now notified and can decide to restart it or not, instead of always trying to restart it in a loop. fixes [docker/for-win#8968](https://github.com/docker/for-win/issues/8968).
- Fixed an issue related to container logs lagging under heavy load. Fixes [docker/for-win#8216](https://github.com/docker/for-win/issues/8216).
- Diagnostics: avoid hanging when Kubernetes is in a broken state.
- Fixed the path to the installer log file default location when the username contains a space. Fixes [docker/for-win#7941](https://github.com/docker/for-win/issues/7941).
- Fixed an issue where some network plugins may fail to load, provoking a crash of the Docker daemon [docker/for-win#9282](https://github.com/docker/for-win/issues/9282).
- When sharing a file into a container (e.g. `docker run -v ~/.gitconfig`) Docker Desktop does not watch the parent directory. Fixes [docker/for-mac#4981](https://github.com/docker/for-mac/issues/4981).

## Docker Desktop Community 2.4.0.0
2020-09-30

Docker Desktop 2.4.0.0 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### New

- [Docker Compose CLI - 0.1.18](https://github.com/docker/compose-cli), enabling use of volumes with Compose and the Cloud through ECS and ACI.
- Docker introduces the new Images view in the Docker Dashboard. The images view allows users to view the Hub images, pull them and manage their local images on disk including cleaning up unwanted and unused images. To access the new Images view, from the Docker menu, select **Dashboard** > **Images**.
- Docker Desktop now enables BuildKit by default after a reset to factory defaults. To revert to the old `docker build` experience, go to **Settings** > **Docker Engine** and then disable the BuildKit feature.
- [Amazon ECR Credential Helper](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.4.0)

### Upgrades

- [Docker 19.03.13](https://github.com/docker/docker-ce/releases/tag/v19.03.13)
- [Docker Compose 1.27.4](https://github.com/docker/compose/releases/tag/1.27.4)
- [Go 1.14.7](https://github.com/golang/go/releases/tag/go1.14.7)
- [Alpine 3.12](https://alpinelinux.org/posts/Alpine-3.12.0-released.html)
- [Kubernetes 1.18.8](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.8)
- [Qemu 4.2.0](https://git.qemu.org/?p=qemu.git;a=tag;h=1e4aa2dad329852aa6c3f59cefd65c2c2ef2062c)

### Bug fixes and minor changes

- Removed the legacy Kubernetes context `docker-for-desktop`. The context `docker-desktop` should be used instead. Fixes [docker/for-win#5089](https://github.com/docker/for-win/issues/5089) and [docker/for-mac#4089](https://github.com/docker/for-mac/issues/4089).
- Removed the option to start with Windows containers from the installer
- Pinning the application to the taskbar and clicking on it will launch the container view if Docker is already running.
- Left-clicking on the whale in the system tray now launches the dashboard container view.
- Docker Desktop now uses a different systray icon for dark and light mode. Fixes [docker/for-win#4113](https://github.com/docker/for-win/issues/4113).
- Added support for emulating Risc-V via Qemu 4.2.0.
- Added a low-level debug shell accessible via `putty -serial \\.\pipe\dockerDebugShell`.
- Copy container logs without ansi colors to clipboard. Fixes [docker/for-mac#4786](https://github.com/docker/for-mac/issues/4786).
- Fix application startup if `hosts` is specified inside the Docker `daemon.json`. See [docker/for-win#6895](https://github.com/docker/for-win/issues/6895#issuecomment-637429117)
- Fixed DNS resolution of short names. See [docker/for-win#4425](https://github.com/docker/for-win/issues/4425).
- Switched from `chronyd` to `sntpcd` to work around host time synchronization problems. Fixes [docker/for-win#4526](https://github.com/docker/for-win/issues/4526).
- Avoid blocking startup if "Expose daemon on tcp://localhost:2375 without TLS" is set and `localhost:2375` is in use by another program. See [docker/for-win#6929](https://github.com/docker/for-win/issues/6929) [docker/for-win#6961](https://github.com/docker/for-win/issues/6961).
- Fixed an issue where adding a folder on a non-existing drive in the settings would create an empty entry. See [docker/for-win#6797](https://github.com/docker/for-win/issues/6797).
- Avoid failing with "Function not implemented" during file I/O on shared volumes. Fixes [docker/for-win#5955](https://github.com/docker/for-win/issues/5955)
- Ensure that `docker run -v /var/run/docker.sock` rewrites Windows paths properly, see [docker/for-win#6628](https://github.com/docker/for-win/issues/6628).
- Fixed a crash which occurred when Docker Desktop loads a corrupted Docker CLI configuration file. Fixes [docker/for-win#6657](https://github.com/docker/for-win/issues/6657).
- Ensure `localhost` and `127.0.0.1` can both be used in the proxy settings to redirect to a proxy on the host. Fixes [docker/for-win#5715](https://github.com/docker/for-win/issues/5715) and [docker/for-win#6260](https://github.com/docker/for-win/issues/6260).
- Fixed a crash when failing to login with no Internet connection.
- Fixed bug in handling shared volume paths with ".." characters. Fixes [docker/for-win#5375](https://github.com/docker/for-win/issues/5375).
- Report check for updates errors in toast notification. Fixes [docker/for-win#6364](https://github.com/docker/for-win/issues/6364).
- Fixed an upgrade bug where users on versions still using the PowerShell based VM management can experience a silent un-installation crash leading to Docker Desktop being uninstalled instead of upgraded.
- Fixed the path to the installer log file default location when the username contains a space. Fixes [docker/for-win#7941](https://github.com/docker/for-win/issues/7941).
- Docker Desktop always flushes filesystem caches synchronously on container start. See [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).
- Compose-on-Kubernetes is no longer included in the Docker Desktop installer. You can download it separately from the compose-on-kubernetes [release page](https://github.com/docker/compose-on-kubernetes/releases).

### WSL 2 changes

- Docker contexts are now synced between Windows and WSL distributions.
- Fixed an issue that intermittently causes the backend to fail to start.
- Fixed a proxy crash that happened when glibc was not compatible. See [docker/for-win#8183](https://github.com/docker/for-win/issues/8183).
- Fixed an issue when removing a container mounting `/mnt/wsl` would break WSL integration. See [docker/for-win#7836](https://github.com/docker/for-win/issues/7836).
- Added support for mounting files from a distribution using the Windows CLI (e.g. `docker run -v \\wsl$\Ubuntu\home\simon\web:/web ...`)
- Fixed the error message when attempting to use a shared volume with a relative path. Fixes [docker/for-win#6894](https://github.com/docker/for-win/issues/6894).
- Fixed an issue when updating Windows to a WSL 2 capable version, where a configuration file is locked by the old Hyper-V VM.
- Fixed a discrepancy in the version of Docker Compose inside and outside of WSL 2. Fixes [docker/for-win#6461](https://github.com/docker/for-win/issues/6461).
- Detect when the `docker-desktop` wsl distribution is stopped and display a clearer error message.
- Fix a race condition when exposing ports.
- Enable dialog no longer blocks other windows.

### Known issues

-  There is a known issue when using `docker-compose` with named volumes and gRPC FUSE: second and subsequent calls to `docker-compose up` will fail due to the volume path having the prefix `/host_mnt`.
- There is a known issue when enabling Kubernetes where the settings UI sometimes fails to update the Kubernetes state. To work around this issue, close and re-open the Window.
- There is a rare known issue when switching users, where the images UI sometimes continues to show the repositories of the previous user. To work around this issue, close and re-open the Window.

## Docker Desktop Community 2.3.0.5
2020-09-15

### New

- The new Cloud integration in Docker CLI makes it easy to run containers in the cloud using either Amazon ECS or Microsoft ACI. 

### Upgrades

- [Docker Compose 1.27.2](https://github.com/docker/compose/releases/tag/1.27.2)
- [Cloud integration v0.1.15](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.15)

### Bug fixes and minor changes

- WSL2: Fixed a crash when using an incompatible glibc. See [docker/for-win#8183](https://github.com/docker/for-win/issues/8183).

### Known issues

- The `clock_gettime64` system call returns `EPERM` rather than `ENOSYS`
  in i386 images. To work around this issue, disable `seccomp` by using
  the `--privileged` flag. See [docker/for-win#8326](https://github.com/docker/for-win/issues/8326).

## Docker Desktop Community 2.3.0.4
2020-07-27

### Upgrades

- [Docker 19.03.12](https://github.com/docker/docker-ce/releases/tag/v19.03.12)
- [Docker Compose 1.26.2](https://github.com/docker/compose/releases/tag/1.26.2)
- [Go 1.13.14](https://github.com/golang/go/issues?q=milestone%3AGo1.13.14+label%3ACherryPickApproved)

### Bug fixes and minor changes

- Docker Desktop now prompts users to share directories for paths like `////c/Users/foo`, rather than only paths like `C:\Users\foo` and `C:/Users/foo`.
- The installer now returns a non-zero exit code on error, or when the user cancels the installation.
- Fixed the path to the installer log file default location when the username contains a space. Fixes [docker/for-win#6552](https://github.com/docker/for-win/issues/6552)
- Dashboard: Fixed opening a CLI for Windows containers. See [docker/for-win#7079](https://github.com/docker/for-win/issues/7079)
- Dashboard: Fixed containers logs which were sometimes truncated. Fixes [docker/for-win#5954](https://github.com/docker/for-win/issues/5954)
- WSL 2: Fixed an issue where changing the user's default shell blocked WSL integration. Fixes [docker/for-win#7653](https://github.com/docker/for-win/issues/7653)
- WSL 2: Fixed an issue to recover WSL distributions stuck in the "Installing" state.

## Docker Desktop Community 2.3.0.3
2020-05-27

### Upgrades

- [Linux kernel 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-83885d3b4cff391813f4262099b36a529bca2df8-amd64/images/sha256-0214b82436af70054e013ea51cb1fea72bd943d0d6245b6521f1ff09a505c40f?context=repo)

### Bug fixes and minor changes

- Fixed a crash when resetting to factory defaults with Hyper-V disabled. Fixes [docker/for-win#6738](https://github.com/docker/for-win/issues/6738).
- Fixed opening an application in VS Code from a WSL 2 running app. Fixes [docker/for-win#6472](https://github.com/docker/for-win/issues/6472).
- Fixed Swarm mounts in WSL 2. Fixes [docker/for-win#6507](https://github.com/docker/for-win/issues/6507).
- Fixed a bug when using the Microsoft `mssql` image. Fixes [docker/for-win#6646](https://github.com/docker/for-win/issues/6646)
- Implemented `fallocate` for shared file systems. See [docker/for-win#6658](https://github.com/docker/for-win/issues/6658#issuecomment-627736820)
- Fixed an installer crash when an old and/or partially uninstalled version of Docker Desktop was present on the system. Fixes [docker/for-win#6536](https://github.com/docker/for-win/issues/6536).
- Fixed a delay caused when opening the systray menu. Fixes [docker/for-win#1011](https://github.com/docker/for-win/issues/1011).
- Fixed a regression where containers couldn’t anymore refer to mounted folders using the host drive letters. Fixes [docker/for-win#6628](https://github.com/docker/for-win/issues/6628).
- Fixed a regression where sharing a folder using a double leading slash notation would fail. Fixes [docker/for-win#6668](https://github.com/docker/for-win/issues/6668).
- Re-added device-mapper to the embedded Linux kernel. Fixes [docker/for-mac#4549](https://github.com/docker/for-mac/issues/4549).
- Fixed an issue which caused the `:z` attribute in bind mounts to fail. Fixes [docker/for-win#6634](https://github.com/docker/for-win/issues/6634).

## Docker Desktop Community 2.3.0.2
2020-05-11

### New

- Windows 10 Home users can now use Docker Desktop through WSL 2. This requires Windows 10, version 2004 or higher. For more information, see [Install Docker Desktop on Windows](../setup/install/windows-install.md).
- Docker Desktop introduces a new onboarding tutorial upon first startup. The Quick Start tutorial guides users to get started with Docker in a few easy steps. It includes a simple exercise to build an example Docker image, run it as a container, push and save the image to Docker Hub.
- Docker Desktop now allows sharing individual folders, rather than whole drives, giving more control to users over what is being shared.

### Upgrades

- [Docker Compose 1.25.5](https://github.com/docker/compose/releases/tag/1.25.5)
- [Go 1.13.10](https://github.com/golang/go/issues?q=milestone%3AGo1.13.10+label%3ACherryPickApproved)
- [Linux kernel 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-ce15f646db9b062dc947cfc0c1deab019fa63f96-amd64/images/sha256-6c252199aee548e4bdc8457e0a068e7d8e81c2649d4c1e26e4150daa253a85d8?context=repo)
- LinuxKit [init](https://hub.docker.com/layers/linuxkit/init/1a80a9907b35b9a808e7868ffb7b0da29ee64a95/images/sha256-64cc8fa50d63940dbaa9979a13c362c89ecb4439bcb3ab22c40d300b9c0b597e?context=explore), [runc](https://hub.docker.com/layers/linuxkit/runc/69b4a35eaa22eba4990ee52cccc8f48f6c08ed03/images/sha256-57e3c7cbd96790990cf87d7b0f30f459ea0b6f9768b03b32a89b832b73546280?context=explore) and [containerd](https://hub.docker.com/layers/linuxkit/containerd/09553963ed9da626c25cf8acdf6d62ec37645412/images/sha256-866be7edb0598430709f88d0e1c6ed7bfd4a397b5ed220e1f793ee9067255ff1?context=explore)

### Bug fixes and minor changes

**WSL 2**

- Docker Desktop only exposes host ports in Linux if the Windows port is available.
- Docker Desktop now allows users to refresh the list of distributions.
- Docker Desktop defaults to WSL 2 on install on compatible OS versions.
- Docker Desktop detects missing Linux kernel and adds a pointer to the Microsoft documentation to download the kernel.
- Detect when the WSL 2 backend stops and allow the user to restart it.
- Added support for `chmod/chown` on WSL 2 bind mounts. Fixes [docker/for-win#6284](https://github.com/docker/for-win/issues/6284).
- Added a check that virtualization is enabled in the BIOS.

**Filesharing**

- Fixed a bug where renaming parent directories of shared folders led to spurious `File not found` errors. Fixes [docker/for-win#6200](https://github.com/docker/for-win/issues/6200).
- Fixed bug where a letter and two digit root folder name causes docker-compose to fail creating directories inside the volume. Fixes [docker/for-win#6248](https://github.com/docker/for-win/issues/6248).
- Fixed a bug which prevented containers from seeing file updates on shared volumes, when under load and a container restarts. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530#issuecomment-608804192).
- Fixed a bug where host paths are incorrectly translated into VM paths. Fixes [docker/for-win#6209](https://github.com/docker/for-win/issues/6209).
- Fixed bug receiving file events on long paths (> 260 characters). Fixes [docker/for-win#6337](https://github.com/docker/for-win/issues/6337).
- Docker Desktop represents valid directory junctions as directories (rather than symlinks) and handles cache invalidation and event injection properly. Fixes [docker/for-win#5582](https://github.com/docker/for-win/issues/5582).

**Other fixes**

- Reduced the size of the Docker Desktop installer from 960 MB to 409 MB.
- Added an option to delete data from the Troubleshoot screen.
- Fixed a bug where containers disappeared from the UI when Kubernetes context is invalid. Fixed [docker/for-win#6037](https://github.com/docker/for-win/issues/6037).
- Fixed Windows event logs filtering when copying them to the Docker Desktop log files. Fixed [docker/for-win#6258](https://github.com/docker/for-win/issues/6258).
- Fixed a handle leak in `vpnkit-bridge`. Fixed [docker/for-win#5841](https://github.com/docker/for-win/issues/5841)
- Fixed bug when removing Docker Desktop virtual switch.
- Added a link to the Edge channel from the UI.
- Made the embedded terminal resizable.
- Fixed a bug which only respected the `expose on TCP` Docker engine API setting on application restart. Setting will now take effect when the Apply button is clicked.
- Fixed a bug where diagnostic upload would fail if the username contained spaces.
- Docker Desktop now reads the Hyper-V VM disk max size on startup and uses it as the value to display in the Settings.
- Fixed a bug where the Docker Desktop UI could be started without the engine. Fixes [docker/for-win#5376](https://github.com/docker/for-win/issues/5376).
- Docker Desktop now uses the least possible privilege for querying the Server service. Fixes [docker/for-win#5150](https://github.com/docker/for-win/issues/5150).
- Fixed an issue where a container port could not be exposed on a specific host IP. See [docker/for-win#5546](https://github.com/docker/for-mac/issues/5546).
- Removed port probing from dashboard, just unconditionally showing links to ports that should be available. Fixes [docker/for-win#5903](https://github.com/docker/for-win/issues/5903).
- Ceph support has been removed from Docker Desktop to save disk space.
- Fixed an issue that caused the Windows log file archive to grow indefinitely. Fixes [docker/for-win#5113](https://github.com/docker/for-win/issues/5113).
- Added a prerequisite check in the installer for the LanmanServer service. Fixes [docker/for-win#5150](https://github.com/docker/for-win/issues/5150)

### Known issues

- Some CLI commands fail if you are running Docker Desktop in the experimental Linux Containers on Windows (LCOW) mode. As alternatives, we recommend running either traditional Linux containers, or the [WSL 2 backend](../features/wsl/index.md).

**WSL 2**

- Swarm service bind mounts are not always restored correctly.
- Bind mounts of files living outside of the root mount point (files within `/mnt/c`, `/tmp`, `/run...`) don't work correctly when multiple containers mount them.

## Docker Desktop Community 2.2.0.5
2020-04-02

### Bug fixes and minor changes

- Docker Desktop generates `fsnotify.WRITE` events in Linux containers when files are changed on the host. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530#issuecomment-585572414).
- Fixed a race condition in `readlink` on shared volumes using "mfsymlinks". Fixes [docker/for-win#5793](https://github.com/docker/for-win/issues/5793).
- Made the VM time sync more reliable. See [docker/for-win#4526](https://github.com/docker/for-win/issues/4526).
- Fixed bug where files did not change in shared volumes when using `volumes_from` in `docker-compose.yml`. See [docker/for-win#5530](https://github.com/docker/for-win/issues/5530).
- Fixed a bug where opening a read-only file would fail with an `Operation not permitted` error. Fixes [docker/for-win#6016](https://github.com/docker/for-win/issues/6016) and [docker/for-win#6017](https://github.com/docker/for-win/issues/6017).

## Docker Desktop Community 2.2.0.4
2020-03-13

### Upgrades

- [Docker 19.03.8](https://github.com/docker/docker-ce/releases/tag/v19.03.8)

### Bug fixes and minor changes

- Security: Diagnostics were collected with Administrator privileges, which led to a possible privilege escalation on systems where the Docker Desktop user was not an administrator.
- Docker Desktop now displays hidden files in shared volumes. Fixes [docker/for-win#5808](https://github.com/docker/for-win/issues/5808).
- Docker Desktop now generates the inotify `MODIFY` events on shared file systems for Windows file sharing. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530).
- Attempts to create files in a shared volume with an identical filename but a different case (uppercase/lowercase) on Windows filesystem will now fail with the error `EEXIST`. Fixes [docker/for-win#5894](https://github.com/docker/for-win/issues/5894).
- Fixed cache invalidation and event injection in shared volumes with host paths longer than 260 characters.
- Docker Desktop now allows users to rename open files in shared volumes. Fixes [docker/for-win#5565](https://github.com/docker/for-win/issues/5565).
- Fixed an issue which caused Docker Desktop Dashboard to attempt connecting to all exposed ports inside a container. Fixes [docker/for-win#5903](https://github.com/docker/for-win/issues/5903).
- Kubernetes: Persistent volumes created by claims are now stored in the virtual machine. Fixes [docker/for-win#5665](https://github.com/docker/for-win/issues/5665).
- Fixed an issue which caused Docker Desktop to hang when users tried to reset to factory defaults.
- Fixed a file sharing issue that caused Docker Desktop to lock random files. Fixes [docker/for-win#5624](https://github.com/docker/for-win/issues/5624) and [docker/for-win#5575](https://github.com/docker/for-win/issues/5575).

### Known issues

- Some CLI commands fail if you are running Docker Desktop in the experimental Linux Containers on Windows (LCOW) mode. As alternatives, we recommend running either traditional Linux containers, or the experimental [WSL backend](../features/wsl/index.md).
- It is not possible to resize the disk image using the Docker Desktop **Settings** UI. If you would like to update the size of the disk image (for example, to 128 GB), run the following command in PowerShell:

  ```powershell
  Resize-VHD -Path 'C:\ProgramData\DockerDesktop\vm-data\DockerDesktop.vhdx' -SizeBytes 128gb
  ```

## Docker Desktop Community 2.2.0.3
2020-02-11

### Upgrades

- [Docker Compose 1.25.4](https://github.com/docker/compose/releases/tag/1.25.4)
- [Go 1.12.16](https://golang.org/doc/devel/release.html#go1.12)

### Bug fixes and minor changes

- Fixed an issue that prevented users from creating files with special characters in the filenames within a shared volume. Fixes [docker/for-win#5520](https://github.com/docker/for-win/issues/5520).
- Fixed handling of shared volumes with relative paths in `docker-compose.yml`. Fixes [docker/for-win#5516](https://github.com/docker/for-win/issues/5516).
- Fixed handling of shared volumes where the path case (uppercase / lowercase) did not exactly match the host. Fixes [docker/for-win#5516](https://github.com/docker/for-win/issues/5516).
- Fixed an issue where changing a file in the Windows file system did not update the file within the container. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530) and [docker/for-win#5550](https://github.com/docker/for-win/issues/5550).
- Fixed an issue that prevented users from sharing drives and sometimes incorrectly prompted users to enter file system credentials. Fixes [docker/for-win#5567](https://github.com/docker/for-win/issues/5567).
- Fixed an issue which prevented users from mounting nested volumes. Fixes [docker/for-win#5540](https://github.com/docker/for-win/issues/5540).
- Fixed a file synchronization issue on bind mounts. Fixes [docker/for-win#5533](https://github.com/docker/for-win/issues/5533).
- Fixed an issue where timestamps were reset to zero on files within shared volumes. Fixes [docker/for-win#5528](https://github.com/docker/for-win/issues/5528) and [docker/for-win#5543](https://github.com/docker/for-win/issues/5543).
- Fixed a bug which caused Docker Desktop to fail when sharing file paths longer than 260 characters. Fixes [docker/for-win#5572](https://github.com/docker/for-win/issues/5572).
- Fixed an issue where some users were unable to start a container if there is a symlink in a shared volume. Fixes [docker/for-win#5582](https://github.com/docker/for-win/issues/5582).
- Fixed a bug where users were unable to modify the **Manual proxy configuration** settings through the Docker Desktop UI. Fixes [docker/for-win#5606](https://github.com/docker/for-win/issues/5606) and [docker/for-win#5548](https://github.com/docker/for-win/issues/5548).
- Fixed an issue where the Docker Desktop UI failed to start if the `no_proxy` environment variable has an entry that starts with a dot (.). Fixes [docker/for-win/5551](https://github.com/docker/for-win/issues/5551).
- Fixed a bug that did not allow users to access the Docker Desktop UI on machines with a policy preventing access to the Windows registry. Fixes [docker/for-win#5536](https://github.com/docker/for-win/issues/5536).
- Fixed an issue where disabling the WSL2 integration and re-enabling it later resulted in broken symlinks. Fixes [docker/for-win#5613](https://github.com/docker/for-win/issues/5613).
- Fixed a race condition when starting the WSL engine which caused Docker Desktop to incorrectly report that the containers have exited. Fixes [docker/for-win#5607](https://github.com/docker/for-win/issues/5607).
- Fixed an issue where editing code inside a container resulted in an error. Fixes [docker/for-win#5528](https://github.com/docker/for-win/issues/5528).
- Fixed a bug where running the command `DockerCli.exe -SharedDrives` failed to display a list of drives that are shared. Fixes [docker/for-win#5625](https://github.com/docker/for-win/issues/5625).
- Starting with Docker Desktop 2.2.0.3, you must access all shared files using their original case. For example, if you have created a file called `test`, you must open it as `test`. Attempts to open the file as `Test` will fail with the error `No such file or directory`. For more information, see _Tips on shared drives, permissions, and volume mounts_ in [File sharing](../settings-and-maintenance/settings.md#file-sharing).

### Known issues

- DockerNAT has been removed from Docker Desktop 2.2.0.0 as using an IP address to communicate from the host to a container is not a supported feature. To communicate from a container to the host, you must use the special DNS name `host.docker.internal`. We also recommend using ports to communicate from the host to a container. For more information, see [Networking](/manuals/desktop/features/networking.md#use-cases-and-workarounds-for-all-platforms).

  However, if your current setup relies on IP addresses for communication, you can use a temporary workaround to reinstate DockerNAT. To do this, open
  `C:\Program Files\Docker\Docker\resources\MobyLinux.ps1` and add `$SwitchName = "DockerNAT"` between line 175 and 176. Note that the temporary workaround to reinstate DockerNAT may be removed from future releases.
- Directory junctions in shared volumes pointing outside the shared volume do not work.
- It is currently not possible to rename open files within shared volumes.
- In some cases, Docker containers do not synchronize time with the host when the host machine is put to sleep.
- It is not possible to use `localhost` in the proxy settings. You can instead use `host.docker.internal` to work around this issue.

## Docker Desktop Community 2.2.0.0
2020-01-21

Docker Desktop 2.2.0.0 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker Compose 1.25.2](https://github.com/docker/compose/releases/tag/1.25.2)
- [Kubernetes 1.15.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.15.5)
- Linux kernel 4.19.76
- [QEMU 4.0.1](https://github.com/docker/binfmt)

### New

- **Docker Desktop Dashboard:** The new Docker Desktop **Dashboard** provides a user-friendly interface which enables you to interact with containers and applications, and manage the lifecycle of your applications directly from the UI. In addition, it allows you to access the logs, view container details, and monitor resource utilization to explore the container behavior.
  For detailed information about the new Dashboard UI, see [Docker Desktop Dashboard](../index.md).

- **WSL 2 backend:** The experimental Docker Desktop WSL 2 backend architecture introduces support for Kubernetes, provides an updated Docker daemon, offers VPN-friendly networking, and additional features. For more information, see [Docker Desktop WSL 2 backend](../features/wsl/index.md).

- **New file sharing implementation:** Docker Desktop introduces a new file sharing implementation that replaces Samba, CIFS, and Hyper-V networking. The new implementation  offers improved I/O performance. Additionally, when using the new file system:

  - Users don't have to expose the Samba port, and therefore do not experience issues related to IT firewall or drive-sharing policy.
  - There is no need to provide user credentials to Docker Desktop. File access rights are automatically enforced when accessing mounted folders through containers.

    For more information, see the blog post [New file sharing implementation in Docker Desktop Windows](https://www.docker.com/blog/new-filesharing-implementation-in-docker-desktop-windows/).

- Added the **WSL Integration** option in **Settings** > **Resources** to select WSL 2 distributions. This option will be visible only after enabling WSL 2 on your machine.
- Introduced a new user interface for the Docker Desktop **Settings** menu.
- The Restart, Reset, and Uninstall options are now available on the **Troubleshoot** menu.
- Added the ability to start and stop existing Compose-based applications and view combined logs in the Docker Desktop **Dashboard** UI.

### Bug fixes and minor changes

- Enabled Windows features such as Hyper-V and Containers during installation, thereby reducing the need for another restart after installation.
- Added support for `Expect: 100-continue` headers in the Docker API proxy. Some HTTP clients such as `curl` send this header when the payload is large, for example, when creating containers. Fixes [moby/moby#39693](https://github.com/moby/moby/issues/39693).
- Added a loading overlay to the **Settings** and **Troubleshoot** windows to prevent editing conflicts.
- Deactivated the **Reset Kubernetes** button when Kubernetes is not activated.
- Improved the navigation in **Settings** and **Troubleshoot** UI.
- Docker Machine is no longer included in the Docker Desktop installer. You can download it separately from the [Docker Machine releases](https://github.com/docker/machine/releases) page.
- Docker Desktop now automatically restarts after an update.
- Fixed an issue where Docker Desktop auto-start was not being disabled properly on some machines.
- Fixed a container start error when a container has more than one port with an arbitrary or not-yet-configured external port number. For example, `docker run -p 80 -p 443 nginx`). Fixes [docker/for-win#4935](https://github.com/docker/for-win/issues/4935) and [docker/compose#6998](https://github.com/docker/compose/issues/6998).
- Fixed an issue which caused Docker Desktop to crash when resetting to factory defaults while running Windows containers.
- Fixed multiple issues related to Fast Startup.
- Docker Desktop now supports `inotify` events on shared filesystems.
- Docker Desktop startup is now more reliable and does not clash with host firewall software.
- Fixed a rare issue that caused to Docker Desktop to crash with the error `Unable to stop Hyper-V VM: Cannot validate argument on parameter 'SwitchName'. The argument is null or empty.`
- Fixed a bug that caused a rare crash when uninstalling Docker Desktop.
- Fixed an issue that caused Docker Desktop to fail on startup when there is an incomplete Kubernetes config file.
- Fixed various stability issues.

### Known issues

- When you start a Docker Compose application and then start a Docker App which has the same name as the Compose application, Docker Desktop displays only one application on the Dashboard. However, when you expand the application, containers that belong to both applications are displayed on the Dashboard.
- When you deploy a Docker App with multiple containers on Kubernetes, Docker Desktop displays each Pod as an application on the Dashboard.
- WSL 2 requires Windows 10 Insider Preview build 19018 or greater.
- The Dashboard stops updating when you switch the container mode between Linux and Windows. To work around this issue, close and reopen the Dashboard.
- The new gRPC FUSE file sharing implementation does not support connecting to new drives (for example, USB drives) added after Docker Desktop starts. If you would like to share the new drive in Docker Desktop, you must quit Docker Desktop and then start the application to refresh the list of drives in Settings.
- Sharing files from virtual drives created by `ImDisk Toolkit` does not work.

## Docker Desktop Community 2.1.0.5
2019-11-18

Docker Desktop 2.1.0.5 contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker 19.03.5](https://github.com/docker/docker-ce/releases/tag/v19.03.5)
- [Kubernetes 1.14.8](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.8)
- [Go 1.12.13](https://golang.org/doc/devel/release.html#go1.12)

## Docker Desktop Community 2.1.0.4
2019-10-21

Docker Desktop 2.1.0.4 contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker 19.03.4](https://github.com/docker/docker-ce/releases/tag/v19.03.4)
- [Kubernetes 1.14.7](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.7)
- [Go 1.12.10](https://github.com/golang/go/issues?q=milestone%3AGo1.12.10+label%3ACherryPickApproved)
- [Kitematic 0.17.9](https://github.com/docker/kitematic/releases/tag/v0.17.9)

### New

Docker Desktop now enables you to sign into Docker Hub using two-factor authentication.

## Docker Desktop Community 2.1.0.3
2019-09-16

### Upgrades

- [Kitematic 0.17.8](https://github.com/docker/kitematic/releases/tag/v0.17.8)

## Docker Desktop Community 2.1.0.2
2019-09-04

Docker Desktop 2.1.0.2 contains a Kubernetes upgrade. Your local Kubernetes cluster will be reset after installing this version.

### Upgrades

- [Docker 19.03.2](https://github.com/docker/docker-ce/releases/tag/v19.03.2)
- [Kubernetes 1.14.6](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.6)
- [Go 1.12.9](https://github.com/golang/go/issues?q=milestone%3AGo1.12.9+label%3ACherryPickApproved)
- [Docker Machine 0.16.2](https://github.com/docker/machine/releases/tag/v0.16.2)

## Docker Desktop Community 2.1.0.1
2019-08-08

Note that you must sign in and create a Docker ID in order to download Docker Desktop.

### Upgrades

* [Docker 19.03.1](https://github.com/docker/docker-ce/releases/tag/v19.03.1)
* [Docker Compose 1.24.1](https://github.com/docker/compose/releases/tag/1.24.1)
* [Kubernetes 1.14.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.3)
* [Compose on Kubernetes 0.4.23](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.23)
* [Docker Machine 0.16.1](https://github.com/docker/machine/releases/tag/v0.16.1)
* [linuxkit v0.7](https://github.com/linuxkit/linuxkit/releases/tag/v0.7)
* Linux Kernel 4.9.184
* [Kitematic 0.17.6](https://github.com/docker/kitematic/releases/tag/v0.17.6)
* [Qemu 4.0.0](https://github.com/docker/binfmt) for cross compiling for ARM
* [Alpine 3.10](https://alpinelinux.org/posts/Alpine-3.10.0-released.html)
* [Docker Credential Helpers 0.6.3](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.3)

### New

* Selecting the ‘Experimental features’ checkbox in the Daemon, **Settings** menu turns on experimental features for Docker daemon and Docker CLI.
* Docker Desktop now checks for stored credentials at startup before attempting to mount any shared drives. This prompts users to reenter the credentials if they are invalid.

### Experimental

> Experimental features provide early access to future product functionality. These features are intended for testing and feedback only as they may change between releases without warning or can be removed entirely from a future release. Experimental features must not be used in production environments. Docker does not offer support for experimental features.

Docker Desktop Community 2.1.0.0 contains the following experimental features:

* Docker App: Docker App is a CLI plugin that helps configure, share, and install applications.
* Docker Buildx: Docker Buildx is a CLI plugin for extended build capabilities with BuildKit. For more information, see the [Build page](../../build/index.md).

### Bug fixes and minor changes

* Fixed PowerShell script signing issue that caused `AuthorizationManager check failed` errors on machines with strict group policies on PowerShell script signing. [docker/for-win#4376](https://github.com/docker/for-win/issues/4376)
* Fixed an issue where users were unable to start Docker Desktop after upgrading to version 2.1.0.0. [docker/for-win#4390](https://github.com/docker/for-win/issues/4390)
* Fixed an issue where attempts to upgrade Docker Desktop to version 2.1.0.0 sometimes failed with the error `value cannot be null`. [docker/for-win#4343](https://github.com/docker/for-win/issues/4343)
* Fixed an issue that caused the installer to hang when upgrading Docker Desktop to version 2.1.0.0. [docker/for-win#4387](https://github.com/docker/for-win/issues/4387)
* Improved the error messages displayed during VM lifecycle operations. [docker/for-win#4348](https://github.com/docker/for-win/issues/4348)
* Docker Desktop now supports a configurable user timeout for VMs on slower machines. [docker/for-win#4393](https://github.com/docker/for-win/issues/4393)
* Restricted the `cluster-admin` role on local Kubernetes cluster to `kube-system` namespace.
* Reduced the VM startup time. swap is not created every time a virtual machine boots.
* Fixed a bug which caused Windows to crash when a user cancels switching the version using Windows User Account Control (UAC) settings.
* Fixed an issue where Docker Desktop restarts when a user logs out of Windows and logs back in, which results in retaining the exported ports on containers.
* Fixed Kubernetes installation with VPNkit subnet.
* Fixed a bug where the process output was not redirected to stdout when gathering diagnostics on Windows, which sometimes resulted in a crash.
* Fixed race condition where Kubernetes sometimes fails to start after the app is restarted.
* The system tray icon now opens the Docker Desktop menu with left and right mouse button.
* When displaying the crash report window, Docker Desktop does not send a bugsnag crash report unless the user needs the report to upload diagnostics.
* Docker Desktop has removed the ability to log in using email address as a username as the Docker command line does not support this.
* For Linux containers on Windows (LCOW), the host must run Windows 10 Professional or Windows 10 Enterprise version 1809 or later.
* The **Send usage statistics** checkbox is selected by default in Docker Desktop for Windows Community. This option cannot be modified.
* Docker Desktop has added a new dialog box during startup which allows users to retry mounting a shared drive or remove it from the shared drives list after a failed attempt.
* Fixed the Kubernetes Delete operation of persistent volume claims on Windows.
* Docker Desktop now truncates UDP DNS responses which are over 512 bytes in size.
* Fixed a bug where Docker was not added to PATH after installation in some cases.
* Fixed port 8080 that was used on localhost when starting Kubernetes.
* Renamed the product from **Docker for Windows** to **Docker Desktop**.
* Fixed the **Create issue** link in the Diagnostics window.
* Fixed a bug related to service log collection in diagnostics.
* Docker Desktop now gathers `/etc/hosts` to help with diagnostics.
* Added the missing daemon options in Docker Engine 18.09.
* When two services have a common exposed port, Docker Desktop exposes the available ports for the second service.
* Fixed the UI lock when changing the Kubernetes state.

### Docker Community Edition 2.0.0.3 2019-02-15

* Upgrades
  - [Docker 18.09.2](https://github.com/docker/docker-ce/releases/tag/v18.09.2), fixes [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736)

* Bug fix
  - Fix crash in system tray menu when the Hub login fails or Air gap mode

### Docker Community Edition 2.0.0.2 2019-01-16

* Upgrades
  - [Docker 18.09.1](https://github.com/docker/docker-ce/releases/tag/v18.09.1)
  - [Docker Machine 0.16.1](https://github.com/docker/machine/releases/tag/v0.16.1)
  - [Kubernetes 1.10.11](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.10.md#v11011), fixes [CVE-2018-1002105](https://github.com/kubernetes/kubernetes/issues/71411)
  - [Kitematic 0.17.6](https://github.com/docker/kitematic/releases/tag/v0.17.6)
  - Golang 1.10.6, fixes CVEs: [CVE-2018-16875](https://www.cvedetails.com/cve/CVE-2018-16875), [CVE-2018-16873](https://www.cvedetails.com/cve/CVE-2018-16873) and [CVE-2018-16874](https://www.cvedetails.com/cve/CVE-2018-16874)
  - Windows 14393 is marked as deprecated ; it will not be supported anymore in the next major stable release (2.1.0.0 and further)

* Bug fixes and minor changes
  - Rename Docker for Windows to Docker Desktop
  - Add 18.09 missing daemon options

### Docker Community Edition 2.0.0.0-win81 2018-12-07

* Upgrades
  - [Docker compose 1.23.2](https://github.com/docker/compose/releases/tag/1.23.2)

* Bug fixes and minor changes
  - Compose: Fixed a bug where build context URLs would fail to build on Windows. Fixes [docker/for-win#2918](https://github.com/docker/for-win/issues/2918)

### Docker Community Edition 2.0.0.0-win78 2018-11-19

* Upgrades
  - [Docker 18.09.0](https://github.com/docker/docker-ce-packaging/releases/tag/v18.09.0)
  - [Docker compose 1.23.1](https://github.com/docker/compose/releases/tag/1.23.1)
  - [Docker Machine 0.16.0](https://github.com/docker/machine/releases/tag/v0.16.0)
  - [Kitematic 0.17.5](https://github.com/docker/kitematic/releases/tag/v0.17.5)
  - Linux Kernel 4.9.125

* New
  - New version scheme

* Deprecation
  - Removed support of AUFS

* Bug fixes and minor changes
  - Windows Containers: Fix group daemon option settings. Fixes [docker/for-win#2647](https://github.com/docker/for-win/issues/2647)
  - Windows Containers: Better host.docker.internal resolution, don't rewrite it if not modified. From [docker/for-win#1976](https://github.com/docker/for-win/issues/1976)
  - Do not try to update samba share mounts when using Windows Containers
  - Improved dns update too verbose in logs
  - VPNKit: Improved scalability of port forwarding.
  - VPNKit: Limit the size of the UDP NAT table. This ensures port forwarding and regular TCP traffic continue even when running very chatty UDP protocols.
  - LCOW does not need --platform flag on multi-arch images any more
  - Disk size can now be adjusted from 32GiB to drive space.
  - Fix dns update too verbose in logs
  - Fix panic in diagnose


---

# Docker Desktop for Mac 3.x release notes

*Sección: Desktop*

This page contains release notes for Docker Desktop for Mac 3.x. 

## Docker Desktop 3.6.0
2021-08-11

### New

- **Dev Environments**: You can now create a Dev Environment from your local Git repository. 
- **Volume Management**: You can now sort volumes by the name, the date created, and the size of the volume. You can also search for specific volumes using the **Search** field. For more information, see [Explore volumes](../use-desktop/volumes.md).

### Upgrades

- [Compose V2 RC1](https://github.com/docker/compose-cli/releases/tag/v2.0.0-rc.1)
  - Docker compose command line completion.
  - Allow setting 0 scale/replicas.
  - Detect new container on logs —follow.
- [Go 1.16.7](https://github.com/golang/go/releases/tag/go1.16.7)
- [Docker Engine 20.10.8](../../engine/release-notes/20.10.md#20108)
- [containerd v1.4.9](https://github.com/containerd/containerd/releases/tag/v1.4.9)
- [runc v1.0.1](https://github.com/opencontainers/runc/releases/tag/v1.0.1)
- [Kubernetes 1.21.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.3)
- [Linux kernel 5.10.47](https://hub.docker.com/layers/docker/for-desktop-kernel/5.10.47-0b705d955f5e283f62583c4e227d64a7924c138f/images/sha256-a4c79bc185ec9eba48dcc802a8881b9d97e532b3f803d23e5b8d4951588f4d51?context=repo)

### Bug fixes and minor changes

- Update kernel configuration to fix a performance regression in [Docker Desktop 3.0.0](#docker-desktop-300)
  that caused publishing container ports to take 10 times longer than on older
  versions. For more information, see [linuxkit/linuxkit#3701](https://github.com/linuxkit/linuxkit/pull/3701)
  and [docker/for-mac#5668](https://github.com/docker/for-mac/issues/5668).
- Fixed a bug where the DNS server would fail after receiving an unexpectedly large datagram.
- Fixed an issue related to hardware acceleration [docker/for-mac#5121](https://github.com/docker/for-mac/issues/5121)
- Fixed an issue related to Skip This Update for mac [docker/for-mac#5842](https://github.com/docker/for-mac/issues/5842)

## Docker Desktop 3.5.2
2021-07-08

### New

**Dev Environments Preview**: Dev Environments enable you to seamlessly collaborate with your team members without moving between Git branches to get your code onto your team members' machines. When using Dev Environments, you can share your in-progress work with your team members in just one click, and without having to deal with any merge conflicts.

### Upgrades

- [Compose V2 beta 6](https://github.com/docker/compose-cli/releases/tag/v2.0.0-beta.6)
  - `compose run` and `compose exec` commands use separate streams for stdout and stderr. See [docker/compose-cli#1873](https://github.com/docker/compose-cli/issues/1873).
  - `compose run` and `compose exec` commands support detach keys. Fixes [docker/compose-cli#1709](https://github.com/docker/compose-cli/issues/1709).
  - Fixed `--force` and `--volumes` flags on `compose rm` command. See [docker/compose-cli#1844](https://github.com/docker/compose-cli/issues/1844).
  - Fixed network's IPAM configuration. Service can define a fixed IP. Fixes for [docker/compose-cli#1678](https://github.com/docker/compose-cli/issues/1678) and [docker/compose-cli#1816](https://github.com/docker/compose-cli/issues/1816)

- Dev Environments
  - Support VS Code Insiders. 
  - Allow users to specify a branch when cloning a project. 

### Bug fixes and minor changes

- Dev Environments: Fixed a blank screen in some create and remove scenarios. Fixes [dev-environments#4](https://github.com/docker/dev-environments/issues/4)
- Dev Environments: Fixed error handling when removing an environment. Fixes [dev-environments#8](https://github.com/docker/dev-environments/issues/8)
- Dev Environments: The **Start**, **Stop**, and **Share** buttons are disabled while an environment is being created or removed.
- Fixed a connection leak when using `virtualization.framework` and not using `vpnkit`.
- Fixed spurious traces on iptables updates.
- Fixed a delay when adding a multiple port forwarding option.

## Docker Desktop 3.5.1
2021-06-25

### New

**Dev Environments Preview**: Dev Environments enable you to seamlessly collaborate with your team members without moving between Git branches to get your code onto your team members' machines. When using Dev Environments, you can share your in-progress work with your team members in just one click, and without having to deal with any merge conflicts.

**Compose V2 beta**: Docker Desktop now includes the beta version of Compose V2, which supports the `docker compose` command as part of the Docker CLI. While `docker-compose` is still supported and maintained, Compose V2 implementation relies directly on the compose-go bindings which are maintained as part of the specification. The compose command in the Docker CLI supports most of the `docker-compose` commands and flags. It is expected to be a drop-in replacement for `docker-compose`. There are a few remaining flags that have yet to be implemented, see the docker-compose compatibility list for more information about the flags that are supported in the new compose command. If you run into any problems with Compose V2, you can easily switch back to Compose v1 by either by making changes in Docker Desktop **Experimental** Settings, or by running the command `docker-compose disable-v2`. Let us know your feedback on the new ‘compose’ command by creating an issue in the [Compose-CLI](https://github.com/docker/compose-cli/issues) GitHub repository.

### Bug fixes and minor changes

- Fixed a link to the policy that provides details on how Docker handles the uploaded diagnostics data. Fixes [docker/for-mac#5741](https://github.com/docker/for-mac/issues/5741)

## Docker Desktop 3.5.0
2021-06-23

### New

**Dev Environments Preview**: Dev Environments enable you to seamlessly collaborate with your team members without moving between Git branches to get your code onto your team members' machines. When using Dev Environments, you can share your in-progress work with your team members in just one click, and without having to deal with any merge conflicts.

**Compose V2 beta**: Docker Desktop now includes the beta version of Compose V2, which supports the `docker compose` command as part of the Docker CLI. While `docker-compose` is still supported and maintained, Compose V2 implementation relies directly on the compose-go bindings which are maintained as part of the specification. The compose command in the Docker CLI supports most of the `docker-compose` commands and flags. It is expected to be a drop-in replacement for `docker-compose`. There are a few remaining flags that have yet to be implemented, see the docker-compose compatibility list for more information about the flags that are supported in the new compose command. If you run into any problems with Compose V2, you can easily switch back to Compose v1 by either by making changes in Docker Desktop **Experimental** Settings, or by running the command `docker-compose disable-v2`. Let us know your feedback on the new ‘compose’ command by creating an issue in the [Compose-CLI](https://github.com/docker/compose-cli/issues) GitHub repository.

### Upgrades

- [Compose V2 beta](https://github.com/docker/compose-cli/releases/tag/v2.0.0-beta.4)
  - Fixed a bug where a container cannot be started when a file is bind-mounted into a nested mountpoint. Fixes [docker/compose-cli#1795](https://github.com/docker/compose-cli/issues/1795).
  - Added support for container links and external links.
  - Introduced the `docker compose logs --since --until` option.
  - `docker compose config --profiles` now lists all defined profiles.
- From [Kubernetes 1.21.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.1) to [Kubernetes 1.21.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.2)

### Bug fixes and minor changes

- **Volume Management**
  - Users can now remove a file or directory inside a volume using the Docker Dashboard.
  - The **Volumes** view in Docker Dashboard displays the last modified time and the size of the contents inside a volume.
  - Users can save the files and directories inside a volume from Docker Dashboard.
- Fixed a bug that caused Docker to fail to start because `/usr/bin` was not present on the `PATH`. Fixes [docker/for-mac#5770](https://github.com/docker/for-mac/issues/5770)
- Docker Desktop now allows files to be modified inside a host directory which is a nested mountpoint in a container. Fixes [docker/for-mac#5748](https://github.com/docker/for-mac/issues/5748).
- Fixed a settings migration bug which caused Docker Desktop not to find images and containers data after upgrading to 3.4.0. Fixes [docker/for-mac#5754](https://github.com/docker/for-mac/issues/5754).
- Docker Desktop now highlights the architecture of the non-native images in the Docker Dashboard on Apple Silicon.
- Fix using virtualization.framework on macOS 12 (Monterey).
- The default `docker` CLI `context` is now `desktop-linux`.
- Show the Docker Desktop Feedback popup only when clicking Docker menu.

## Docker Desktop 3.4.0
2021-06-09

### New

**Volume Management**: Docker Desktop users can now create and delete volumes using the Docker Dashboard and also see which volumes are being used. For more information, see [Explore volumes](../use-desktop/volumes.md).

**Compose V2 beta**: Docker Desktop now includes the beta version of Compose V2, which supports the `docker compose` command as part of the Docker CLI. While `docker-compose` is still supported and maintained, Compose V2 implementation relies directly on the compose-go bindings which are maintained as part of the specification. The compose command in the Docker CLI supports most of the `docker-compose` commands and flags. It is expected to be a drop-in replacement for `docker-compose`. There are a few remaining flags that have yet to be implemented, see the docker-compose compatibility list for more information about the flags that are supported in the new compose command. If you run into any problems with Compose V2, you can easily switch back to Compose v1 by either by making changes in Docker Desktop **Experimental** Settings, or by running the command `docker-compose disable-v2`. Let us know your feedback on the new ‘compose’ command by creating an issue in the [Compose-CLI](https://github.com/docker/compose-cli/issues) GitHub repository.

**Skip Docker Desktop updates**: All users can now skip an update when they are prompted to install individual Docker Desktop releases.

### Deprecation

- Docker Desktop no longer installs Notary. You can now use [Docker Content Trust](../../engine/security/trust/index.md) for image signing.

### Upgrades

- [Docker Engine 20.10.7](../../engine/release-notes/20.10.md#20107)
- [Docker Compose 1.29.2](https://github.com/docker/compose/releases/tag/1.29.2)
- [Docker Hub Tool v0.4.1](https://github.com/docker/hub-tool/releases/tag/v0.4.1)
- [Compose CLI v1.0.16](https://github.com/docker/compose-cli/releases/tag/v1.0.16)
- [Kubernetes 1.21.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.1)
- [containerd v1.4.6](https://github.com/containerd/containerd/releases/tag/v1.4.6)
- [runc v1.0.0-rc95](https://github.com/opencontainers/runc/releases/tag/v1.0.0-rc95)
- [Go 1.16.5](https://github.com/golang/go/releases/tag/go1.16.5)

### Bug fixes and minor changes

- Prevent `docker run` from hanging if inotify event injection fails. Fixes [docker/for-mac#5590](https://github.com/docker/for-mac/issues/5590).
- Fixed error showing stderr log in the UI. Fixes [docker/for-mac#5688](https://github.com/docker/for-mac/issues/5688).
- Fixed an issue which caused `riscv64` emulation to fail on Docker Desktop. Fixes [docker/for-mac#5699](https://github.com/docker/for-mac/issues/5699).
- Automatically reclaim space after deleting containers by deleting volumes and removing build cache.
- Docker Desktop now allows a blank HTTP proxy to be configured for the Docker engine, which will completely disable the internal HTTP proxy. See [docker/for-mac#2467](https://github.com/docker/for-mac/issues/2467).
- Docker Compose applications with file names other than `docker-compose.yml` can now be removed from Docker Desktop. Fixes [docker/for-win#11046](https://github.com/docker/for-win/issues/11046)
- Docker Desktop now exposes the host CPU on Apple silicon. Fixes [docker/for-mac#5681](https://github.com/docker/for-mac/issues/5681).
- Avoid leaking open ports bound to privileged ports and specific IPs over engine Restart. Fixes [docker/for-mac#5649](https://github.com/docker/for-mac/issues/5649).
- Use `vpnkit` with `virtualization.framework` to fix connectivity issues with VPN clients such as Cisco AnyConnect.
- Fixed version number missing in update dialog window.
- Fixed an issue where the diagnostics were sometimes not uploaded correctly from the **Support** dialog.
- Fixed DNS entries for `*.docker.internal` and Kubernetes cluster reset after the VM IP changes. Fixes [docker/for-mac#5707](https://github.com/docker/for-mac/issues/5707), [docker/for-mac#5680](https://github.com/docker/for-mac/issues/5680), [docker/for-mac#5663](https://github.com/docker/for-mac/issues/5663) and [docker/for-mac#5653](https://github.com/docker/for-mac/issues/5653).
- Avoid running `com.docker.osxfs` when gRPC FUSE is enabled. Fixes [docker/for-mac#5725](https://github.com/docker/for-mac/issues/5725).

### Known issues

- On Apple Silicon in native `arm64` containers, older versions of `libssl` in `debian:buster`, `ubuntu:20.04` and `centos:8` will segfault when connected to some TLS servers, for example `curl https://dl.yarnpkg.com`. The bug is fixed in newer versions of `libssl` in `debian:bullseye`, `ubuntu:21.04` and `fedora:35`.

## Docker Desktop 3.3.3
2021-05-06

### Upgrades

- [Snyk v1.563.0](https://github.com/snyk/snyk/releases/tag/v1.563.0)
- [Docker Scan v0.8.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.8.0)

### Bug fixes and minor changes

- Fixed the diagnostics failing to upload from the Troubleshoot screen.

### Docker Desktop 3.3.2
2021-05-03

### Upgrades

- [Compose CLI v1.0.14](https://github.com/docker/compose-cli/tree/v1.0.14)
- [Go 1.16.3](https://golang.org/doc/go1.16)
- [Docker Compose 1.29.1](https://github.com/docker/compose/releases/tag/1.29.1)
- [Docker Engine 20.10.6](../../engine/release-notes/20.10.md#20106)

### Bug fixes and minor changes

- Fixed a bug with an Apple chip where the last byte in a network transfer was occasionally lost.
- Fixed a bug where a `metrics-port` defined in the engine's `daemon.json` blocks application restart.
- Fixed a leak of ephemeral ports. Fixes [docker/for-mac#5611](https://github.com/docker/for-mac/issues/5611).
- Emulate a more modern Intel CPU with `qemu` on an Apple chip, for better image compatibility. See [docker/for-mac#5561](https://github.com/docker/for-mac/issues/5561).
- Enable buildkit garbage collection by default.
- Fixed a bug which blocked binding to port 123. Fixes [docker/for-mac#5589](https://github.com/docker/for-mac/issues/5589).
- Disable the HTTP and HTTPS transparent proxies when there is no upstream proxy set. Fixes [docker/for-mac#5572](https://github.com/docker/for-mac/issues/5572).
- Revert to the HTTP and HTTPS proxy implementation used in 3.2.2.
- Removed the "Deploy Docker Stacks to Kubernetes by default" Kubernetes setting. The component was removed in 2.4.0.0 but we forgot to remove the setting. Fixes [docker/for-mac#4966](https://github.com/docker/for-mac/issues/4966).

## Docker Desktop 3.3.1
2021-04-15

### New

Docker Desktop is now available for Apple silicon as well as Intel chips. This enables developers with their choice of local development environments, and extends development pipelines for ARM-based applications. For more information, see [Docker Desktop for Apple silicon](../setup/install/mac-install.md).

### Bug fixes and minor changes

- Docker Desktop now ensures the permissions of `/dev/null` and other devices are correctly set to `0666` (`rw-rw-rw-`) inside `--privileged` containers. Fixes [docker/for-mac#5527](https://github.com/docker/for-mac/issues/5527)
- Fixed an issue that caused Docker Desktop to fail during startup when it is unable to establish a connection with Docker Hub in the backend. Fixes [docker/for-win#10896](https://github.com/docker/for-win/issues/10896)

- **Mac with Apple silicon**: Docker Desktop now reduces the idle CPU consumption.

### Known issues

**Apple silicon**

- `ping` from inside a container to the Internet does not work as expected. To test the network, we recommend using `curl` or `wget`. See [docker/for-mac#5322](https://github.com/docker/for-mac/issues/5322#issuecomment-809392861).
- Users may occasionally experience data drop when a TCP stream is half-closed.

## Docker Desktop 3.3.0
2021-04-08

You can now specify when to download and install a Docker Desktop update. When an update becomes available, Docker Desktop displays an icon to indicate the availability of a newer version. You can download the update in the background whenever convenient. When the download is complete, all you need to do is to click Update and restart to install the latest update.

Developers who use Docker Desktop for professional development purposes may at times need to skip a specific update. For this reason, users with a paid Docker subscription can skip notifications for a particular update when a reminder appears.

For developers in IT managed environments, who don’t have administrative access to install updates to Docker Desktop, there is now an option in the Settings menu to opt out of notifications altogether for Docker Desktop updates if your Docker ID is part of a Team subscription.

### Upgrades

- [Docker Compose 1.29.0](https://github.com/docker/compose/releases/tag/1.29.0)
- [Compose CLI v1.0.12](https://github.com/docker/compose-cli/tree/v1.0.12)
- [Linux kernel 5.10.25](https://hub.docker.com/layers/docker/for-desktop-kernel/5.10.25-6594e668feec68f102a58011bb42bd5dc07a7a9b/images/sha256-80e22cd9c9e6a188a785d0e23b4cefae76595abe1e4a535449627c2794b10871?context=repo)
- [Snyk v1.461.0](https://github.com/snyk/snyk/releases/tag/v1.461.0)
- [Docker Hub Tool v0.3.1](https://github.com/docker/hub-tool/releases/tag/v0.3.1)
- [containerd v1.4.4](https://github.com/containerd/containerd/releases/tag/v1.4.4)
- [runc v1.0.0-rc93](https://github.com/opencontainers/runc/releases/tag/v1.0.0-rc93)

### Bug fixes and minor changes

- Fixed an issue when viewing compose applications that have been started with an explicit project name. Fixes [docker/for-win#10564](https://github.com/docker/for-win/issues/10564).
- Fixed a bug that `--add-host host.docker.internal:host-gateway` caused `host.docker.internal` to resolve to the wrong IP address. See [docker/for-linux#264](https://github.com/docker/for-linux/issues/264#issuecomment-785137844).
- Fixed a bug that caused inter-container HTTP traffic to be misrouted to the external HTTP proxy. Fixes [docker/for-mac#5476](https://github.com/docker/for-mac/issues/5476).
- Fixed a bug that could cause other files in the same folder as the VM disk to be deleted when the disk was resized. Fixes [docker/for-mac#5486](https://github.com/docker/for-mac/issues/5486).
- Fixed an issue where delta downloads caused an `Illegal instruction exception`. Fixes [docker/for-mac#5459](https://github.com/docker/for-mac/issues/5459).
- Apply domain-based HTTPS proxy `no_proxy` rules for encrypted connections. Fixes [docker/for-mac#2732](https://github.com/docker/for-mac/issues/2732).
- Fixed missing text in reset to factory defaults dialog. Fixes [docker/for-mac#5457](https://github.com/docker/for-mac/issues/5457).
- Fixed an issue where running a container with a random port on the host caused Docker Desktop dashboard to incorrectly open a browser with port 0, instead of using the allocated port.
- Fixed an issue where pulling an image from Docker Hub using the Docker Desktop dashboard was failing silently.
- Removed unused DNS name `docker.for.mac.http.internal`.
- Perform a filesystem check when starting the Linux VM.
- Detect Linux kernel crashes and escalate them to the user.

## Docker Desktop 3.2.2
2021-03-15

### Bug fixes and minor changes

- Fixed an issue that stopped containers binding to port 53. Fixes [docker/for-mac#5416](https://github.com/docker/for-mac/issues/5416).
- Fixed an issue that 32-bit Intel binaries were emulated on Intel CPUs. Fixes [docker/for-win#10594](https://github.com/docker/for-win/issues/10594).
- Fixed an issue related to high CPU consumption and frozen UI when the network connection is lost. Fixes [for-win/#10563](https://github.com/docker/for-win/issues/10563).
- Fixed an issue opening a terminal in iTerm2 when it has no other windows open. Fixes [docker/roadmap#98](https://github.com/docker/roadmap/issues/98#issuecomment-791927788).

## Docker Desktop 3.2.1
2021-03-05

### Upgrades

- [Docker Engine 20.10.5](../../engine/release-notes/20.10.md#20105)

### Bug fixes and minor changes

- Fixed an issue that sometimes caused Docker Desktop to fail to start after updating to version 3.2.0. Fixes [docker/for-mac#5406](https://github.com/docker/for-mac/issues/5406). If you are still experiencing this issue when trying to update from 3.2.0 to 3.2.1, we recommend that you uninstall 3.2.0 and manually install Docker Desktop 3.2.1.

## Docker Desktop 3.2.0
2021-03-01

### New

- The Docker Dashboard opens automatically when you start Docker Desktop.
- The Docker Dashboard displays a tip once a week.
- Docker Desktop uses iTerm2 to launch the terminal on the container if it is installed. Otherwise, it launches the default Terminal.App. [docker/roadmap#98](https://github.com/docker/roadmap/issues/98)
- Add experimental support to use the new Apple Virtualization framework (requires macOS Big Sur 11.1 or later)
- BuildKit is now the default builder for all users, not just for new installations. To turn this setting off, go to **Preferences** > **Docker Engine** and add the following block to the Docker daemon configuration file:
```json
"features": {
    "buildkit": false
}
```

### Upgrades

- [Docker Engine 20.10.3](../../engine/release-notes/20.10.md#20103)
- [Docker Compose 1.28.5](https://github.com/docker/compose/releases/tag/1.28.5)
- [Compose CLI v1.0.9](https://github.com/docker/compose-cli/tree/v1.0.9)
- [Docker Hub Tool v0.3.0](https://github.com/docker/hub-tool/releases/tag/v0.3.0)
- [QEMU 5.0.1](https://wiki.qemu.org/ChangeLog/5.0)
- [Amazon ECR Credential Helper v0.5.0](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.5.0)
- [Alpine 3.13](https://alpinelinux.org/posts/Alpine-3.13.0-released.html)
- [Kubernetes 1.19.7](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.7)
- [Go 1.16](https://golang.org/doc/go1.16)

### Bug fixes and minor changes

- Fixed an issue on the container detail screen where the buttons would disappear when scrolling the logs. Fixes [docker/for-mac#5290](https://github.com/docker/for-mac/issues/5290)
- Fixed an issue when port forwarding multiple ports with an IPv6 container network. Fixes [docker/for-mac#5247](https://github.com/docker/for-mac/issues/5247)
- Fixed a regression where `docker load` could not use an xz archive anymore. Fixes [docker/for-mac#5271](https://github.com/docker/for-mac/issues/5271)
- Fixed a navigation issue in the **Containers / Apps** view. Fixes [docker/for-win#10160](https://github.com/docker/for-win/issues/10160#issuecomment-764660660)
- Fixed container instance view with long container/image name. Fixes [docker/for-mac#5290](https://github.com/docker/for-mac/issues/5290)
- Fixed an issue when binding ports on specific IPs. Note: It may now take a bit of time before the `docker inspect` command shows the open ports. Fixes [docker/for-mac#4541](https://github.com/docker/for-mac/issues/4541)
- Fixed an issue where an image deleted from the Docker dashboard was still displayed on the **Images** view.

### Known issue

Docker Desktop can sometimes fail to start after updating to version 3.2.0. If you are experiencing this issue, we recommend that you uninstall 3.2.0 and manually install [Docker Desktop 3.2.1](#docker-desktop-321). See [docker/for-mac#5406](https://github.com/docker/for-mac/issues/5406).

## Docker Desktop 3.1.0
2021-01-14

### New

- Docker daemon now runs within a Debian Buster based container (instead of Alpine).

### Upgrades

- [Compose CLI v1.0.7](https://github.com/docker/compose-cli/tree/v1.0.7)

### Bug fixes and minor changes

- Fixed UI reliability issues when users create or delete a lot of objects in batches.
- Fixed an issue with DNS address resolution in Alpine containers. Fixes [docker/for-mac#5020](https://github.com/docker/for-mac/issues/5020).
- Redesigned the **Support** UI to improve usability.

## Docker Desktop 3.0.4
2021-01-06

### Upgrades

- [Docker Engine 20.10.2](../../engine/release-notes/20.10.md#20102)

### Bug fixes and minor changes

- Avoid timeouts during `docker-compose up` by making cache invalidation faster. Fixes [docker/for-mac#4957](https://github.com/docker/for-mac/issues/4957).
- Avoid generating a spurious filesystem DELETE event while invalidating caches. Fixes [docker/for-mac#5124](https://github.com/docker/for-mac/issues/5124).

### Known issues

- Some DNS addresses fail to resolve within containers based on Alpine Linux 3.13. See [docker/for-mac#5020](https://github.com/docker/for-mac/issues/5020).

## Docker Desktop 3.0.3
2020-12-21

### Bug fixes and minor changes

- Fixed an issue that caused overlapping volume mounts to fail. Fixes [docker/for-mac#5157](https://github.com/docker/for-mac/issues/5157). However, the fixes for [docker/for-mac#4957](https://github.com/docker/for-mac/issues/4957) and [docker/for-mac#5124](https://github.com/docker/for-mac/issues/5124) have been reverted as a result of this change, so those issues are now present again.

### Known issues

- Some DNS addresses fail to resolve within containers based on Alpine Linux 3.13. See [docker/for-mac#5020](https://github.com/docker/for-mac/issues/5020).
- There can be timeouts during docker-compose up if there are several services being started. See [docker/for-mac#4957](https://github.com/docker/for-mac/issues/4957) and [docker/for-mac#5124](https://github.com/docker/for-mac/issues/5124).

## Docker Desktop 3.0.2
2020-12-18

### Bug fixes and minor changes

- Avoid timeouts during `docker-compose up` by making cache invalidation faster. Fixes [docker/for-mac#4957](https://github.com/docker/for-mac/issues/4957).
- Avoid generating a spurious filesystem DELETE event while invalidating caches. Fixes [docker/for-mac#5124](https://github.com/docker/for-mac/issues/5124).
- It is now possible to share directories in `~/Library` (except Docker Desktop data directories) with a container. Fixes [docker/for-mac#5115](https://github.com/docker/for-mac/issues/5115).
- You will now see a performance warning pop-up message if you create a container that shares the `Home` or  a user `Library` directory.

### Known issues

- Some DNS addresses fail to resolve within containers based on Alpine Linux 3.13. See [docker/for-mac#5020](https://github.com/docker/for-mac/issues/5020).

## Docker Desktop 3.0.1
2020-12-11

### Bug fixes and minor changes

- Fixed an issue that caused certain directories not to be mountable into containers. Fixes [docker/for-mac#5115](https://github.com/docker/for-mac/issues/5115). See Known issues below.

### Known issues

- It is currently not possible to bind mount files within `~/Library` into a container. See [docker/for-mac#5115](https://github.com/docker/for-mac/issues/5115).
- Building an image with BuildKit from a git URL fails when using the form `github.com/org/repo`. To work around this issue, use the form `git://github.com/org/repo`.
- Some DNS addresses fail to resolve within containers based on Alpine Linux 3.13. See [docker/for-mac#5020](https://github.com/docker/for-mac/issues/5020).

## Docker Desktop 3.0.0
2020-12-10

### New 

- Use of three-digit version number for Docker Desktop releases.
- Starting with Docker Desktop 3.0.0, updates are now much smaller as they will be applied using delta patches.
- First version of `docker compose` (as an alternative to the existing `docker-compose`). Supports some basic commands but not the complete functionality of `docker-compose` yet.

  - Supports the following subcommands: `up`, `down`, `logs`, `build`, `pull`, `push`, `ls`, `ps`
  - Supports basic volumes, bind mounts, networks, and environment variables

    Let us know your feedback by creating an issue in the [compose-cli](https://github.com/docker/compose-cli/issues) GitHub repository.
- [Docker Hub Tool v0.2.0](https://github.com/docker/roadmap/issues/117)

### Upgrades

- [Docker Engine 20.10.0](../../engine/release-notes/20.10.md#20100)
- [Go 1.15.6](https://github.com/golang/go/issues?q=milestone%3AGo1.15.6+label%3ACherryPickApproved+)
- [Compose CLI v1.0.4](https://github.com/docker/compose-cli/releases/tag/v1.0.4)
- [Snyk v1.432.0](https://github.com/snyk/snyk/releases/tag/v1.432.0)

### Bug fixes and minor changes

- Downgraded the kernel to [4.19.121](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.121-2a1dbedf3f998dac347c499808d7c7e029fbc4d3-amd64/images/sha256-4e7d94522be4f25f1fbb626d5a0142cbb6e785f37e437f6fd4285e64a199883a?context=repo) to reduce the CPU usage of hyperkit. Fixes [docker/for-mac#5044](https://github.com/docker/for-mac/issues/5044)
- Avoid caching bad file sizes and modes when using `osxfs`. Fixes [docker/for-mac#5045](https://github.com/docker/for-mac/issues/5045).
- Fixed a possible file sharing error where a file may appear to have the wrong size in a container when it is modified on the host. This is a partial fix for [docker/for-mac#4999](https://github.com/docker/for-mac/issues/4999).
- Removed unnecessary log messages which slow down filesystem event injection.
- Re-enabled the experimental SOCKS proxy. Fixes [docker/for-mac#5048](https://github.com/docker/for-mac/issues/5048).
- Fixed an unexpected EOF error when trying to start a non-existing container with `-v /var/run/docker.sock:`. See [docker/for-mac#5025](https://github.com/docker/for-mac/issues/5025).
- Display an error message instead of crashing when the application needs write access on specific directories. See [docker/for-mac#5068](https://github.com/docker/for-mac/issues/5068)

### Known issues

- Building an image with BuildKit from a git URL fails when using the form `github.com/org/repo`. To work around this issue, use the form `git://github.com/org/repo`.
- Some DNS addresses fail to resolve within containers based on Alpine Linux 3.13.


---

# Docker for Windows 3.x release notes

*Sección: Desktop*

This page contains release notes for Docker Desktop for Windows 3.x. 

## Docker Desktop 3.6.0
2021-08-11

### New

- **Dev Environments**: You can now create a Dev Environment from your local Git repository. 
- **Volume Management**: You can now sort volumes by the name, the date created, and the size of the volume. You can also search for specific volumes using the **Search** field. For more information, see [Explore volumes](../use-desktop/volumes.md).

### Upgrades

- [Compose V2 RC1](https://github.com/docker/compose-cli/releases/tag/v2.0.0-rc.1)
  - Docker compose command line completion.
  - Allow setting 0 scale/replicas.
  - Detect new container on logs —follow.
- [Go 1.16.7](https://github.com/golang/go/releases/tag/go1.16.7)
- [Docker Engine 20.10.8](../../engine/release-notes/20.10.md#20108)
- [containerd v1.4.9](https://github.com/containerd/containerd/releases/tag/v1.4.9)
- [runc v1.0.1](https://github.com/opencontainers/runc/releases/tag/v1.0.1)
- [Kubernetes 1.21.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.3)
- [Linux kernel 5.10.47](https://hub.docker.com/layers/docker/for-desktop-kernel/5.10.47-0b705d955f5e283f62583c4e227d64a7924c138f/images/sha256-a4c79bc185ec9eba48dcc802a8881b9d97e532b3f803d23e5b8d4951588f4d51?context=repo)

### Bug fixes and minor changes

- Update kernel configuration to fix a performance regression in [Docker Desktop 3.0.0](#docker-desktop-300)
  that caused publishing container ports to take 10 times longer than on older
  versions. For more information, see [linuxkit/linuxkit#3701](https://github.com/linuxkit/linuxkit/pull/3701)
  and [docker/for-mac#5668](https://github.com/docker/for-mac/issues/5668).
- Fixed a bug where the DNS server would fail after receiving an unexpectedly large datagram.
- Fixed spurious traces on iptables updates.
- Fixed slowness when adding multiple ports forwarding option.
- Fixed bug where the WSL 2 synchronization code creates dangling symlinks if the WSL 2 home directory if it is the same as the Windows home directory. Fixes [docker/for-win#11668](https://github.com/docker/for-win/issues/11668).
- Fixed `docker context ls` after upgrade from 3.5.x when the Linux WSL 2 home directory is the same as the Windows home directory.
- Fixed the permissions on `%PROGRAMDATA%\Docker` to avoid a potential Windows containers compromise. See [CVE-2021-37841](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-37841). Thanks to [Alessio Dalla Piazza](http://it.linkedin.com/in/alessiodallapiazza) for discovering the issue and to @kevpar for helpful discussion.
- Fixed bug where the Linux home directory under WSL 2 was set to the Windows home directory e.g. `/mnt/c/Users/...`.
- Fixed bug where Desktop would fail to start if it could not parse CLI contexts. Fixes [docker/for-win#11601](https://github.com/docker/for-win/issues/11601).
- Fixed an issue related to log display inside a container [docker/for-win#11251](https://github.com/docker/for-win/issues/11251).
- Fixed failures of the Windows Background Intelligent Transfer Service preventing Docker Desktop to start. [docker/for-win#11273](https://github.com/docker/for-win/issues/11273)

## Docker Desktop 3.5.2
2021-07-08

### New

**Dev Environments Preview**: Dev Environments enable you to seamlessly collaborate with your team members without moving between Git branches to get your code onto your team members' machines. When using Dev Environments, you can share your in-progress work with your team members in just one click, and without having to deal with any merge conflicts. 

### Upgrades

- [Compose V2 beta 6](https://github.com/docker/compose-cli/releases/tag/v2.0.0-beta.6)
  - `compose run` and `compose exec` commands use separate streams for stdout and stderr. See [docker/compose-cli#1873](https://github.com/docker/compose-cli/issues/1873).
  - `compose run` and `compose exec` commands support detach keys. Fixes [docker/compose-cli#1709](https://github.com/docker/compose-cli/issues/1709).
  - Fixed `--force` and `--volumes` flags on `compose rm` command. See [docker/compose-cli#1844](https://github.com/docker/compose-cli/issues/1844).
  - Fixed network's IPAM configuration. Service can define a fixed IP. Fixes for [docker/compose-cli#1678](https://github.com/docker/compose-cli/issues/1678) and [docker/compose-cli#1816](https://github.com/docker/compose-cli/issues/1816)

- Dev Environments
  - Support VS Code Insiders. 
  - Allow users to specify a branch when cloning a project. See [dev-environments#11](https://github.com/docker/dev-environments/issues/11)

### Bug fixes and minor changes

- Dev Environments: Fixed a blank screen in some create and remove scenarios. Fixes [dev-environments#4](https://github.com/docker/dev-environments/issues/4)
- Dev Environments: Fixed error handling when removing an environment. Fixes [dev-environments#8](https://github.com/docker/dev-environments/issues/8)
- Dev Environments: The **Start**, **Stop**, and **Share** buttons are disabled while an environment is being created or removed.
- Do not automatically switch CLI contexts on application start or when switching between Windows and Linux containers. Fixes [docker/for-mac#5787](https://github.com/docker/for-mac/issues/5787) and [docker/for-win#11530](https://github.com/docker/for-win/issues/11530).
- Fixed spurious traces on iptables updates.
- Fixed a delay when adding a multiple port forwarding option.

## Docker Desktop 3.5.1
2021-06-25

### New

**Dev Environments Preview**: Dev Environments enable you to seamlessly collaborate with your team members without moving between Git branches to get your code onto your team members' machines. When using Dev Environments, you can share your in-progress work with your team members in just one click, and without having to deal with any merge conflicts.

**Compose V2 beta**: Docker Desktop now includes the beta version of Compose V2, which supports the `docker compose` command as part of the Docker CLI. While `docker-compose` is still supported and maintained, Compose V2 implementation relies directly on the compose-go bindings which are maintained as part of the specification. The compose command in the Docker CLI supports most of the `docker-compose` commands and flags. It is expected to be a drop-in replacement for `docker-compose`. There are a few remaining flags that have yet to be implemented, see the docker-compose compatibility list for more information about the flags that are supported in the new compose command. If you run into any problems with Compose V2, you can easily switch back to Compose v1 by either by making changes in Docker Desktop **Experimental** Settings, or by running the command `docker-compose disable-v2`. Let us know your feedback on the new ‘compose’ command by creating an issue in the [Compose-CLI](https://github.com/docker/compose-cli/issues) GitHub repository.

### Bug fixes and minor changes

- Fixed a bug where users could not install Docker Desktop when the path to the temp folder contained dots. Fixes [docker/for-win#11514](https://github.com/docker/for-win/issues/11514)
- Fixed a link to the policy that provides details on how Docker handles the uploaded diagnostics data. Fixes [docker/for-mac#5741](https://github.com/docker/for-mac/issues/5741)

## Docker Desktop 3.5.0
2021-06-23

### New

**Dev Environments Preview**: Dev Environments enable you to seamlessly collaborate with your team members without moving between Git branches to get your code onto your team members' machines. When using Dev Environments, you can share your in-progress work with your team members in just one click, and without having to deal with any merge conflicts.

**Compose V2 beta**: Docker Desktop now includes the beta version of Compose V2, which supports the `docker compose` command as part of the Docker CLI. While `docker-compose` is still supported and maintained, Compose V2 implementation relies directly on the compose-go bindings which are maintained as part of the specification. The compose command in the Docker CLI supports most of the `docker-compose` commands and flags. It is expected to be a drop-in replacement for `docker-compose`. There are a few remaining flags that have yet to be implemented, see the docker-compose compatibility list for more information about the flags that are supported in the new compose command. If you run into any problems with Compose V2, you can easily switch back to Compose v1 by either by making changes in Docker Desktop **Experimental** Settings, or by running the command `docker-compose disable-v2`. Let us know your feedback on the new ‘compose’ command by creating an issue in the [Compose-CLI](https://github.com/docker/compose-cli/issues) GitHub repository.

### Upgrades

- [Compose V2 beta](https://github.com/docker/compose-cli/releases/tag/v2.0.0-beta.4)
  - Fixed a bug where a container cannot be started when a file is bind-mounted into a nested mountpoint. Fixes [docker/compose-cli#1795](https://github.com/docker/compose-cli/issues/1795).
  - Added support for container links and external links.
  - Introduced the `docker compose logs --since --until` option.
  - `docker compose config --profiles` now lists all defined profiles.
- From [Kubernetes 1.21.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.1) to [Kubernetes 1.21.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.2)

### Bug fixes and minor changes

- **Volume Management**
  - Users can now remove a file or directory inside a volume using the Docker Dashboard.
  - The **Volumes** view in Docker Dashboard displays the last modified time and the size of the contents inside a volume.
  - Users can save the files and directories inside a volume from Docker Dashboard.
- Fixed an issue that caused credStore timeout errors when running the `docker login` command. Fixes [docker/for-win#11472](https://github.com/docker/for-win/issues/11472)
- Docker Desktop now allows the WSL 2 integration agent to start even when `/etc/wsl.conf` is malformed.
- Fixed an issue with the Docker Compose app not being stopped or removed when started by multiple configuration files. [docker/for-win#11445](https://github.com/docker/for-win/issues/11445)
- Fixed a bug where Docker Desktop fails to restart after a power failure because the Hyper-V VM restarted prematurely.
- The default `docker` CLI `context` is now `desktop-linux` in Linux containers mode and `desktop-windows` when in Windows containers mode.
- Show the Docker Desktop Feedback popup only when clicking Docker menu.

## Docker Desktop 3.4.0
2021-06-09

### New

**Volume Management**: Docker Desktop users can now create and delete volumes using the Docker Dashboard and also see which volumes are being used. For more information, see [Explore volumes](../use-desktop/volumes.md).

**Compose V2 beta**: Docker Desktop now includes the beta version of Compose V2, which supports the `docker compose` command as part of the Docker CLI. While `docker-compose` is still supported and maintained, Compose V2 implementation relies directly on the compose-go bindings which are maintained as part of the specification. The compose command in the Docker CLI supports most of the `docker-compose` commands and flags. It is expected to be a drop-in replacement for `docker-compose`. There are a few remaining flags that have yet to be implemented, see the docker-compose compatibility list for more information about the flags that are supported in the new compose command. If you run into any problems with Compose V2, you can easily switch back to Compose v1 by either by making changes in Docker Desktop **Experimental** Settings, or by running the command `docker-compose disable-v2`. Let us know your feedback on the new ‘compose’ command by creating an issue in the [Compose-CLI](https://github.com/docker/compose-cli/issues) GitHub repository.

**Skip Docker Desktop updates**: All users can now skip an update when they are prompted to install individual Docker Desktop releases. 

### Deprecation

- Docker Desktop no longer installs Notary, `docker trust` should be used for image signing.

### Upgrades

- [Docker Engine 20.10.7](../../engine/release-notes/20.10.md#20107)
- [Docker Compose 1.29.2](https://github.com/docker/compose/releases/tag/1.29.2)
- [Docker Hub Tool v0.4.1](https://github.com/docker/hub-tool/releases/tag/v0.4.1)
- [Compose CLI v1.0.16](https://github.com/docker/compose-cli/releases/tag/v1.0.16)
- [Kubernetes 1.21.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.1)
- [containerd v1.4.6](https://github.com/containerd/containerd/releases/tag/v1.4.6)
- [runc v1.0.0-rc95](https://github.com/opencontainers/runc/releases/tag/v1.0.0-rc95)
- [Go 1.16.5](https://github.com/golang/go/releases/tag/go1.16.5)

### Bug fixes and minor changes

- Fixed error showing stderr log in the UI. Fixes [docker/for-win#11251](https://github.com/docker/for-win/issues/11251).
- Automatically reclaim space after deleting containers by deleting volumes and removing build cache.
- Docker Compose applications with file names other than `docker-compose.yml` can now be removed from Docker Desktop. Fixes [docker/for-win#11046](https://github.com/docker/for-win/issues/11046)
- Fixed version number missing in update dialog window.
- Fixed an issue where the diagnostics were sometimes not uploaded correctly from the **Support** dialog.
- Fixed DNS entries for `*.docker.internal` and Kubernetes cluster reset after the VM IP changes.
- Fixed a corrupted internal cache which was preventing Docker Desktop from starting. Fixes [docker/for-win#8748](https://github.com/docker/for-win/issues/8748).
- Fixed an issue where `docker info` sometimes took longer to respond. Fixes [docker/for-win#10675](https://github.com/docker/for-win/issues/10675)

## Docker Desktop 3.3.3
2021-05-06

### Upgrades

- [Snyk v1.563.0](https://github.com/snyk/snyk/releases/tag/v1.563.0)
- [Docker Scan v0.8.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.8.0)

### Bug fixes and minor changes

- Fixed the diagnostics failing to upload from the Troubleshoot screen.

## Docker Desktop 3.3.2
2021-05-03

### Upgrades

- [Compose CLI v1.0.14](https://github.com/docker/compose-cli/tree/v1.0.14)
- [Go 1.16.3](https://golang.org/doc/go1.16)
- [Docker Compose 1.29.1](https://github.com/docker/compose/releases/tag/1.29.1)
- [Docker Engine 20.10.6](../../engine/release-notes/20.10.md#20106)

### Bug fixes and minor changes

- Fixed a bug where a `metrics-port` defined in the engine's `daemon.json` blocks application restart.
- Fixed a leak of ephemeral ports. Fixes [docker/for-mac#5611](https://github.com/docker/for-mac/issues/5611).
- Enable buildkit garbage collection by default.
- Fixed a bug which blocked binding to port 123. Fixes [docker/for-mac#5589](https://github.com/docker/for-mac/issues/5589).
- Removed the "Deploy Docker Stacks to Kubernetes by default" Kubernetes setting. The component was removed in 2.4.0.0 but we forgot to remove the setting. Fixes [docker/for-mac#4966](https://github.com/docker/for-mac/issues/4966).

## Docker Desktop 3.3.1
2021-04-15

### Bug fixes and minor changes

- Docker Desktop now ensures the permissions of `/dev/null` and other devices are correctly set to `0666` (`rw-rw-rw-`) inside `--privileged` containers. Fixes [docker/for-mac#5527](https://github.com/docker/for-mac/issues/5527).
- Fixed an issue that caused `docker run` to fail when using `\\wsl.localhost` path to a directory. Fixes [docker/for-win#10786](https://github.com/docker/for-win/issues/10786)
- Fixed an issue that caused Docker Desktop to fail during startup when it is unable to establish a connection with Docker Hub in the backend. Fixes [docker/for-win#10896](https://github.com/docker/for-win/issues/10896)
- Fixed file permission when creating a file from a delta update. Fixes [docker/for-win#10881](https://github.com/docker/for-win/issues/10881)

## Docker Desktop 3.3.0
2021-04-08

### New

You can now specify when to download and install a Docker Desktop update. When an update becomes available, Docker Desktop displays an icon to indicate the availability of a newer version. You can download the update in the background whenever convenient. When the download is complete, all you need to do is to click Update and restart to install the latest update.

Developers who use Docker Desktop for professional development purposes may at times need to skip a specific update. For this reason, users with a paid Docker subscription can skip notifications for a particular update when a reminder appears.

For developers in IT managed environments, who don’t have administrative access to install updates to Docker Desktop, there is now an option in the Settings menu to opt out of notifications altogether for Docker Desktop updates if your Docker ID is part of a Team subscription.

### Upgrades

- [Docker Compose 1.29.0](https://github.com/docker/compose/releases/tag/1.29.0)
- [Compose CLI v1.0.12](https://github.com/docker/compose-cli/tree/v1.0.12)
- [Linux kernel 5.10.25](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-83885d3b4cff391813f4262099b36a529bca2df8-amd64/images/sha256-0214b82436af70054e013ea51cb1fea72bd943d0d6245b6521f1ff09a505c40f?context=repo)
- [Snyk v1.461.0](https://github.com/snyk/snyk/releases/tag/v1.461.0)
- [Docker Hub Tool v0.3.1](https://github.com/docker/hub-tool/releases/tag/v0.3.1)
- [containerd v1.4.4](https://github.com/containerd/containerd/releases/tag/v1.4.4)
- [runc v1.0.0-rc93](https://github.com/opencontainers/runc/releases/tag/v1.0.0-rc93)

### Bug fixes and minor changes

- Fixed an issue when viewing compose applications that have been started with an explicit project name. Fixes [docker/for-win#10564](https://github.com/docker/for-win/issues/10564).
- Ensure `--add-host host.docker.internal:host-gateway` causes `host.docker.internal` resolves to the host IP, rather than the IP of the IP router. See [docker/for-linux#264](https://github.com/docker/for-linux/issues/264).
- Fixed port allocation for Windows containers. Fixes [docker/for-win#10552](https://github.com/docker/for-win/issues/10552).
- Fixed an issue where running a container with a random port on the host caused Docker Desktop dashboard to incorrectly open a browser with port 0, instead of using the allocated port.
- Fixed an issue where pulling an image from Docker Hub using the Docker Desktop dashboard was failing silently.
- Perform a filesystem check when starting the Linux VM.

## Docker Desktop 3.2.2
2021-03-15

### Bug fixes and minor changes

- Fixed an issue that stopped containers binding to port 53. Fixes [docker/for-win#10601](https://github.com/docker/for-win/issues/10601).
- Fixed an issue that 32-bit Intel binaries were emulated on Intel CPUs. Fixes [docker/for-win#10594](https://github.com/docker/for-win/issues/10594).
- Fixed an issue related to high CPU consumption and frozen UI when the network connection is lost. Fixes [for-win/#10563](https://github.com/docker/for-win/issues/10563).

## Docker Desktop 3.2.1
2021-03-05

### Upgrades

- [Docker Engine 20.10.5](../../engine/release-notes/20.10.md#20105)

## Docker Desktop 3.2.0
2021-03-01

### New

- The Docker Dashboard opens automatically when you start Docker Desktop.
- The Docker Dashboard displays a tip once a week.
- BuildKit is now the default builder for all users, not just for new installations. To turn this setting off, go to **Settings** > **Docker Engine** and add the following block to the Docker daemon configuration file:
```json
"features": {
    "buildkit": false
}
```

### Upgrades

- [Docker Engine 20.10.3](../../engine/release-notes/20.10.md#20103)
- [Docker Compose 1.28.5](https://github.com/docker/compose/releases/tag/1.28.5)
- [Compose CLI v1.0.9](https://github.com/docker/compose-cli/tree/v1.0.9)
- [Docker Hub Tool v0.3.0](https://github.com/docker/hub-tool/releases/tag/v0.3.0)
- [QEMU 5.0.1](https://wiki.qemu.org/ChangeLog/5.0)
- [Amazon ECR Credential Helper v0.5.0](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.5.0)
- [Alpine 3.13](https://alpinelinux.org/posts/Alpine-3.13.0-released.html)
- [Kubernetes 1.19.7](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.7)
- [Go 1.16](https://golang.org/doc/go1.16)

### Deprecation

- Docker Desktop cannot be installed on Windows 1709 (build 16299) anymore.
- Removed the deprecated DNS name `docker.for.win.localhost`. Use DNS name `host.docker.internal` in a container to access services that are running on the host. [docker/for-win#10619](https://github.com/docker/for-win/issues/10619)

### Bug fixes and minor changes

- Fixed an issue on the container detail screen where the buttons would disappear when scrolling the logs. Fixes [docker/for-win#10160](https://github.com/docker/for-win/issues/10160)
- Fixed an issue when port forwarding multiple ports with an IPv6 container network. Fixes [docker/for-mac#5247](https://github.com/docker/for-mac/issues/5247)
- Fixed a regression where `docker load` could not use an xz archive anymore. Fixes [docker/for-win#10364](https://github.com/docker/for-win/issues/10364)
- Fixed an issue that caused the WSL 2 backend shutdown process to interfere with Windows shutdown. Fixes [docker/for-win#5825](https://github.com/docker/for-win/issues/5825) [docker/for-win#6933](https://github.com/docker/for-win/issues/6933) [docker/for-win#6446](https://github.com/docker/for-win/issues/6446)
- Fixed creds store using `desktop.exe` from WSL 2. Fixes [docker/compose-cli#1181](https://github.com/docker/compose-cli/issues/1181)
- Fixed a navigation issue in the **Containers / Apps** view. Fixes [docker/for-win#10160](https://github.com/docker/for-win/issues/10160#issuecomment-764660660)
- Fixed container instance view with long container/image name. Fixes [docker/for-win#10160](https://github.com/docker/for-win/issues/10160)
- Fixed an issue when binding ports on specific IPs. Note: It may now take a bit of time before the `docker inspect` command shows the open ports. Fixes [docker/for-win#10008](https://github.com/docker/for-win/issues/10008)
- Fixed an issue where an image deleted from the Docker dashboard was still displayed on the **Images** view.

## Docker Desktop 3.1.0
2021-01-14

## New

- Add experimental support for GPU workloads with WSL 2 backend (requires Windows Insider developer channel).
- Docker daemon now runs within a Debian Buster based container (instead of Alpine).

### Upgrades

- [Compose CLI v1.0.7](https://github.com/docker/compose-cli/tree/v1.0.7)

### Bug fixes and minor changes

- Fixed an issue where disabling proxy settings would not work. Fixes [docker/for-win#9357](https://github.com/docker/for-win/issues/9357).
- Fixed UI reliability issues when users create or delete a lot of objects in batches.
- Redesigned the **Support** UI to improve usability.

## Docker Desktop 3.0.4
2021-01-06
pgrades

- [Docker Engine 20.10.2](../../engine/release-notes/20.10.md#20102)

### Bug fixes and minor changes

- Fixed an issue that could cause Docker Desktop to fail to start after upgrading to 3.0.0. Fixes [docker/for-win#9755](https://github.com/docker/for-win/issues/9755).

## Docker Desktop 3.0.0
2020-12-10

## New

- Use of three-digit version number for Docker Desktop releases.
- Docker Desktop updates are now much smaller as they will be applied using delta patches. For more information, see.
- First version of `docker compose` (as an alternative to the existing `docker-compose`). Supports some basic commands but not the complete functionality of `docker-compose` yet.

  - Supports the following subcommands: `up`, `down`, `logs`, `build`, `pull`, `push`, `ls`, `ps`
  - Supports basic volumes, bind mounts, networks, and environment variables

    Let us know your feedback by creating an issue in the [compose-cli](https://github.com/docker/compose-cli/issues) GitHub repository.
- [Docker Hub Tool v0.2.0](https://github.com/docker/roadmap/issues/117)

### Upgrades

- [Docker Engine 20.10.0](../../engine/release-notes/20.10.md#20100)
- [Go 1.15.6](https://github.com/golang/go/issues?q=milestone%3AGo1.15.6+label%3ACherryPickApproved+)
- [Compose CLI v1.0.4](https://github.com/docker/compose-cli/releases/tag/v1.0.4)
- [Snyk v1.432.0](https://github.com/snyk/snyk/releases/tag/v1.432.0)

### Bug fixes and minor changes

- Downgraded the kernel to [4.19.121](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.121-2a1dbedf3f998dac347c499808d7c7e029fbc4d3-amd64/images/sha256-4e7d94522be4f25f1fbb626d5a0142cbb6e785f37e437f6fd4285e64a199883a?context=repo) to reduce the CPU usage of hyperkit. Fixes [docker/for-mac#5044](https://github.com/docker/for-mac/issues/5044)
- Fixed an unexpected EOF error when trying to start a non-existing container with `-v /var/run/docker.sock:`. See [docker/for-mac#5025](https://github.com/docker/for-mac/issues/5025).

### Known issues

- Building an image with BuildKit from a git URL fails when using the form `github.com/org/repo`. To work around this issue, use the form `git://github.com/org/repo`.
- Some DNS addresses fail to resolve within containers based on Alpine Linux 3.13.


---

# Previous releases

*Sección: Desktop*




---

# Release notes for previous versions

*Sección: Desktop*

This page contains release notes for older versions of Docker Desktop for Mac.

## Stable Releases of 2018

### Docker Community Edition 18.06.1-ce-mac73 2018-08-29

* Upgrades
  - [Docker 18.06.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.1-ce)

* Bug fixes and minor changes
  - Fix local DNS failing to resolve inside containers.

### Docker Community Edition 18.06.0-ce-mac70 2018-07-25

* Upgrades
  - [Docker 18.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.0-ce)
  - [Docker Machine 0.15.0](https://github.com/docker/machine/releases/tag/v0.15.0)
  - [Docker compose 1.22.0](https://github.com/docker/compose/releases/tag/1.22.0)
  - [LinuxKit v0.5](https://github.com/linuxkit/linuxkit/releases/tag/v0.5)
  - Linux Kernel 4.9.93 with CEPH, DRBD, RBD, MPLS_ROUTING and MPLS_IPTUNNEL enabled

* New
  - Kubernetes Support. You can now run a single-node Kubernetes cluster from the "Kubernetes" Pane in Docker For Mac Preferences and use kubectl commands as well as docker commands. See [the Kubernetes section](../use-desktop/kubernetes.md)
  - Add an experimental SOCKS server to allow access to container networks, see [docker/for-mac#2670](https://github.com/docker/for-mac/issues/2670#issuecomment-372365274). Also see [docker/for-mac#2721](https://github.com/docker/for-mac/issues/2721)
  - Re-enable raw as the default disk format for users running macOS 10.13.4 and higher. Note this change only takes effect after a "reset to factory defaults" or "remove all data" (from the Whale menu -> Preferences -> Reset). Related to [docker/for-mac#2625](https://github.com/docker/for-mac/issues/2625)

* Bug fixes and minor changes
  - AUFS storage driver is deprecated in Docker Desktop and AUFS support will be removed in the next major release. You can continue with AUFS in Docker Desktop 18.06.x, but you will need to reset disk image (in Preferences > Reset menu) before updating to the next major update. You can check documentation to [save images](/reference/cli/docker/image/save/#examples) and [back up volumes](../../engine/storage/volumes.md#back-up-restore-or-migrate-data-volumes)
  - OS X El Captain 10.11 is deprecated in Docker Desktop. You will not be able to install updates after Docker Desktop 18.06.x. We recommend upgrading to the latest version of macOS.
  - Fix bug which would cause VM logs to be written to RAM rather than disk in some cases, and the VM to hang. See [docker/for-mac#2984](https://github.com/docker/for-mac/issues/2984)
  - Fix network connection leak triggered by haproxy TCP health-checks [docker/for-mac#1132](https://github.com/docker/for-mac/issues/1132)
  - Better message to reset vmnetd when it's disabled. See [docker/for-mac#3035](https://github.com/docker/for-mac/issues/3035)
  - Fix VPNKit memory leak. Fixes [moby/vpnkit#371](https://github.com/moby/vpnkit/issues/371)
  - Virtual Machine default disk path is stored relative to $HOME. Fixes [docker/for-mac#2928](https://github.com/docker/for-mac/issues/2928), [docker/for-mac#1209](https://github.com/docker/for-mac/issues/1209)
  - Use Simple NTP to minimise clock drift between the VM and the host. Fixes [docker/for-mac#2076](https://github.com/docker/for-mac/issues/2076)
  - Fix a race between calling stat on a file and calling close of a file descriptor referencing the file that could result in the stat failing with EBADF (often presented as "File not found"). Fixes [docker/for-mac#2870](https://github.com/docker/for-mac/issues/2870)
  - Do not allow install of Docker for Mac on macOS Yosemite 10.10, this version is not supported since Docker for Mac 17.09.0.
  - Fix button order in reset dialog windows. Fixes [docker/for-mac#2827](https://github.com/docker/for-mac/issues/2827)
  - Fix upgrade straight from pre-17.12 versions where Docker for Mac cannot restart once the upgrade has been performed. Fixes [docker/for-mac#2739](https://github.com/docker/for-mac/issues/2739)
  - Added log rotation for docker-ce logs inside the virtual machine.

### Docker Community Edition 18.03.1-ce-mac65 2018-04-30

* Upgrades
  - [Docker 18.03.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.1-ce)
  - [Docker compose 1.21.1](https://github.com/docker/compose/releases/tag/1.21.1)
  - [Notary 0.6.1](https://github.com/docker/notary/releases/tag/v0.6.1)

* Bug fixes and minor changes
  - Fix Docker for Mac not starting due to socket file paths being too long (typically HOME folder path being too long). Fixes [docker/for-mac#2727](https://github.com/docker/for-mac/issues/2727), [docker/for-mac#2731](https://github.com/docker/for-mac/issues/2731).

### Docker Community Edition 18.03.1-ce-mac64 2018-04-26

* Upgrades
  - [Docker 18.03.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.1-ce)
  - [Docker compose 1.21.0](https://github.com/docker/compose/releases/tag/1.21.0)
  - [Notary 0.6.1](https://github.com/docker/notary/releases/tag/v0.6.1)

* Bug fixes and minor changes
  - Fix Docker for Mac not starting due to socket file paths being too long (typically HOME folder path being too long). Fixes [docker/for-mac#2727](https://github.com/docker/for-mac/issues/2727), [docker/for-mac#2731](https://github.com/docker/for-mac/issues/2731).

### Docker Community Edition 18.03.0-ce-mac60 2018-03-30

* Bug fixes and minor changes
  - Fix Upgrade straight from 17.09 versions where Docker for Mac cannot restart once the upgrade has been performed. Fixes [docker/for-mac#2739](https://github.com/docker/for-mac/issues/2739)

### Docker Community Edition 18.03.0-ce-mac59 2018-03-26

* Upgrades
  - [Docker 18.03.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce)
  - [Docker Machine 0.14.0](https://github.com/docker/machine/releases/tag/v0.14.0)
  - [Docker compose 1.20.1](https://github.com/docker/compose/releases/tag/1.20.1)
  - [Notary 0.6.0](https://github.com/docker/notary/releases/tag/v0.6.0)
  - Linux Kernel 4.9.87
  - AUFS 20180312

* New
  - VM Swap size can be changed in settings. See [docker/for-mac#2566](https://github.com/docker/for-mac/issues/2566), [docker/for-mac#2389](https://github.com/docker/for-mac/issues/2389)
  - New menu item to restart Docker.
  - Support NFS Volume sharing.
  - The directory holding the disk images has been renamed (from `~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux` to ~/Library/Containers/com.docker.docker/Data/vms/0`).

* Bug fixes and minor changes
  - Fix daemon not starting properly when setting TLS-related options. Fixes [docker/for-mac#2663](https://github.com/docker/for-mac/issues/2663)
  - DNS name `host.docker.internal` should be used for host resolution from containers. Older aliases (still valid) are deprecated in favor of this one. (See https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06).
  - Fix for the HTTP/S transparent proxy when using "localhost" names (e.g. `host.docker.internal`).
  - Fix empty registry added by mistake in some cases in the Preference Daemon Pane. Fixes [docker/for-mac#2537](https://github.com/docker/for-mac/issues/2537)
  - Clearer error message when incompatible hardware is detected.
  - Fix some cases where selecting "Reset" after an error did not reset properly.
  - Fix incorrect NTP config. Fixes [docker/for-mac#2529](https://github.com/docker/for-mac/issues/2529)
  - Migration of Docker Toolbox images is not proposed anymore in Docker For Mac installer (still possible to migrate Toolbox images manually).

### Docker Community Edition 17.12.0-ce-mac55 2018-02-27

* Bug fixes and minor changes
  - Revert the default disk format to qcow2 for users running macOS 10.13 (High Sierra). There are confirmed reports of file corruption using the raw format which uses sparse files on APFS. Note this change only takes effect after a reset to factory defaults (from the Whale menu -> Preferences -> Reset). Related to [docker/for-mac#2625](https://github.com/docker/for-mac/issues/2625)
  - Fix VPNKit proxy for docker.for.mac.http.internal.

### Docker Community Edition 17.12.0-ce-mac49 2018-01-19

* Bug fixes and minor changes
  - Fix error during resize/create Docker.raw disk image in some cases. Fixes [docker/for-mac#2383](https://github.com/docker/for-mac/issues/2383), [docker/for-mac#2447](https://github.com/docker/for-mac/issues/2447), [docker/for-mac#2453], (https://github.com/docker/for-mac/issues/2453), [docker/for-mac#2420](https://github.com/docker/for-mac/issues/2420)
  - Fix additional allocated disk space not available in containers. Fixes [docker/for-mac#2449](https://github.com/docker/for-mac/issues/2449)
  - Vpnkit port max idle time default restored to 300s. Fixes [docker/for-mac#2442](https://github.com/docker/for-mac/issues/2442)
  - Fix using an HTTP proxy with authentication. Fixes [docker/for-mac#2386](https://github.com/docker/for-mac/issues/2386)
  - Allow HTTP proxy excludes to be written as .docker.com as well as *.docker.com
  - Allow individual IP addresses to be added to HTTP proxy excludes.
  - Avoid hitting DNS timeouts when querying docker.for.mac.* when the upstream DNS servers are slow or missing.

### Docker Community Edition 17.12.0-ce-mac47 2018-01-12

* Bug fixes and minor changes
  - Fix for `docker push` to an insecure registry. Fixes [docker/for-mac#2392](https://github.com/docker/for-mac/issues/2392)
  - Separate internal ports used to proxy HTTP and HTTPS content.

### Docker Community Edition 17.12.0-ce-mac46 2018-01-09

* Upgrades
  - [Docker 17.12.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce)
  - [Docker compose 1.18.0](https://github.com/docker/compose/releases/tag/1.18.0)
  - [Docker Machine 0.13.0](https://github.com/docker/machine/releases/tag/v0.13.0)
  - Linux Kernel 4.9.60

* New
  - VM entirely built with Linuxkit
  - VM disk size can be changed in disk preferences. (See [docker/for-mac#1037](https://github.com/docker/for-mac/issues/1037))
  - For systems running APFS on SSD on High Sierra, use `raw` format VM disks by default. This improves disk throughput (from 320MiB/sec to 600MiB/sec in `dd` on a 2015 MacBook Pro) and disk space handling.
    Existing disks are kept in qcow format, if you want to switch to raw format you need to "Remove all data" or "Reset to factory defaults".
  - DNS name `docker.for.mac.host.internal` should be used instead of `docker.for.mac.localhost` (still valid) for host resolution from containers, since since there is an RFC banning the use of subdomains of localhost. See  https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06.

* Bug fixes and minor changes
  - Display various component versions in About box.
  - Avoid VM reboot when changing host proxy settings.
  - Don't break HTTP traffic between containers by forwarding them via the external proxy. (See [docker/for-mac#981](https://github.com/docker/for-mac/issues/981))
  - Filesharing settings are now stored in settings.json.
  - Daemon restart button has been moved to settings / Reset Tab.
  - Better VM state handling & error messages in case of VM crashes.
  - Fix login into private repository with certificate issue. (See [docker/for-mac#2201](https://github.com/docker/for-mac/issues/2201))

## Stable Releases of 2017

### Docker Community Edition 17.09.1-ce-mac42 2017-12-11

* Upgrades
  - [Docker 17.09.1-ce](https://github.com/docker/docker-ce/releases/tag/v17.09.1-ce)
  - [Docker compose 1.17.1](https://github.com/docker/compose/releases/tag/1.17.1)
  - [Docker Machine 0.13.0](https://github.com/docker/machine/releases/tag/v0.13.0)

* Bug fixes and minor changes
  - Fix bug not allowing to move qcow disk in some cases.

### Docker Community Edition 17.09.0-ce-mac35 2017-10-06

* Bug fix
  - Fix Docker For Mac unable to start in some cases : removed use of libgmp sometimes causing the vpnkit process to die.

### Docker Community Edition 17.09.0-ce-mac33 2017-10-03
  - Do not show Toolbox migration assistant when there are existing Docker For Mac data.

### Docker Community Edition 17.09.0-ce-mac32 2017-10-02

* Upgrades
  - [Docker 17.09.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce)
  - [Docker Compose 1.16.1](https://github.com/docker/compose/releases/tag/1.16.1)
  - [Docker Machine 0.12.2](https://github.com/docker/machine/releases/tag/v0.12.2)
  - [Docker Credential Helpers 0.6.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.0)
  - Linux Kernel 4.9.49
  - AUFS 20170911
  - DataKit update (fix instability on High Sierra)

* New
  - Add daemon options validation
  - VPNKit: add support for ping!
  - VPNKit: add slirp/port-max-idle-timeout to allow the timeout to be adjusted or even disabled
  - VPNKit: bridge mode is default everywhere now
  - Transparent proxy using macOS system proxies (if defined) directly
  - GUI settings are now stored in ~/Library/Group\ Containers/group.com.docker/settings.json. daemon.json in now a file in ~/.docker/
  - You can now change the default IP address used by Hyperkit if it collides with your network

* Bug fixes and minor changes
  - Fix instability on High Sierra (docker/for-mac#2069, docker/for-mac#2062, docker/for-mac#2052, docker/for-mac#2029, docker/for-mac#2024)
  - Fix password encoding/decoding (docker/for-mac#2008, docker/for-mac#2016, docker/for-mac#1919, docker/for-mac#712, docker/for-mac#1220).
  - Kernel: Enable TASK_XACCT and TASK_IO_ACCOUNTING (docker/for-mac#1608)
  - Rotate logs in the VM more often
  - VPNKit: change protocol to support error messages reported back from the server
  - VPNKit: fix a bug which causes a socket to leak if the corresponding TCP connection is idle
    for more than 5 minutes (related to [docker/for-mac#1374](https://github.com/docker/for-mac/issues/1374))
  - VPNKit: improve the logging around the Unix domain socket connections
  - VPNKit: automatically trim whitespace from int or bool database keys
  - Diagnose can be cancelled & Improved help information. Fixes docker/for-mac#1134, docker/for-mac#1474
  - Support paging of docker-cloud repositories & orgs. Fixes docker/for-mac#1538

### Docker Community Edition 17.06.2-ce-mac27 2017-09-06

**Upgrades**

  - [Docker 17.06.2-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.2-ce)
  - [Docker Machine 0.12.2](https://github.com/docker/machine/releases/tag/v0.12.2)

### Docker Community Edition 17.06.1-ce-mac24, 2017-08-21

**Upgrades**

- [Docker 17.06.1-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.06.1-ce-rc1)
- Linux Kernel 4.9.36
- AUFS 20170703

**Bug fixes and minor changes**

- DNS Fixes. Fixes [docker/for-mac#1763](https://github.com/docker/for-mac/issues/176), [docker/for-mac#1811](https://github.com/docker/for-mac/issues/1811), [docker/for-mac#1803](https://github.com/docker/for-mac/issues/1803)

- Avoid unnecessary VM reboot (when changing proxy exclude, but no proxy set). Fixes [docker/for-mac#1809](https://github.com/docker/for-mac/issues/1809), [docker/for-mac#1801](https://github.com/docker/for-mac/issues/1801)

### Docker Community Edition 17.06.0-ce-mac18, 2017-06-28s

**Upgrades**

- [Docker 17.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce)
- [Docker Credential Helpers 0.5.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.2)
- [Docker Machine 0.12.0](https://github.com/docker/machine/releases/tag/v0.12.0)
- [Docker compose 1.14.0](https://github.com/docker/compose/releases/tag/1.14.0)
- qcow-tool v0.10.0 (improve the performance of `compact`: mirage/ocaml-qcow#94)
- OSX Yosemite 10.10 is marked as deprecated
- Linux Kernel 4.9.31

**New**

- Integration with Docker Cloud: control remote Swarms from the local CLI and view your repositories.
- GUI Option to opt out of credential store
- GUI option to reset Docker data without losing all settings (fixes [docker/for-mac#1309](https://github.com/docker/for-mac/issues/1309))
- Add an experimental DNS name for the host: `docker.for.mac.localhost`
- Support for client (i.e. "login") certificates for authenticating registry access (fixes [docker/for-mac#1320](https://github.com/docker/for-mac/issues/1320))
- OSXFS: support for `cached` mount flag to improve performance of macOS mounts when strict consistency is not necessary

**Bug fixes and minor changes**

- Resync HTTP(S) proxy settings on application start
- Interpret system proxy setting of `localhost` correctly (see [docker/for-mac#1511](https://github.com/docker/for-mac/issues/1511))
- All Docker binaries bundled with Docker for Mac are now signed
- Display all Docker Cloud organizations and repositories in the whale menu (fixes [docker/for-mac#1538](https://github.com/docker/for-mac/issues/1538))
- OSXFS: improved latency for many common operations, such as read and write, by approximately 25%
- Fixed GUI crash when text table view was selected and windows re-opened (fixes [docker/for-mac#1477](https://github.com/docker/for-mac/issues/1477))
- Reset to default / uninstall also remove `config.json` and `osxkeychain` credentials
- More detailed VirtualBox uninstall requirements ( [docker/for-mac#1343](https://github.com/docker/for-mac/issues/1343))
- Request time sync after waking up to improve [docker/for-mac#17](https://github.com/docker/for-mac/issues/17)
- VPNKit: Improved DNS timeout handling (fixes [docker/for-mac#202](https://github.com/docker/vpnkit/issues/202))
- VPNKit: Use DNSServiceRef API by default (only enabled for new installs or after factory reset)
- Add a reset to factory defaults button when application crashes
- Toolbox import dialog now defaults to "Skip"
- Buffered data should be treated correctly when Docker client requests are upgraded to raw streams
- Removed an error message from the output related to experimental features handling
- `vmnetd` should not crash when user home directory is on an external drive
- Improved settings database schema handling
- Disk trimming should work as expected
- Diagnostics now contains more settings data

### Docker Community Edition 17.03.1-ce-mac12, 2017-05-12s

**Upgrades**

- Security fix for CVE-2017-7308

### Docker Community Edition 17.03.1-ce-mac5, 2017-03-29s

**Upgrades**

- [Docker Credential Helpers 0.4.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.4.2)


### Docker Community Edition 17.03.0-ce-mac1, 2017-03-02- Renamed to Docker Community Edition

**New** 

- Integration with Docker Cloud: control remote Swarms from the local CLI and view your repositories. This feature is going to be rolled out to all users progressively
- Docker will now securely store your IDs in the macOS keychain

**Upgrades**

- [Docker 17.03.0-ce](https://github.com/docker/docker/releases/tag/v17.03.0-ce)
- [Docker Compose 1.11.2](https://github.com/docker/compose/releases/tag/1.11.2)
- [Docker Machine 0.10.0](https://github.com/docker/machine/releases/tag/v0.10.0)
- Linux kernel 4.9.12

**Bug fixes and minor changes**

- Allow to reset faulty daemon.json through a link in advanced subpanel
- More options when moving disk image
- Add link to experimental features
- Filesharing and daemon table empty fields are editable
- Hide restart button in settings window
- Fix bug where update window hides when app not focused
- Don't use port 4222 inside the Linux VM
- Add page_poison=1 to boot args
- Add a new disk flushing option
- DNS forwarder ignores responses from malfunctioning servers (docker/for-mac#1025)
- DNS forwarder send all queries in parallel, process results in order
- DNS forwarder includes servers with zones in general searches (docker/for-mac#997)
- Parses aliases from /etc/hosts (docker/for-mac#983)
- Can resolve DNS requests via servers listed in the /etc/resolver directory on the host
- Limit vCPUs to 64
- Fixed for swap not being mounted
- Fixed aufs xattr delete issue (docker/docker#30245)
- osxfs: Catch EPERM when reading extended attributes of non-files
- VPNKit: Fixed unmarshalling of DNS packets containing pointers to pointers to labels
- VPNKit: Set the Recursion Available bit on DNS responses from the cache
- VPNKit: Avoid diagnostics to capture too much data
- VPNKit: Fixed a source of occasional packet loss (truncation) on the virtual ethernet link
- HyperKit: Dump guest physical and linear address from VMCS when dumping state
- HyperKit: Kernel boots with panic=1 arg

### Docker for Mac 1.13.1, 2017-02-09s

**Upgrades**

- [Docker 1.13.1](https://github.com/docker/docker/releases/tag/v1.13.1)
- [Docker Compose 1.11.1](https://github.com/docker/compose/releases/tag/1.11.1)
- Linux kernel 4.9.8

**Bug fixes and minor changes**

- Add link to experimental features
- New 1.13 cancellable operations should now be properly handled by the Docker for desktop
- `daemon.json` should render nicely in the UI
- Allow to reset faulty `daemon.json` through a link in advanced subpanel

### Docker for Mac 1.13.0, 2017-01-19s

**Upgrades**

- [Docker 1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)
- [Docker Compose 1.10](https://github.com/docker/compose/releases/tag/1.10.0)
- [Docker Machine 0.9.0](https://github.com/docker/machine/releases/tag/v0.9.0)
- [Notary 0.4.3](https://github.com/docker/notary/releases/tag/v0.4.3)
- Linux kernel 4.9.4
- qcow-tool 0.7.2

**New**

- The storage location of the Linux volume can now be moved
- Reclaim disk size on reboot
- You can now edit filesharing paths
- Memory can be allocated with 256 MiB steps
- Proxy can now be completely disabled
- Support for arm, aarch64, ppc64le architectures using qemu
- Dedicated preference pane for advanced configuration of the
  docker daemon (edit `daemon.json`)
- Docker Experimental mode can be toggled
- Better support for Split DNS VPN configurations
- Use more DNS servers, respect order

**Bug fixes and minor changes**

- You cannot edit settings while docker is restarting
- Support Copy/Paste in About box
- Auto update polling every 24h
- Kernel boots with vsyscall=emulate arg and CONFIG_LEGACY_VSYSCALL is set to NONE in Moby
- Fixed vsock deadlock under heavy write load
- If you opt-out of analytics, you're prompted for approval before a bug report is sent
- Fixed bug where search domain could be read as `DomainName`
- Dedicated preference pane for HTTP proxy settings
- Dedicated preference pane for CPU & Memory computing resources
- Privacy settings moved to the general preference pane
- Fixed an issue where the preference pane disappeared when the welcome whale menu was closed
- HyperKit: code cleanup and minor fixes
- Improvements to Logging and Diagnostics
- osxfs: switch to libev/kqueue to improve latency
- VPNKit: improvements to DNS handling
- VPNKit: Improved diagnostics
- VPNKit: Forwarded UDP datagrams should have correct source port numbers
- VPNKit: add a local cache of DNS responses
- VPNKit: If one request fails, allow other concurrent requests to succeed.
  For example this allows IPv4 servers to work even if IPv6 is broken.
- VPNKit: Fix bug that could cause the connection tracking to
  underestimate the number of active connections

## Stable Releases of 2016

### Docker for Mac 1.12.5, 2016-12-20s

**Upgrades**

- Docker 1.12.5
- Docker Compose 1.9.0

### Skipped Docker for Mac 1.12.4

We did not distribute a 1.12.4 stable release

### Docker for Mac 1.12.3, 2016-11-09s

**Upgrades**

- Docker 1.12.3
- Linux Kernel 4.4.27
- Notary 0.4.2
- Docker Machine 0.8.2
- Docker Compose 1.8.1
- Kernel vsock driver v7
- aufs 20160912

**Bug fixes and minor changes**

**General**

- Fixed an issue where the whale animation during setting change was inconsistent

- Fixed an issue where some windows stayed hidden behind another app

- Fixed an issue where the Docker status would continue to be yellow/animated after the VM had started correctly

- Fixed an issue where Docker for Mac was incorrectly reported as updated

- Channel is now displayed in About box

- Crash reports are sent over Bugsnag rather than HockeyApp

- Fixed an issue where some windows did not claim focus correctly

- Added UI when switching channel to prevent user losing containers and settings

- Check disk capacity before Toolbox import

- Import certificates in `etc/ssl/certs/ca-certificates.crt`

- disk: make the "flush" behaviour configurable for database-like workloads. This works around a performance regression in 1.12.1.

**Networking**

- Proxy: Fixed application of system or custom proxy settings over container restart

- DNS: reduce the number of UDP sockets consumed on the host

- VPNkit: improve the connection-limiting code to avoid running out of sockets on the host

- UDP: handle diagrams bigger than 2035, up to the configured macOS kernel limit

- UDP: make the forwarding more robust; drop packets and continue rather than stopping

**File sharing**

- osxfs: Fixed the prohibition of chown on read-only or mode 0 files, (fixes
  [docker/for-mac#117](https://github.com/docker/for-mac/issues/117),
  [docker/for-mac#263](https://github.com/docker/for-mac/issues/263),
  [docker/for-mac#633](https://github.com/docker/for-mac/issues/633))

- osxfs: Fixed race causing some reads to run forever

- osxfs: Fixed a simultaneous volume mount race which can result in a crash

**Moby**

- Increase default ulimit for memlock (fixes [docker/for-mac#801](https://github.com/docker/for-mac/issues/801))

### Docker for Mac 1.12.1, 2016-09-16

**New**

* Support for macOS 10.12 Sierra

**Upgrades**

* Docker 1.12.1
* Docker machine 0.8.1
* Linux kernel 4.4.20
* aufs 20160905

**Bug fixes and minor changes**

**General**

* Fixed communications glitch when UI talks to com.docker.vmnetd
  Fixes [docker/for-mac#90](https://github.com/docker/for-mac/issues/90)

* `docker-diagnose`: display and record the time the diagnosis was captured

* Don't compute the container folder in `com.docker.vmnetd`
  Fixes [docker/for-mac#47](https://github.com/docker/for-mac/issues/47)

* Warn the user if BlueStacks is installed (potential kernel panic)

* Automatic update interval changed from 1 hour to 24 hours

* Include Zsh completions

* UI Fixes

**Networking**

* VPNKit supports search domains

* slirp: support up to 8 external DNS servers

* slirp: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules will time out earlier than expected

* Entries from `/etc/hosts` should now resolve from within containers

* Allow ports to be bound on host addresses other than `0.0.0.0` and `127.0.0.1`
  Fixes issue reported in
  [docker/for-mac#68](https://github.com/docker/for-mac/issues/68)

* Use Mac System Configuration database to detect DNS

**File sharing (osxfs)**

* Fixed thread leak

* Fixed a malfunction of new directories that have the same name as an old directory that is still open

* Rename events now trigger DELETE and/or MODIFY `inotify` events
  (saving with TextEdit works now)

* Fixed an issue that caused `inotify` failure and crashes

* Fixed a directory file descriptor leak

* Fixed socket `chowns`

**Moby**

* Use default `sysfs` settings, transparent huge pages disabled

* `cgroup` mount to support `systemd` in containers

* Increase Moby `fs.file-max` to 524288

* Fixed Moby Diagnostics and Update Kernel

**HyperKit**

* HyperKit updated with `dtrace` support and lock fixes

### Docker for Mac 2016-08-11 1.12.0-afix release contains osxfs improvements. 

The fixed issues may have
been seen as failures with apt-get and npm in containers, missed inotify
events or unexpected unmounts.

**Bug fixes**

* osxfs: fixed an issue causing access to children of renamed directories to fail (symptoms: npm failures, apt-get failures)

* osxfs: fixed an issue causing some ATTRIB and CREATE inotify events to fail delivery and other inotify events to stop

* osxfs: fixed an issue causing all inotify events to stop when an ancestor directory of a mounted directory was mounted

* osxfs: fixed an issue causing volumes mounted under other mounts to spontaneously unmount


### Docker for Mac 1.12.0, 2016-07-28table release

**Components**

* Docker 1.12.0
* Docker Machine 0.8.0
* Docker Compose 1.8.0


---

# Release notes for previous versions

*Sección: Desktop*

This page contains release notes for older versions of Docker Desktop for Windows. 

## Stable Releases of 2018

### Docker Community Edition 18.06.1-ce-win73 2018-08-29

* Upgrades
  - [Docker 18.06.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.1-ce)

* Bug fixes and minor changes
  - Fix bug in VM activity detection, preventing Docker Desktop from starting. Fixes [docker/for-win#2404](https://github.com/docker/for-win/issues/2404)
  - Fix bug in detection when Windows service is not running, and propose to restart the service.
  - Fix local DNS failing to resolve inside containers. Fixes [docker/for-win#2301](https://github.com/docker/for-win/issues/2301), [docker/for-win#2304](https://github.com/docker/for-win/issues/2304)
  - Fix Kubernetes status display after reset to factory default
  - Fix bug where `host.docker.internal` is not resolved in some cases. Fixes [docker/for-win#2402](https://github.com/docker/for-win/issues/2402)
  - Use a 1MB vhdx blocksize instead of the default 32MB. See [docker/for-win#244](https://github.com/docker/for-win/issues/244). Also see [Microsoft Best Practices for running Linux on Hyper-V](https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/best-practices-for-running-linux-on-hyper-v)
  - Fix diagnostics in specific cases when the Windows service is not started.
  - Changed the samba default file permission to avoid an issue with too open rights. Fixes [docker/for-win#2170](https://github.com/docker/for-win/issues/2170)
  - On RS5 insider, fixed wrong detection of missing feature "Containers" requiring you to install the feature and then reboot.

### Docker Community Edition 18.06.0-ce-win72 2018-07-26

* New
  - Renewed signing certificate. The installer may show a Windows Defender popup until the renewed certificate is allowlisted. Click "More info" to view the app is published by "Docker Inc" and run it.

* Bug fixes and minor changes
  - Fix bug in automatic feature enabling if "Hyper-V" and "Containers" Windows features are not enabled already when starting Docker Desktop.

### Docker Community Edition 18.06.0-ce-win70 2018-07-25

* Upgrades
  - [Docker 18.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.0-ce)
  - [Docker Machine 0.15.0](https://github.com/docker/machine/releases/tag/v0.15.0)
  - [Docker compose 1.22.0](https://github.com/docker/compose/releases/tag/1.22.0)
  - [LinuxKit v0.4](https://github.com/linuxkit/linuxkit/releases/tag/v0.4)
  - Linux Kernel 4.9.93 with CEPH, DRBD, RBD, MPLS_ROUTING and MPLS_IPTUNNEL enabled

* New
  - Kubernetes Support. You can now run a single-node Kubernetes cluster from the "Kubernetes" Pane in Docker for Windows settings and use kubectl commands as well as Docker commands. See [the Kubernetes section](../use-desktop/kubernetes.md)

* Bug fixes and minor changes
  - AUFS storage driver is deprecated in Docker Desktop and AUFS support will be removed in the next major release. You can continue with AUFS in Docker Desktop 18.06.x, but you will need to reset the disk image (in Settings > Reset menu) before updating to the next major update. You can check documentation to [save images](/reference/cli/docker/image/save/#examples) and [backup volumes](../../engine/storage/volumes.md#back-up-restore-or-migrate-data-volumes)
  - Fix bug which would in some cases cause virtual machine logs to be written to RAM rather than disk, and the virtual machine to hang.
  - Fix security issue with named pipe connection to docker service.
  - Fix VPNKit memory leak. Fixes [docker/for-win#2087](https://github.com/docker/for-win/issues/2087), [moby/vpnkit#371](https://github.com/moby/vpnkit/issues/371)
  - Fix restart issue when using Windows fast startup on latest 1709 Windows updates. Fixes [docker/for-win#1741](https://github.com/docker/for-win/issues/1741), [docker/for-win#1741](https://github.com/docker/for-win/issues/1741)
  - DNS name `host.docker.internal` can be used for host resolution from Windows Containers.  Fixes [docker/for-win#1976](https://github.com/docker/for-win/issues/1976)
  - Fix broken link in diagnostics window.
  - Added log rotation for docker-ce logs inside the virtual machine.
  - Changed smb permission to avoid issue when trying to manipulate files with different users in containers. Fixes [docker/for-win#2170](https://github.com/docker/for-win/issues/2170)

### Docker Community Edition 18.03.1-ce-win65 2018-04-30

* Upgrades
  - [Docker 18.03.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.1-ce)
  - [Docker compose 1.21.1](https://github.com/docker/compose/releases/tag/1.21.1)
  - [Notary 0.6.1](https://github.com/docker/notary/releases/tag/v0.6.1)

* Bug fixes and minor changes
  - Fix startup failure when the HOME environment variable is already defined (typically started from the command line). Fixes [docker/for-win#1880](https://github.com/docker/for-win/issues/1880)
  - Fix startup failure due to incompatibility with other programs (like Razer Synapse 3). Fixes [docker/for-win#1723](https://github.com/docker/for-win/issues/1723)

### Docker Community Edition 18.03.1-ce-win64 2018-04-26

* Upgrades
  - [Docker 18.03.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.1-ce)
  - [Docker compose 1.21.0](https://github.com/docker/compose/releases/tag/1.21.0)
  - [Notary 0.6.1](https://github.com/docker/notary/releases/tag/v0.6.1)

* Bug fixes and minor changes
  - Fix startup failure when the HOME environment variable is already defined (typically started from the command line). Fixes [docker/for-win#1880](https://github.com/docker/for-win/issues/1880)
  - Fix startup failure due to incompatibility with other programs (like Razer Synapse 3). Fixes [docker/for-win#1723](https://github.com/docker/for-win/issues/1723)

### Docker Community Edition 18.03.0-ce-win59 2018-03-26

* Upgrades
  - [Docker 18.03.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce)
  - [Docker Machine 0.14.0](https://github.com/docker/machine/releases/tag/v0.14.0)
  - [Docker compose 1.20.1](https://github.com/docker/compose/releases/tag/1.20.1)
  - [Notary 0.6.0](https://github.com/docker/notary/releases/tag/v0.6.0)
  - Linux Kernel 4.9.87
  - AUFS 20180312

* New
  - Virtual machine disk size can be changed in settings. Fixes [docker/for-win#105](https://github.com/docker/for-win/issues/105)
  - Virtual machine swap size can be changed in settings.
  - New menu item to restart Docker.
  - Support NFS Volume sharing. See [docker/for-win#1700](https://github.com/docker/for-win/issues/1700)
  - Allow to activate Windows Containers during installation (avoid virtual machine disk creation and virtual machine boot when working only on Windows containers). See [docker/for-win#217](https://github.com/docker/for-win/issues/217).
  - Experimental feature: LCOW containers can now be run next to Windows containers (on Windows RS3 build 16299 and later). Use `--platform=linux` in Windows container mode to run Linux Containers On Windows. Note that LCOW is experimental; it requires the daemon `experimental` option.

* Bug fixes and minor changes
  - Fix Windows Containers port forwarding on Windows 10 build 16299 post KB4074588. Fixes [docker/for-win#1707](https://github.com/docker/for-win/issues/1707), [docker/for-win#1737](https://github.com/docker/for-win/issues/1737)
  - Fix daemon not starting properly when setting TLS-related options.
  - DNS name `host.docker.internal` should be used for host resolution from containers. Older aliases (still valid) are deprecated in favor of this one. (See https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06).
  - Fix for the HTTP/S transparent proxy when using "localhost" names (for example, `host.docker.internal`). Fixes [docker/for-win#1130](https://github.com/docker/for-win/issues/1130)
  - Fix Linuxkit start on Windows RS4 Insider. Fixes [docker/for-win#1458](https://github.com/docker/for-win/issues/1458), [docker/for-win#1514](https://github.com/docker/for-win/issues/1514), [docker/for-win#1640](https://github.com/docker/for-win/issues/1640)
  - Fix risk of privilege escalation. (https://www.tenable.com/sc-report-templates/microsoft-windows-unquoted-service-path-vulnerability)
  - All users present in the docker-users group are now able to use Docker. Fixes [docker/for-win#1732](https://github.com/docker/for-win/issues/1732)
  - Migration of Docker Toolbox images is not proposed in Docker For Windows installer (still possible to migrate Toolbox images manually).
  - Better cleanup for Windows containers and images on reset/uninstall. Fixes [docker/for-win#1580](https://github.com/docker/for-win/issues/1580), [docker/for-win#1544](https://github.com/docker/for-win/issues/1544), [docker/for-win#191](https://github.com/docker/for-win/issues/191)
  - Desktop icon creation is optional in installer; do not recreate Desktop icon on upgrade (effective on next upgrade). Fixes [docker/for-win#246](https://github.com/docker/for-win/issues/246), [docker/for-win#925](https://github.com/docker/for-win/issues/925), [docker/for-win#1551](https://github.com/docker/for-win/issues/1551)

### Docker Community Edition 17.12.0-ce-win47 2018-01-12

* Bug fixes and minor changes
  - Fix linuxkit port-forwarder sometimes not being able to start. Fixes [docker/for-win#1506](https://github.com/docker/for-win/issues/1506)
  - Fix certificate management when connecting to a private registry. Fixes [docker/for-win#1512](https://github.com/docker/for-win/issues/1512)
  - Fix Mount compatibility when mounting drives with `-v //c/...`, now mounted in /host_mnt/c in the linuxkit virtual machine. Fixes [docker/for-win#1509](https://github.com/docker/for-win/issues/1509), [docker/for-win#1516](https://github.com/docker/for-win/issues/1516), [docker/for-win#1497](https://github.com/docker/for-win/issues/1497)
  - Fix icon displaying edge. Fixes [docker/for-win#1508](https://github.com/docker/for-win/issues/1508)

### Docker Community Edition 17.12.0-ce-win46 2018-01-09

* Upgrades
  - [Docker 17.12.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce)
  - [Docker compose 1.18.0](https://github.com/docker/compose/releases/tag/1.18.0)
  - [Docker Machine 0.13.0](https://github.com/docker/machine/releases/tag/v0.13.0)
  - Linux Kernel 4.9.60

* New
  - Virtual machine entirely built with linuxkit
  - Add localhost port forwarder for Windows (thanks @simonferquel). Use Microsoft localhost port forwarder when it is available (insider build RS4).

* Bug fixes and minor changes
  - Display various component versions in About box.
  - Fix vpnkit issue when username has spaces. See [docker/for-win#1429](https://github.com/docker/for-win/issues/1429)
  - Diagnostic improvements to get VM logs before VM shutdown.
  - Fix installer check for not supported Windows `CoreCountrySpecific` Edition.
  - Fix a class of startup failures where the database fails to start. See [docker/for-win#498](https://github.com/docker/for-win/issues/498)
  - Links in update changelog now open the default browser instead of IE. (fixes [docker/for-win#1311](https://github.com/docker/for-win/issues/1311))

## Stable Releases of 2017

### Docker Community Edition 17.09.1-ce-win42 2017-12-11

* Upgrades
  - [Docker 17.09.1-ce](https://github.com/docker/docker-ce/releases/tag/v17.09.1-ce)
  - [Docker compose 1.17.1](https://github.com/docker/compose/releases/tag/1.17.1)
  - [Docker Machine 0.13.0](https://github.com/docker/machine/releases/tag/v0.13.0)

* Bug fixes and minor changes
  - Fix bug during Windows fast-startup process. Fixes [for-win/#953](https://github.com/docker/for-win/issues/953)
  - Fix uninstaller issue (in some specific cases dockerd process was not killed properly)
  - Fix Net Promoter Score Gui bug. Fixes [for-win/#1277](https://github.com/docker/for-win/issues/1277)
  - Fix `docker.for.win.localhost` not working in proxy settings. Fixes [for-win/#1130](https://github.com/docker/for-win/issues/1130)
  - Increased timeout for virtual machine boot startup to 2 minutes.


### Docker Community Edition 17.09.0-ce-win33 2017-10-06

* Bug fixes
  - Fix Docker For Windows unable to start in some cases: removed use of libgmp sometimes causing the vpnkit process to die.

### Docker Community Edition 17.09.0-ce-win32 2017-10-02

* Upgrades
  - [Docker 17.09.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce)
  - [Docker Compose 1.16.1](https://github.com/docker/compose/releases/tag/1.16.1)
  - [Docker Machine 0.12.2](https://github.com/docker/machine/releases/tag/v0.12.2)
  - [Docker Credential Helpers 0.6.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.0)
  - Linux Kernel 4.9.49
  - AUFS 20170911

* New
  - Windows Docker daemon is now started as service for better lifecycle management
  - Store Linux daemon configuration in ~\.docker\daemon.json instead of settings file
  - Store Windows daemon configuration in C:\ProgramData\Docker\config\daemon.json instead of settings file
  - VPNKit: add support for ping!
  - VPNKit: add slirp/port-max-idle-timeout to allow the timeout to be adjusted or even disabled
  - VPNKit: bridge mode is default everywhere now
  - Add `Skip This Version` button in update window

* Security fixes
  - VPNKit: security fix to reduce the risk of DNS cache poisoning attack (reported by Hannes Mehnert https://hannes.nqsb.io/)

* Bug fixes and minor changes
  - Kernel: Enable TASK_XACCT and TASK_IO_ACCOUNTING
  - Rotate logs in the virtual machine more often (docker/for-win#244)
  - Reset to default stops all engines and removes settings including all daemon.json files
  - Better backend service checks (related to https://github.com/docker/for-win/issues/953)
  - Fix auto updates checkbox, no need to restart the application
  - Fix check for updates menu when auto updates was disable
  - VPNKit: do not block startup when ICMP permission is denied. (Fixes docker/for-win#1036, docker/for-win#1035, docker/for-win#1040)
  - VPNKit: change protocol to support error messages reported back from the server
  - VPNKit: fix a bug which causes a socket to leak if the corresponding TCP connection is idle
    for more than 5 minutes (related to [docker/for-mac#1374](https://github.com/docker/for-mac/issues/1374))
  - VPNKit: improve the logging around the UNIX domain socket connections
  - VPNKit: automatically trim whitespace from int or bool database keys
  - Do not move credentials into the credential store at startup

### Docker Community Edition 17.06.2-ce-win27 2017-09-06

* Upgrades
  - [Docker 17.06.2-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.2-ce)
  - [Docker Machine 0.12.2](https://github.com/docker/machine/releases/tag/v0.12.2)

### Docker Community Edition 17.06.1-ce-rc1-win24 2017-08-24

**Upgrades**

- [Docker 17.06.1-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.06.1-ce-rc1)
- Linux Kernel 4.9.36
- AUFS 20170703

**Bug fixes and minor**

- Fix locked container id file (Fixes [docker/for-win#818](https://github.com/docker/for-win/issues/818))
- Avoid expanding variables in PATH env variable (Fixes [docker/for-win#859](https://github.com/docker/for-win/issues/859))

### Docker Community Edition 17.06.0-ce-win18 2017-06-28

**Upgrades**

- [Docker 17.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce)
- [Docker Credential Helpers 0.5.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.2)
- [Docker Machine 0.12.0](https://github.com/docker/machine/releases/tag/v0.12.0)
- [Docker compose 1.14.0](https://github.com/docker/compose/releases/tag/1.14.0)
- Linux Kernel 4.9.31

**New**

- Windows Server 2016 support
- Windows 10586 is marked as deprecated; it is not supported going forward in stable releases
- Integration with Docker Cloud, with the ability to control remote Swarms from the local command line interface (CLI) and view your repositories
- Unified login between the Docker CLI and Docker Hub, Docker Cloud.
- Sharing a drive can be done on demand, the first time a mount is requested
- Add an experimental DNS name for the host: docker.for.win.localhost
- Support for client (i.e. "login") certificates for authenticating registry access (fixes [docker/for-win#569](https://github.com/docker/for-win/issues/569))
- New installer experience

**Bug fixes and minor changes**

- Fixed group access check for users logged in with Active Directory (fixes [docker/for-win#785](https://github.com/docker/for-win/issues/785))
- Checked environment variables and add some warnings in logs if they can cause docker to fail
- Many processes that were running in admin mode now run within the user identity
- Cloud federation command lines now open in the user home directory
- Named pipes are now created with more constrained security descriptors to improve security
- Security fix: Users must be part of the specific group "docker-users" to run Docker for Windows
- Reset to default / uninstall also reset Docker cli settings and logout user from Docker Cloud and registries
- Detected a bitlocker policy preventing windows containers to work
- Fixed an issue on filesharing when explicitly disabled on vmswitch interface
- Fixed virtual machine not starting when the machine had a very long name
- Fixed a bug where Windows daemon.json file was not written (fixes [docker/for-win#670](https://github.com/docker/for-win/issues/670))
- Added patches to the kernel to fix VMBus crash
- Named pipe client connection should not trigger dead locks on `docker run` with data in stdin any more
- Buffered data should be treated correctly when docker client requests are upgraded to raw streams

### Docker Community Edition 17.03.1-ce-win12  2017-05-12

**Upgrades**

- Security fix for CVE-2017-7308

### Docker Community Edition 17.03.0, 2017-03-02

**New**

- Renamed to Docker Community Edition
- Integration with Docker Cloud: control remote Swarms from the local CLI and view your repositories. This feature is going to be rolled out to all users
  progressively

**Upgrades**

- [Docker 17.03.0-ce](https://github.com/docker/docker/releases/tag/v17.03.0-ce)
- [Docker Compose 1.11.2](https://github.com/docker/compose/releases/tag/1.11.2)
- [Docker Machine 0.10.0](https://github.com/docker/machine/releases/tag/v0.10.0)
- Linux kernel 4.9.12

**Bug fixes and minor changes**

- Matched Hyper-V Integration Services by ID, not name
- Don't consume 100% CPU when the service is stopped
- Log the diagnostic id when uploading
- Improved firewall handling: stop listing the rules since it can take a lot of time
- Don't rollback to the previous engine when the desired engine fails to start
- Don't use port 4222 inside the Linux virtual machine
- Fixed startup error of ObjectNotFound in Set-VMFirmware
- Added detailed logs when firewall is configured
- Added a link to the Experimental Features documentation
- Fixed the copyright in the About dialog
- VPNKit: fix unmarshalling of DNS packets containing pointers to pointers to labels
- VPNKit: set the Recursion Available bit on DNS responses from the cache
- VPNKit: Avoid diagnostics to capture too much data
- VPNKit: fix a source of occasional packet loss (truncation) on the virtual ethernet link
- Fixed negotiation of TimeSync protocol version (through kernel update)

### Docker for Windows 1.13.1, 2017-02-09

- [Docker 1.13.1](https://github.com/docker/docker/releases/tag/v1.13.1)
- [Docker Compose 1.11.1](https://github.com/docker/compose/releases/tag/1.11.1)
- Linux kernel 4.9.8

**Bug fixes and minor changes**

- Add link to experimental features
- New 1.13 cancellable operations should now be properly handled by the Docker for desktop
- Various typos fixes
- Fix in Hyper-V VM setup (should fix `ObjectNotFound` errors)

### Docker for Windows 1.13.0, 2017-01-19
- [Docker 1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)
- [Docker Compose 1.10](https://github.com/docker/compose/releases/tag/1.10.0)
- [Docker Machine 0.9.0](https://github.com/docker/machine/releases/tag/v0.9.0)
- [Notary 0.4.3](https://github.com/docker/notary/releases/tag/v0.4.3)
- Linux kernel 4.9.4

**New**

- Windows containers
- Improved UI for Daemon.json editing
- VHDX file containing images and non-host mounted volumes can be moved
  (using "advanced" tab in the UI)
- Support for arm, aarch64, ppc64le architectures using qemu
- TRIM support for disk (shrinks virtual disk)
- Virtual machine's time synchronization is forced after the host wakes from sleep mode
- Docker Experimental mode can be toggled

**Bug fixes and minor changes**

- Improved Proxy UI
- Improvements to Logging and Diagnostics
- About Box is now copy/paste enabled
- Improvements in drive sharing code
- Optimized boot process
- Trend Micro Office Scan made the API proxy think no drive was shared
- Show a link to the virtualization documentation
- Always remove the disk on factory reset
- VPNKit: Improved diagnostics
- VPNKit: Forwarded UDP datagrams have correct source port numbers
- VPNKit: If one request fails, allow other concurrent requests to succeed.
  For example this allows IPv4 servers to work even if IPv6 is broken.
- VPNKit: Fix bug which could cause the connection tracking to
  underestimate the number of active connections
- VPNKit: add a local cache of DNS responses

## Stable Releases of 2016

### Docker for Windows 1.12.5, 2016-12-20
- Docker 1.12.5
- Docker Compose 1.9.0

### Skipped Docker for Windows 1.12.4

We did not distribute a 1.12.4 stable release

### Docker for Windows 1.12.3, 2016-11-09

**New**

- Restore the virtual machine's configuration after user changes

- Detect firewall configurations that might block file sharing

- Send more GUI usage statistics to help us improve the product

- The path to HyperV disks is not hardcoded anymore, making the Toolbox import work with non-standard paths

- Verify that all HyperV features are enabled

- Added Moby console to the logs

- Save the current engine with the other settings

- Notary version 0.4.2 installed

- Reworked the File Sharing dialog and underlying mechanism
  - Pre-fill username
  - Faster and more reliable feedback when the user/password is not valid
  - Better support for domain users
  - Error message in Logs when File Sharing failed for other reasons

**Upgrades**

- Docker 1.12.3
- Linux Kernel 4.4.27
- Docker Machine 0.8.2
- Docker Compose 1.8.1
- aufs 20160912

**Bug fixes and minor changes**

**General**

- Added the settings to the diagnostics

- Made sure we didn't use an older Nlog library from the GAC

- Fixed a password escaping regression

- Supports writing large values to the database, specially for trusted CAs

- Preserves the Powershell stacktraces

- Writes OS and Application versions at the top of each log file

- Don't recreate the virtual machine if only the DNS server is set

- The uninstaller now kills the service if it failed to stop it properly

- Improved debug information

**Networking**

- VpnKit is now restarted if it stops

- VpnKit: impose a connection limit to avoid exhausting file descriptors

- VpnKit: handle UDP datagrams larger than 2035 bytes

- VpnKit: reduce the number of file descriptors consumed by DNS

**File sharing**


- Faster mount/unmount of shared drives

- Added a timeout to mounting/unmounting a shared drive

**Hyper-V**

- Make sure invalid "DockerNat" switches are not used

**Moby**

- Increase default ulimit for memlock (fixes [https://github.com/docker/for-mac/issues/801](https://github.com/docker/for-mac/issues/801))

### Docker for Windows 1.12.1, 2016-09-16

**New**

* To support trusted registry transparently, all trusted CAs (root or intermediate) on the Windows host are automatically copied to Moby

* `Reset Credentials` also unshares the shared drives

* Logs are now rotated every day

* Support multiple DNS servers

* Added `mfsymlinks` SMB option to support symlinks on bind mounted folder

* Added `nobrl` SMB option to support `sqlite` on bind mounted folders

* Detect outdated versions of Kitematic

**Upgrades**

* Docker 1.12.1
* Docker machine 0.8.1
* Linux kernel 4.4.20
* aufs 20160905

**Bug fixes and minor changes**

**General**

* Uploading a diagnostic now shows a proper status message in the Settings

* Docker stops asking to import from the Toolbox after an upgrade

* Docker can now import from the Toolbox just after HyperV is activated

* Added more debug information to the diagnostics

* Sending anonymous statistics doesn't hang anymore when Mixpanel is not available

* Support newlines in release notes

* Improve the error message when the Docker daemon is not responding

* The configuration database is now stored in memory

* Preserve the stacktrace of PowerShell errors

* Display service stacktrace in error windows

**Networking**

* Improve name servers discovery
* VpnKit supports search domains
* VpnKit is now compiled with OCaml 4.03 rather than 4.02.3

**File sharing**

* Set `cifs` version to 3.02

* VnpKit: reduce the number of sockets used by UDP NAT, reduce the probability

* `slirp`: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules time out earlier than expected

* Fixed password handling for host file system sharing

**Hyper-V**

* Automatically disable lingering net adapters that prevent Docker from starting or using the network

* Automatically delete duplicated MobyLinuxVMs on a `reset to factory defaults`

* Improved the HyperV detection and activation mechanism

**Moby**

* Fixed Moby Diagnostics and Update Kernel

* Use default `sysfs` settings, transparent huge pages disabled

* `Cgroup` mount to support `systemd` in containers

**Known issues**

* Docker automatically disables lingering net adapters. The only way to remove them is manually using `devmgmt.msc`.

### Docker for Windows 1.12.0, 2016-07-28
 
- First stable release

**Components**

* Docker 1.12.0
* Docker Machine 0.8.0
* Docker Compose 1.8.0


---

# Docker Desktop for Mac Edge release notes

*Sección: Desktop*

This page contains information about Docker Desktop Edge releases. Edge releases give you early access to our newest features. Note that some of the features may be experimental, and some of them may not ever reach the Stable release.

For Docker Desktop system requirements, see
[What to know before you install](../setup/install/mac-install.md#system-requirements).

## Docker Desktop Community 2.5.4

2020-12-07

### Upgrades

- [Docker Engine 20.10.0-rc2](https://github.com/docker/docker-ce/blob/master/CHANGELOG.md#20100)
- [Go 1.15.6](https://github.com/golang/go/issues?q=milestone%3AGo1.15.6+label%3ACherryPickApproved+)

### Bug fixes and minor changes

- Changed the «Update and quit» menu entry to «Update and restart».
- Fixed the check for updates dialog reporting the build number instead of the version number of a new version.
- Downgraded the kernel to [4.19.121](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.121-2a1dbedf3f998dac347c499808d7c7e029fbc4d3-amd64/images/sha256-4e7d94522be4f25f1fbb626d5a0142cbb6e785f37e437f6fd4285e64a199883a?context=repo) to reduce the CPU usage of hyperkit. Fixes [docker/for-mac#5044](https://github.com/docker/for-mac/issues/5044)
- Fixed a bug that DNS would return `NXDOMAIN` when a name exists but the type of record was not found. Fixes [docker/for-mac#5020](https://github.com/docker/for-mac/issues/5020). Related to https://gitlab.alpinelinux.org/alpine/aports/-/issues/11879
- Avoid caching bad file sizes and modes when using `osxfs`. Fixes [docker/for-mac#5045](https://github.com/docker/for-mac/issues/5045).

## Docker Desktop Community 2.5.3

2020-11-30

### Upgrades

- [Compose CLI v1.0.3](https://github.com/docker/compose-cli/releases/tag/v1.0.3)

### Bug fixes and minor changes

- Fixed a possible file sharing error where a file may appear to have the wrong size in a container when it is modified on the host. This is a partial fix for [docker/for-mac#4999](https://github.com/docker/for-mac/issues/4999).
- Removed unnecessary log messages which slow down filesystem event injection.

## Docker Desktop Community 2.5.2

2020-11-26

### New

- Use of three digit version number.
- Starting with Docker Desktop 2.5.2, updates will be much smaller as they will be applied using delta patches.

### Bug fixes and minor changes

- Re-enabled the experimental SOCKS proxy. Fixes [docker/for-mac#5048](https://github.com/docker/for-mac/issues/5048).
- Fixed an unexpected EOF error when trying to start a non-existing container with `-v /var/run/docker.sock:`. See [docker/for-mac#5025](https://github.com/docker/for-mac/issues/5025).
- Display an error message instead of crashing when the application needs write access on specific directories. See [docker/for-mac#5068](https://github.com/docker/for-mac/issues/5068)

## Docker Desktop Community 2.5.1.0

2020-11-18

This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing Docker Desktop.

### Upgrades

- [Docker Engine 20.10.0-rc1](https://github.com/docker/docker-ce/blob/master/CHANGELOG.md#20100)
- [Compose CLI v1.0.2](https://github.com/docker/compose-cli/releases/tag/v1.0.2)
- [Snyk v1.424.4](https://github.com/snyk/snyk/releases/tag/v1.424.4)
- [Kubernetes 1.19.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.3)

### Bug fixes and minor changes

- Renamed 'Run Diagnostics' to 'Get support'.
- Fixed an issue that caused Docker Desktop to crash on MacOS 11.0 (Big Sur) when VirtualBox was also installed. See [docker/for-mac#4997](https://github.com/docker/for-mac/issues/4997).
- Removed BlueStacks warning message. Fixes [docker/for-mac#4863](https://github.com/docker/for-mac/issues/4863).
- Made container start faster in cases where shared volumes have lots of files. Fixes [docker/for-mac#4957](https://github.com/docker/for-mac/issues/4957).
- File sharing: fixed changing ownership of read-only files. Fixes [docker/for-mac#4989](https://github.com/docker/for-mac/issues/4989), [docker/for-mac#4964](https://github.com/docker/for-mac/issues/4964).
- Fixed an unexpected EOF error when trying to start a non-existing container. See [docker/for-mac#5025](https://github.com/docker/for-mac/issues/5025).

## Docker Desktop Community 2.4.2.0

2020-10-19

### New

- If you have enabled [Vulnerability Scanning](/docker-hub/repos/manage/vulnerability-scanning/) in Docker Hub, the scan results will now appear in Docker Desktop.

### Upgrades

- [Docker Engine 20.10.0 beta1](https://github.com/docker/docker-ce/blob/0fc7084265b3786a5867ec311d3f916af7bf7a23/CHANGELOG.md)
- [Docker Compose CLI - 0.1.22](https://github.com/docker/compose-cli/releases/tag/v0.1.22)
- [Linux kernel 5.4.39](https://hub.docker.com/layers/linuxkit/kernel/5.4.39-f39f83d0d475b274938c86eaa796022bfc7063d2/images/sha256-8614670219aca0bb276d4749e479591b60cd348abc770ac9ecd09ee4c1575405?context=explore).
- [Kubernetes 1.19.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.2)
- [Go 1.15.2](https://github.com/golang/go/issues?q=milestone:Go1.15.2+label:CherryPickApproved)

### Bug fixes and minor changes

- When sharing Linux directories (`/var`, `/bin`, etc) with containers, Docker Desktop avoids watching paths in the host file system.
- When sharing a file into a container (e.g. `docker run -v ~/.gitconfig`) Docker Desktop does not watch the parent directory. Fixes [docker/for-mac#4981](https://github.com/docker/for-mac/issues/4981).
- gRPC FUSE: fix `chown` when the file is read-only. Fixes `rabbitmq`, see [docker/for-mac#4964](https://github.com/docker/for-mac/issues/4964).
- gRPC FUSE: generate `ATTRIB` inotify events as well as `MODIFY`. Fixes [docker/for-mac#4962](https://github.com/docker/for-mac/issues/4962).
- gRPC FUSE: return `EOPNOTSUPP` from `fallocate` for unsupported modes. Fixes `minio`. See [docker/for-mac#4964](https://github.com/docker/for-mac/issues/4964).
- Fixed an issue related to NFS mounting. See [docker/for-mac#4958](https://github.com/docker/for-mac/issues/4958).
- Always flush file system caches synchronously on container start. See [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).
- Allow symlinks to point outside of shared volumes. Fixes [docker/for-mac#4862](https://github.com/docker/for-mac/issues/4862).
- Diagnostics: avoid hanging when Kubernetes is in a broken state.
- Fixed automatic start on log in. See [docker/for-mac#4877](https://github.com/docker/for-mac/issues/4877) and [docker/for-mac#4890](https://github.com/docker/for-mac/issues/4890).

## Docker Desktop Community 2.4.1.0

2020-10-01

### Upgrades

- [Docker Compose CLI - 0.1.18](https://github.com/docker/compose-cli)
- [Docker Compose 1.27.4](https://github.com/docker/compose/releases/tag/1.27.4)
- [Snyk v1.399.1](https://github.com/snyk/snyk/releases/tag/v1.399.1)
- [Docker Engine 19.03.13](https://github.com/docker/docker-ce/releases/tag/v19.03.13)

### Bug fixes and minor changes

- Docker Desktop always flushes filesystem caches synchronously on container start. See [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).
- Docker Desktop now supports `S_ISUID`, `S_ISGID` and `S_ISVTX` in calls to `chmod(2)` on shared filesystems. See [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).
- Fixed a possible premature file handle close when using `gRPC-FUSE`.

## Docker Desktop Community 2.3.7.0

2020-09-17

### New

- [Amazon ECR Credential Helper](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.4.0)

### Upgrades

- [Docker ACI integration 0.1.15](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.15)
- [Snyk v0.393.0](https://github.com/snyk/snyk/releases/tag/v1.393.0)

### Bug fixes and minor changes

- Fixed automatic start on log in. See [docker/for-mac#4877](https://github.com/docker/for-mac/issues/4877) and [docker/for-mac#4890](https://github.com/docker/for-mac/issues/4890).
- Docker Desktop now allows symlinks to point outside of shared volumes. Fixes [docker/for-mac#4862](https://github.com/docker/for-mac/issues/4862).
- Removed an artificial file descriptor limit (`setrlimit`) of `10240`. Docker Desktop now relies on the kernel to impose limits via `kern.maxfiles` and `kern.maxfilesperproc`.
- Fixed the VM debug shell used for low-level debugging.
- Fixed compatibility with Go 1.15 clients. See [docker/for-mac#4855](https://github.com/docker/for-mac/issues/4855).
- Avoid exposing `/host_mnt` paths in `docker container inspect` and `docker volume inspect`. Fixes [docker/for-mac#4859](https://github.com/docker/for-mac/issues/4859).
- Fixed container logs lagging under heavy load. See [docker/for-win#8216](https://github.com/docker/for-win/issues/8216).

### Known issues

- The `clock_gettime64` system call returns `EPERM` rather than `ENOSYS`
  in i386 images. To work around this issue, disable `seccomp` by using
  the `--privileged` flag. See [docker/for-win#8326](https://github.com/docker/for-win/issues/8326).

## Docker Desktop Community 2.3.6.1

2020-09-08

### Upgrades

- [Docker Compose 1.27.0](https://github.com/docker/compose/releases/tag/1.27.0)

### Bug fixes and minor changes

- Docker Desktop now correctly displays the state of "Use gRPC FUSE for file sharing" in the UI. Fixes [docker/for-mac#4864](https://github.com/docker/for-mac/issues/4864).

## Docker Desktop Community 2.3.6.0

2020-09-01

### New

- In partnership with Snyk, Docker Desktop launches vulnerability scanning for Docker local images.
- Docker ECS plugin has been replaced by ECS cloud integration
- Docker UI:
  - The Images view now has search and filter options.
  - You can now push an image to Docker Hub using the Remote repositories drop-down menu.
- WSL 2 files and directories can now be mounted from the Windows Docker CLI with e.g. `docker run -v \\wsl$\Ubuntu\my-files:/my-files ...`.

### Removal

- Support for MacOS 10.13 has ended, you will need to update your system to keep using Docker Desktop.

### Upgrades

- [Alpine 3.12](https://alpinelinux.org/posts/Alpine-3.12.0-released.html)
- [Kubernetes 1.18.8](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.8)

### Bug fixes and minor changes

- Fixed a Mac CPU usage bug by removing the serial console from `hyperkit`, see [docker/roadmap#12](https://github.com/docker/roadmap/issues/12#issuecomment-663163280). To open a shell in the VM use either `nc -U ~/Library/Containers/com.docker.docker/Data/debug-shell.sock` (on Mac) or `putty -serial \\.\pipe\dockerDebugShell` (on Windows).

## Docker Desktop Community 2.3.5.0

2020-08-21

### New

- The **Images** view on the Dashboard now allows you to interact with images on Docker Hub. You can now pull a remote repository with specific tags from Docker Hub, or view the details of the repository on the Docker Hub page. To access the new Images view, from the Docker menu, select **Dashboard** > **Images**.

- Docker Desktop now enables BuildKit by default after a reset to factory defaults. To revert to the old docker build experience, go to **Preferences** > **Docker Engine** and then disable the BuildKit feature.

- Docker Desktop now uses **gRPC-FUSE** for file sharing by default. This has much faster file sharing and uses much less CPU than `osxfs`, especially when there are lots of file events on the host. To switch back to `osxfs`, go to **Preferences** > **General** and disable gRPC-FUSE.

### Upgrades

- [Go 1.14.7](https://github.com/golang/go/issues?q=milestone:Go1.14.7+label:CherryPickApproved)
- [Docker ECS integration v1.0.0-beta.5](https://github.com/docker/ecs-plugin/releases/tag/v1.0.0-beta.5)
- [Docker Engine 19.03.13-beta2](https://github.com/docker/docker-ce/releases/tag/v19.03.13-beta2)
- [Docker ACI integration 0.1.12](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.12)

### Removal

- The Mutagen file sync feature that we have been experimenting with in recent Edge releases has been removed. Thanks to everyone who has provided feedback on this feature. We are reconsidering how to integrate it based on the feedback we have received so far.

### Bug fixes and minor changes

- Moved **Dashboard** to the top of the whale menu.
- Improved the error handling when `dockerd` crashes.
- Fixed minor bugs in the **Images** view.

## Docker Desktop Community 2.3.4.0

2020-07-28

### New

- Docker Desktop introduces the new **Images** view to the Docker Dashboard. The Images view allows users to view a list of Docker images on the disk, run an image as a container, pull the latest version of an image from Docker Hub, inspect images, and remove any unwanted images from the disk.

  To access the new Images view, from the Docker menu, select **Dashboard** > **Images**.

### Upgrades

- [Docker ECS integration v1.0.0-beta.4](https://github.com/docker/ecs-plugin/releases/tag/v1.0.0-beta.4)
- [Kubernetes 1.18.6](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.6)

### Bug fixes and minor changes

- Copying the container logs from the dashboard does not copy the ANSI color codes to the clipboard anymore.
- Mutagen two-way sync now uses `.dockersyncignore` rather than `.dockerignore` to exclude files.

## Docker Desktop Community 2.3.3.2

2020-07-21

### Upgrades

- [Docker ECS integration v1.0.0-beta.2](https://github.com/docker/ecs-plugin/releases/tag/v1.0.0-beta.2)
- [Docker ACI integration 0.1.10](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.10)

### Bug fixes and minor changes

- Mutagen uses the `.dockerignore` file when creating a session to filter the list of synchronized files. See [docker/for-mac#4621](https://github.com/docker/for-mac/issues/4621).
- Docker CLI commands can now bypass any active Mutagen synchronization for volumes using `:cached`. See [docker/for-mac#1592](https://github.com/docker/for-mac/issues/1592#issuecomment-651309816).

## Docker Desktop Community 2.3.3.0

2020-07-09

### Upgrades

- Beta release of Docker ECS integration v1.0.0-beta.1
- [Docker ACI integration v0.1.7](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.7)
- [Docker Compose 1.26.2](https://github.com/docker/compose/releases/tag/1.26.2)

### Bug fixes and minor changes

- Compose-on-Kubernetes is no longer included in the Docker Desktop installer. You can download it separately from the compose-on-kubernetes [release page](https://github.com/docker/compose-on-kubernetes/releases).
- Fixed an incompatibility between `hyperkit` and `osquery` which resulted in excessive `hyperkit` CPU usage. See [docker/for-mac#3499](https://github.com/docker/for-mac/issues/3499#issuecomment-639140844)
- Docker Desktop now respects consistency flags `cached`, `delegated`, `consistent` even when in a list of options (for example, `z,delegated`). See [docker/for-mac#4718](https://github.com/docker/for-mac/issues/4718).
- Docker Desktop now implements the shared volume flag `:delegated` by automatically setting up a two-way file sync with Mutagen.

## Docker Desktop Community 2.3.2.0

2020-06-25

### Upgrades

- [Docker 19.03.12](https://github.com/docker/docker-ce/releases/tag/v19.03.12)
- [Docker Compose 1.26.0](https://github.com/docker/compose/releases/tag/1.26.0)
- [Kubernetes 1.18.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.3)
- Beta release of the [Docker ACI integration](/engine/context/aci-integration/)

### Bug fixes and minor changes

- Fixed an issue with startup when the Kubernetes certificates have expired. See [docker/for-mac#4594](https://github.com/docker/for-mac/issues/4594).
- Fixed `hyperkit` on newer Macs / newer versions of `Hypervisor.framework`.
- Added support for the global Mutagen config file `~/.mutagen.yml`.
- Automatically set up a two-way file sync using `:delegated` option with `docker run -v` command.
- Re-added device-mapper to the embedded Linux kernel. See [docker/for-mac#4549](https://github.com/docker/for-mac/issues/4549).
- Improved diagnostics when using two-way synchronization with the Mutagen cache.
- Switched to Mutagen `posix-raw` symlink mode which fixes cases where the symlinks point outside the synchronized directory. See [docker/for-mac#4595](https://github.com/docker/for-mac/issues/4595).
- Removed the legacy Kubernetes context `docker-for-desktop`. The context `docker-desktop` should be used instead. See [docker/for-mac#4089](https://github.com/docker/for-mac/issues/4089).

## Docker Desktop Community 2.3.1.0

2020-05-20

### New

Docker Desktop introduces a directory caching mechanism to greatly improve disk performance in containers. This feature uses [mutagen.io](https://mutagen.io/) to sync files between the host and the containers and benefits from native disk performance.

We appreciate you trying out an early version of the Mutagen file sync feature. Please let us know your feedback by creating an issue in the [Docker Desktop for Mac GitHub](https://github.com/docker/for-mac/issues) repository with the `Mutagen` label.

### Upgrades

- [Docker Compose 1.26.0-rc4](https://github.com/docker/compose/releases/tag/1.26.0-rc4)
- Upgrade to Qemu 4.2.0, add Risc-V support

### Bug fixes and minor changes

- Fixed a performance regression when using shared volumes in 2.2.0.5. Fixes [docker/for-mac#4423](https://github.com/docker/for-mac/issues/4423).
- Fixed containers logs in Docker Desktop **Dashboard** which were sometimes truncated. Fixes [docker/for-win#5954](https://github.com/docker/for-win/issues/5954).

## Docker Desktop Community 2.3.0.1

2020-04-28

### Bug fixes and minor changes

- Fixed a bug that caused starting and stopping of a Compose application from the UI to fail when the path contains whitespace.

## Docker Desktop Community 2.3.0.0

2020-04-20

### Upgrades

- [Docker Compose 1.25.5](https://github.com/docker/compose/releases/tag/1.25.5)
- [Go 1.13.10](https://github.com/golang/go/issues?q=milestone%3AGo1.13.10+label%3ACherryPickApproved)
- [Linux kernel 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-ce15f646db9b062dc947cfc0c1deab019fa63f96-amd64/images/sha256-6c252199aee548e4bdc8457e0a068e7d8e81c2649d4c1e26e4150daa253a85d8?context=repo)
- LinuxKit [init](https://hub.docker.com/layers/linuxkit/init/1a80a9907b35b9a808e7868ffb7b0da29ee64a95/images/sha256-64cc8fa50d63940dbaa9979a13c362c89ecb4439bcb3ab22c40d300b9c0b597e?context=explore), [runc](https://hub.docker.com/layers/linuxkit/runc/69b4a35eaa22eba4990ee52cccc8f48f6c08ed03/images/sha256-57e3c7cbd96790990cf87d7b0f30f459ea0b6f9768b03b32a89b832b73546280?context=explore), and [containerd](https://hub.docker.com/layers/linuxkit/containerd/09553963ed9da626c25cf8acdf6d62ec37645412/images/sha256-866be7edb0598430709f88d0e1c6ed7bfd4a397b5ed220e1f793ee9067255ff1?context=explore)

### Bug fixes and minor changes

> Docker Desktop Edge 2.3.0.0 fixes one issue reported on the [docker/for-mac](https://github.com/docker/for-mac/issues) GitHub repository.

- IPv6 has been re-enabled in the embedded Linux kernel, so listening on IPv6 addresses works again. Fixed [docker/for-win#6206](https://github.com/docker/for-win/issues/6206) and [docker/for-mac#4415](https://github.com/docker/for-mac/issues/4415).
- Fixed a bug where containers disappeared from the UI when Kubernetes context is invalid. Fixes [docker/for-win#6037](https://github.com/docker/for-win/issues/6037).
- Fixed a file descriptor leak in `vpnkit-bridge`. Fixes [docker/for-win#5841](https://github.com/docker/for-win/issues/5841).
- Added a link to the Stable channel from the Docker Desktop UI.
- Made the embedded terminal resizable.
- Fixed bug where diagnostic upload would fail if the username contained spaces.

## Docker Desktop Community 2.2.3.0

2020-04-02

### Upgrades

- [Docker 19.03.8](https://github.com/docker/docker-ce/releases/tag/v19.03.8)
- [Docker Compose 1.26.0-rc3](https://github.com/docker/compose/releases/tag/1.26.0-rc3)
- [Linux 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-4e5d9e5f3bde0abf236f97e4a81b029ae0f5f6e7-amd64/images/sha256-11dc0f6ee3187088219ba1463ebb378f5093a7d98f176ddfd62dd6b741c2dd2d?context=repo)

### New

- Docker Desktop introduces a new onboarding tutorial upon first startup. The Quick Start tutorial guides users to get started with Docker in a few easy steps. It includes a simple exercise to build an example Docker image, run it as a container, push and save the image to Docker Hub.

### Bug fixes and minor changes

> Docker Desktop Edge 2.2.3.0 fixes 7 issues reported on the [docker/for-mac](https://github.com/docker/for-mac/issues) GitHub repository.

- Reduced the size of the Docker Desktop installer from 710 MB to 445 MB.
- Removed dangling `/usr/local/bin/docker-machine` symlinks which avoids custom installs of `docker-machine` being accidentally deleted in future upgrades. Note that if you have installed Docker Machine manually, then the install might have followed the symlink and installed Docker Machine in `/Applications/Docker.app`. In this case, you must manually reinstall Docker Machine after installing this version of Docker Desktop. Fixes [docker/for-mac#4208](https://github.com/docker/for-mac/issues/4208).
- Fixed a bug where the Docker UI could be started without the engine.
- Switched from `ahci-hd` to `virtio-blk` to avoid an AHCI deadlock, see [moby/hyperkit#94](https://github.com/moby/hyperkit/issues/94) and [docker/for-mac#1835](https://github.com/docker/for-mac/issues/1835).
- Capturing diagnostics is now faster and easier.
- Fixed an issue where a container port could not be exposed on a specific host IP. See [docker/for-mac#4209](https://github.com/docker/for-mac/issues/4209).
- Kubernetes: Persistent volumes created by claims are now stored in the virtual machine. Fixes [docker/for-win#5665](https://github.com/docker/for-win/issues/5665).
- Removed port probing from dashboard, just unconditionally showing links to ports that should be available. Fixes [docker/for-mac#4264](https://github.com/docker/for-mac/issues/4264).

### Known issues

- Loopback and unspecified IPv6 addresses (`::` and `::1`) within a container do not currently work. Some web servers and other programs may be using these addresses in their configuration files.

## Docker Desktop Community 2.2.2.0

2020-03-02

This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing Docker Desktop.

### Upgrades

- [Kubernetes 1.16.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.16.5)
- [Go 1.13.8](https://golang.org/doc/devel/release.html#go1.13)

### Bug fixes and minor changes

- Docker Desktop now shares `/var/folders` by default as it stores per-user temporary files and caches.
- Ceph support has been removed from Docker Desktop to save disk space.

## Docker Desktop Community 2.2.1.0

2020-02-12

### Upgrades

- [Docker Compose 1.25.4](https://github.com/docker/compose/releases/tag/1.25.4)
- [Go 1.12.16](https://golang.org/doc/devel/release.html#go1.12)

## Docker Desktop Community 2.1.7.0

2019-12-11

> [!NOTE]
>
> Docker Desktop Edge 2.1.7.0 is the release candidate for the upcoming major Stable release. Please help us test this version before the wider release and report any issues in the [docker/for-mac](https://github.com/docker/for-mac/issues) GitHub repository.

### Upgrades

- [Docker Compose 1.25.1-rc1](https://github.com/docker/compose/releases/tag/1.25.1-rc1)

### Bug fixes and minor changes

- The Docker Desktop Dashboard now displays port information inline with the container status.
- Fixed an issue that caused the 'back' button on the Dashboard UI to behave inconsistently when repeatedly switching between the container details and the Settings window.
- Various minor improvements to the Dashboard UI.
- Fixed an issue that occurs when sharing overlapping directories.
- Fixed a bug that prevented users from changing the location of the VM disk image.
- Docker Desktop does not inject `inotify` events on directories anymore as these can cause mount points to disappear inside containers. Fixes [docker/for-mac#3976](https://github.com/docker/for-mac/issues/3976).
- Fixed an issue that caused Docker Desktop to fail on startup when there is an incomplete Kubernetes config file.
- Fixed an issue where attempts to log into Docker through Docker Desktop could sometimes fail with the `Incorrect authentication credentials` error. Fixes [docker/for-mac#4010](https://github.com/docker/for-mac/issues/4010).

## Docker Desktop Community 2.1.6.0

2019-11-18

### Upgrades

- [Docker 19.03.5](https://github.com/docker/docker-ce/releases/tag/v19.03.5)
- [Go 1.12.13](https://golang.org/doc/devel/release.html#go1.12)

### New

Added the ability to start and stop Compose-based applications and view combined logs in the Docker Desktop **Dashboard** UI.

### Bug fixes and minor changes

- Fixed port forwarding when containers are using `overlay` networks.
- Fixed a container start error when a container has more than one port with an arbitrary or not-yet-configured external port number. For example, `docker run -p 80 -p 443 nginx`. Fixes [docker/for-win#4935](https://github.com/docker/for-win/issues/4935) and [docker/compose#6998](https://github.com/docker/compose/issues/6998).

## Docker Desktop Community 2.1.5.0

2019-11-04

This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installation.

### Upgrades

- [Kubernetes 1.15.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.15.5)
- [Docker Compose 1.25.0-rc4](https://github.com/docker/compose/releases/tag/1.25.0-rc4)
- Linux kernel 4.19.76

### New

**Docker Desktop Dashboard:** The new Docker Desktop **Dashboard** provides a user-friendly interface which enables you to interact with containers and applications, and manage the lifecycle of your applications directly from the UI. In addition, it allows you to access the logs, view container details, and monitor resource utilization to explore the container behavior.

To access the new Dashboard UI, select the Docker menu from the Mac menu bar and then click **Dashboard**.

### Bug fixes and minor changes

Fixed an issue that caused VMs running on older hardware with macOS Catalina to fail on startup with the error `processor does not support desired secondary processor-based controls`.

### Known issues

- When you start a Docker Compose application and then start a Docker App which has the same name as the Compose application, Docker Desktop displays only one application on the Dashboard. However, when you expand the application, containers that belong to both applications are displayed on the Dashboard.

- When you deploy a Docker App with multiple containers on Kubernetes, Docker Desktop displays each Pod as an application on the Dashboard.

## Docker Desktop Community 2.1.4.0

2019-10-15

### Upgrades

- [Docker 19.03.3](https://github.com/docker/docker-ce/releases/tag/v19.03.3)
- [Kubernetes 1.15.4](https://github.com/kubernetes/kubernetes/releases/tag/v1.15.4)
- [Go 1.12.10](https://github.com/golang/go/issues?q=milestone%3AGo1.12.10+label%3ACherryPickApproved) for [CVE-2019-16276](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16276)
- [Kitematic 0.17.9](https://github.com/docker/kitematic/releases/tag/v0.17.9)

### Bug fixes and minor changes

- Improved the navigation in **Settings** and **Troubleshoot** UI.
- Fixed a bug in the UEFI boot menu that sometimes caused Docker Desktop to hang during restart. Fixes [docker/for-mac#2655](https://github.com/docker/for-mac/issues/2655) and [docker/for-mac#3921](https://github.com/docker/for-mac/issues/3921).
- Docker Desktop now allows users to access the host’s SSH agent inside containers. Fixes [docker/for-mac#410](https://github.com/docker/for-mac/issues/410)
- Docker Machine is no longer included in the Docker Desktop installer. You can download it separately from the [Docker Machine releases](https://github.com/docker/machine/releases) page.

## Docker Desktop Community 2.1.3.0

2019-09-16

### Bug fixes and minor changes

- All binaries included in Docker Desktop are now notarized so that they can run on macOS Catalina. For more information, see [Notarization Requirement for Mac Software](https://developer.apple.com/news/?id=06032019i).
- Fixed an issue which caused higher CPU utilization when closing Docker Desktop windows.
- Added a loading overlay to the **Settings** and **Troubleshoot** windows to prevent editing conflicts.
- Deactivated the **Reset Kubernetes** button when Kubernetes is not activated.

## Docker Desktop Community 2.1.2.0

2019-09-09

#### Upgrades

- [Docker 19.03.2](https://github.com/docker/docker-ce/releases/tag/v19.03.2)
- [Kubernetes 1.14.6](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.6)
- [Go 1.12.9](https://github.com/golang/go/issues?q=milestone%3AGo1.12.9+label%3ACherryPickApproved)
- [Qemu 4.0.1](https://github.com/docker/binfmt)
- [Docker Machine 0.16.2](https://github.com/docker/machine/releases/tag/v0.16.2)
- [Kitematic 0.17.8](https://github.com/docker/kitematic/releases/tag/v0.17.8)

#### Bug fixes and minor changes

- Reduced the Virtual Machine (VM) startup time.
- Added support for `Expect: 100-continue` headers in the Docker API proxy. Some HTTP clients such as `curl` send this header when the payload is large, for example, when creating containers. Fixes [moby/moby#39693](https://github.com/moby/moby/issues/39693).

## Docker Desktop Community 2.1.1.0

2019-08-12

#### Upgrades

- Linux Kernel 4.14.131
- [Hyperkit v0.20190802](https://github.com/moby/hyperkit/releases/tag/v0.20190802)

#### Bug fixes and minor changes

- Docker Desktop now allows users to expose privileged UDP ports. [docker/for-mac#3775](https://github.com/docker/for-mac/issues/3775)
- Added missing fish completions for Docker Compose. [docker/for-mac#3795](https://github.com/docker/for-mac/issues/3795)
- Fixed an issue where running some Docker commands can fail if you are not using Credential Helpers. [docker/for-mac#3785](https://github.com/docker/for-mac/issues/3785)
- Fixed a bug that did not allow users to copy and paste text in the **Preferences** > **Daemon** window. [docker/for-mac#3798](https://github.com/docker/for-mac/issues/3798)

## Docker Desktop Community 2.1.0.0

2019-07-26

This release contains Kubernetes security improvements. Note that your local Kubernetes PKI and cluster will be reset after installation.

#### Upgrades

- [Docker 19.03.1](https://github.com/docker/docker-ce/releases/tag/v19.03.1)
- [Docker Compose 1.24.1](https://github.com/docker/compose/releases/tag/1.24.1)
- [Alpine 3.10](https://alpinelinux.org/posts/Alpine-3.10.0-released.html)
- Linux Kernel 4.9.184
- [Docker Credential Helpers 0.6.3](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.3)

#### New

- Introduced a new user interface for the Docker Desktop **Preferences** menu.
- The **Restart**, **Reset**, and **Uninstall** options are now available on the **Troubleshoot** menu.

#### Bug fixes and minor changes

- Changed the host's Kubernetes context to ensure `docker run -v .kube:kube ... kubectl` works.
- Restricted cluster-admin role on local Kubernetes cluster to `kube-system` namespace.
- Fixed Kubernetes installation with VPNkit subnet.
- Reduced the VM startup time. swap is not created every time a virtual machine boots.
- Fixed a bug where the process output was not redirected to stdout when gathering diagnostics on Windows, which sometimes resulted in a crash.
- Added `/etc/machine-id` to the virtual machine. Fixes [docker/for-mac#3554](https://github.com/docker/for-mac/issues/3554).

## Docker Community Edition 2.0.5.0 2019-06-12

This is the Edge channel, which gives you early access to our newest features. Be aware that some of them may be experimental, and some of them may not ever reach the Stable release.

This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after install.

- Upgrades
  - [Docker 19.03.0-rc2](https://github.com/docker/docker-ce/releases/tag/v19.03.0-rc2)
  - [Kubernetes 1.14.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.3)
  - [Compose on Kubernetes 0.4.23](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.23)
  - [linuxkit v0.7](https://github.com/linuxkit/linuxkit/releases/tag/v0.7)
  - [Qemu 4.0.0](https://github.com/docker/binfmt) for cross compiling for ARM

- New
  - Docker Desktop includes the `buildx` plugin (currently experimental).
  - Selecting the `Experimental features` checkbox on the Docker Desktop Preferences Daemon page enables experimental features in the Docker daemon and the Docker CLI.
  - Docker Desktop has improved the reliability of `com.docker.osxfs trace` performance profiling command.
  - Users can now run the `com.docker.osxfs trace --summary` option to get a high-level summary of operations, instead of receiving a trace of all operations.
  - Docker Desktop now supports large lists of DNS resource records on Mac. Fixes [docker/for-mac#2160](https://github.com/docker/for-mac/issues/2160#issuecomment-431571031)

- Bug fixes and minor changes
  - Docker Desktop does not send DNS queries for `docker-desktop.<domain>` every 10s. It now relies on the host's DNS domain search order rather than trying to replicate it inside the VM.
  - Docker Desktop has removed the ability to log in using email address as a username as the Docker command line does not support this.
  - Docker Desktop now allows running a Docker registry inside a container. Fixes [docker/for-mac#3611](https://github.com/docker/for-mac/issues/3611)
  - Fixed a stability issue with the DNS resolver.

## Docker Community Edition 2.0.4.1 2019-05-07

- Bug fixes and minor changes
  - Upgrade QEMU from 2.8.0 to 3.1.0 to fix an emulation issue when building and running Java applications on Arm64 devices.

## Docker Community Edition 2.0.4.0 2019-04-30

- Upgrades
  - [Docker 19.03.0-beta3](https://github.com/docker/docker-ce/releases/tag/v19.03.0-beta3)
  - [Docker Compose 1.24.0](https://github.com/docker/compose/releases/tag/1.24.0)
  - [Compose on Kubernetes 0.4.22](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.22)
  - [Kubernetes 1.14.1](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md#changelog-since-v1141)

- New
  - App: Docker CLI plugin to configure, share, and install applications
    - Extend Compose files with metadata and parameters
    - Reuse the same application across multiple environments (Development/QA/Staging/Production)
    - Multi-orchestrator installation (Swarm or Kubernetes)
    - Push/Pull/Promotion/Signing supported for application, with the same workflow as images
    - Fully CNAB compliant
    - Full support for Docker Contexts

  - Buildx (Tech Preview): Docker CLI plugin for extended build capabilities with BuildKit
    - Familiar UI from docker build
    - Full BuildKit capabilities with container driver
    - Multiple builder instance support
    - Multi-node builds for cross-platform images (out-of-the-box support for linux/arm/v7 and linux/arm64)
    - Concurrent building of Compose files
    - High-level build constructs with `bake`

- Bug fixes and minor changes
  - Truncate UDP DNS responses which are over 512 bytes in size

## Docker Community Edition 2.0.3.0 2019-03-05

- Upgrades
  - [Docker 18.09.3](https://github.com/docker/docker-ce/releases/tag/v18.09.3)

- Bug fixes and minor changes
  - Fixed port 8080 that was used on localhost when starting Kubernetes. Fixes [docker/for-mac#3522](https://github.com/docker/for-mac/issues/3522)
  - Error message improvements, do not propose to run diagnostics / reset to factory default when not appropriate.

### Docker Community Edition 2.0.2.1 2019-02-15

- Upgrades
  - [Docker 18.09.2](https://github.com/docker/docker-ce/releases/tag/v18.09.2), fixes [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736)

## Docker Community Edition 2.0.2.0 2019-02-06

- Upgrades
  - [Docker Compose 1.24.0-rc1](https://github.com/docker/compose/releases/tag/1.24.0-rc1)
  - [Docker Machine 0.16.1](https://github.com/docker/machine/releases/tag/v0.16.1)
  - [Compose on Kubernetes 0.4.18](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.18)

- New
  - Rebranded UI

- Bug fixes and minor changes
  - Kubernetes: use default maximum number of pods for kubelet. [docker/for-mac#3453](https://github.com/docker/for-mac/issues/3453)
  - Fix DockerHelper crash. [docker/for-mac#3470](https://github.com/docker/for-mac/issues/3470)
  - Fix binding of privileged ports with specified IP. [docker/for-mac#3464](https://github.com/docker/for-mac/issues/3464)

## Docker Community Edition 2.0.1.0 2019-01-11

- Upgrades
  - [Docker 18.09.1](https://github.com/docker/docker-ce/releases/tag/v18.09.1)
  - [Kubernetes 1.13.0](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.13.md#v1130)
  - [Kitematic 0.17.6](https://github.com/docker/kitematic/releases/tag/v0.17.6)
  - Golang 1.10.6, fixes CVEs: [CVE-2018-16875](https://www.cvedetails.com/cve/CVE-2018-16875), [CVE-2018-16873](https://www.cvedetails.com/cve/CVE-2018-16873) and [CVE-2018-16874](https://www.cvedetails.com/cve/CVE-2018-16874)

  WARNING: If you have an existing Kubernetes cluster created with Docker Desktop, this upgrade will reset the cluster. If you need to back up your Kubernetes cluster or persistent volumes you can use [Ark](https://github.com/heptio/ark).

- Bug fixes and minor changes
  - Fix service log collection in diagnostics
  - Gather /etc/hosts to help diagnostics
  - Ensure localhost resolves to 127.0.0.1. Related to [docker/for-mac#2990](https://github.com/docker/for-mac/issues/2990#issuecomment-443097942), [docker/for-mac#3383](https://github.com/docker/for-mac/issues/3383)
  - Add 18.09 missing daemon options
  - Rename Docker for Mac to Docker Desktop
  - Partially open services ports if possible. [docker/for-mac#3438](https://github.com/docker/for-mac/issues/3438)

## Edge Releases of 2018

### Docker Community Edition 2.0.0.0-mac82 2018-12-07

- Upgrades
  - [Docker compose 1.23.2](https://github.com/docker/compose/releases/tag/1.23.2)
  - [Docker Machine 0.16.0](https://github.com/docker/machine/releases/tag/v0.16.0)

### Docker Community Edition 2.0.0.0-mac77 2018-11-14

- Upgrades
  - [Docker 18.09.0](https://github.com/docker/docker-ce-packaging/releases/tag/v18.09.0)
  - [Docker compose 1.23.1](https://github.com/docker/compose/releases/tag/1.23.1)
  - [Kitematic 0.17.5](https://github.com/docker/kitematic/releases/tag/v0.17.5)

- Bug fixes and minor changes
  - Fix appearance in dark mode for OS X 10.14 (Mojave)
  - VPNKit: Improved scalability of port forwarding. Related to [docker/for-mac#2841](https://github.com/docker/for-mac/issues/2841)
  - VPNKit: Limit the size of the UDP NAT table. This ensures port forwarding and regular TCP traffic continue even when running very chatty UDP protocols.
  - Ensure Kubernetes can be installed when using a non-default internal IP subnet.

### Docker Community Edition 2.0.0.0-beta1-mac75 2018-09-14

- Upgrades
  - [Docker 18.09.0-ce-beta1](https://github.com/docker/docker-ce/releases/tag/v18.09.0-ce-beta1)
  - Linux Kernel 4.9.125

- New
  - New version scheme

- Deprecation
  - Removed support of AUFS
  - Removed support of OS X 10.11

- Bug fixes and minor changes
  - Fix panic in diagnose

### Docker Community Edition 18.06.1-ce-mac74 2018-08-29

- Upgrades
  - [Docker 18.06.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.1-ce)

- Bug fixes and minor changes
  - Fix local DNS failing to resolve inside containers.

### Docker Community Edition 18.06.0-ce-mac69 2018-07-25

- Upgrades
  - [Docker 18.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.0-ce)

- Bug fixes and minor changes
  - Fix bug in experimental SOCKS server. See [docker/for-mac#2670](https://github.com/docker/for-mac/issues/2670)
  - Fix bug in docker login when "Securely store Docker logins in macOS keychain" is unchecked. Fixed [docker/for-mac#3104](https://github.com/docker/for-mac/issues/3104)

### Docker Community Edition 18.06.0-ce-rc3-mac68 2018-07-19

- Upgrades
  - [Docker 18.06.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v18.06.0-ce-rc3)
  - [Docker Machine 0.15.0](https://github.com/docker/machine/releases/tag/v0.15.0)
  - [Docker compose 1.22.0](https://github.com/docker/compose/releases/tag/1.22.0)

- New
  - Add an experimental SOCKS server to allow access to container networks, see [docker/for-mac#2670](https://github.com/docker/for-mac/issues/2670#issuecomment-372365274). Also see [docker/for-mac#2721](https://github.com/docker/for-mac/issues/2721)

- Bug fixes and minor changes
  - AUFS storage driver is deprecated in Docker Desktop and AUFS support will be removed in the next major release. You can continue with AUFS in Docker Desktop 18.06.x, but you will need to reset disk image (in Preferences > Reset menu) before updating to the next major update. You can check documentation to [save images](/reference/cli/docker/image/save/#examples) and [back up volumes](../../engine/storage/volumes.md#back-up-restore-or-migrate-data-volumes)
  - Fix startup issue with AUFS [docker/for-mac#2804](https://github.com/docker/for-mac/issues/2804)
  - Fix status bug which could prevent the Kubernetes cluster from starting. Fixes [docker/for-mac#2990](https://github.com/docker/for-mac/issues/2990)
  - Fix bug which would cause virtual machine logs to be written to RAM rather than disk in some cases, and the virtual machine to hang. See [docker/for-mac#2984](https://github.com/docker/for-mac/issues/2984)
  - Fix network connection leak triggered by haproxy TCP health-checks [docker/for-mac#1132](https://github.com/docker/for-mac/issues/1132)
  - Better message to reset vmnetd when it's disabled. See [docker/for-mac#3035](https://github.com/docker/for-mac/issues/3035)

### Docker Community Edition 18.05.0-ce-mac67 2018-06-07

- Upgrades
  - [LinuxKit v0.4](https://github.com/linuxkit/linuxkit/releases/tag/v0.4)
  - Linux Kernel 4.9.93 with CEPH, DRBD, RBD, MPLS_ROUTING and MPLS_IPTUNNEL enabled
  - [Kubernetes 1.10.3](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.10.md#v1103). If Kubernetes is enabled, the upgrade will be performed automatically when starting Docker Desktop for Mac.

- Bug fixes and minor changes
  - Fix VPNKit memory leak. Fixes [moby/vpnkit#371](https://github.com/moby/vpnkit/issues/371)
  - Fix com.docker.supervisor using 100% CPU. Fixes [docker/for-mac#2967](https://github.com/docker/for-mac/issues/2967), [docker/for-mac#2923](https://github.com/docker/for-mac/issues/2923)
  - Do not override existing kubectl binary in /usr/local/bin (installed with brew or otherwise). Fixes [docker/for-mac#2368](https://github.com/docker/for-mac/issues/2368), [docker/for-mac#2890](https://github.com/docker/for-mac/issues/2890)
  - Detect Vmnetd install error. Fixes [docker/for-mac#2934](https://github.com/docker/for-mac/issues/2934), [docker/for-mac#2687](https://github.com/docker/for-mac/issues/2687)
  - Virtual machine default disk path is stored relative to $HOME. Fixes [docker/for-mac#2928](https://github.com/docker/for-mac/issues/2928), [docker/for-mac#1209](https://github.com/docker/for-mac/issues/1209)

### Docker Community Edition 18.05.0-ce-mac66 2018-05-17

- Upgrades
  - [Docker 18.05.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.05.0-ce)
  - [Docker compose 1.21.2](https://github.com/docker/compose/releases/tag/1.21.2)

- New
  - Allow orchestrator selection from the UI in the "Kubernetes" pane, to allow "docker stack" commands to deploy to Swarm clusters, even if Kubernetes is enabled in Docker for Mac.

- Bug fixes and minor changes
  - Use Simple NTP to minimize clock drift between the virtual machine and the host. Fixes [docker/for-mac#2076](https://github.com/docker/for-mac/issues/2076)
  - Fix filesystem event notifications for Swarm services and those using the new-style --mount option. Fixes [docker/for-mac#2216](https://github.com/docker/for-mac/issues/2216), [docker/for-mac#2375](https://github.com/docker/for-mac/issues/2375)
  - Fix filesystem event delivery to Kubernetes pods when the path to the bind mount is a symlink.
  - Fix a race between calling stat on a file and calling close of a file descriptor referencing the file that could result in the stat failing with EBADF (often presented as "File not found"). Fixes [docker/for-mac#2870](https://github.com/docker/for-mac/issues/2870)
  - Do not allow install of Docker for Mac on macOS Yosemite 10.10; this version has not been supported since Docker for Mac 17.09.0.
  - Fix button order in reset dialog windows. Fixes [docker/for-mac#2827](https://github.com/docker/for-mac/issues/2827)
  - Diagnostics are run when diagnostics window is displayed; user is prompted to upload them when available.

### Docker Community Edition 18.05.0-ce-rc1-mac63 2018-04-26

- Upgrades
  - [Docker 18.05.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v18.05.0-ce-rc1)
  - [Notary 0.6.1](https://github.com/docker/notary/releases/tag/v0.6.1)

- New
  - Re-enable raw as the default disk format for users running macOS 10.13.4 and higher. Note this change only takes effect after a "reset to factory defaults" or "remove all data" (from the Whale menu > Preferences > Reset). Related to [docker/for-mac#2625](https://github.com/docker/for-mac/issues/2625)

- Bug fixes and minor changes
  - Fix Docker for Mac not starting due to socket file paths being too long (typically HOME folder path being too long). Fixes [docker/for-mac#2727](https://github.com/docker/for-mac/issues/2727), [docker/for-mac#2731](https://github.com/docker/for-mac/issues/2731).

### Docker Community Edition 18.04.0-ce-mac62 2018-04-12

- Upgrades
  - [Docker 18.04.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.04.0-ce)
  - [Docker compose 1.21.0](https://github.com/docker/compose/releases/tag/1.21.0)

### Docker Community Edition 18.04.0-ce-rc2-mac61 2018-04-09

- Upgrades
  - [Docker 18.04.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v18.04.0-ce-rc2)
  - [Kubernetes 1.9.6](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.9.md#v196). If Kubernetes is enabled, the upgrade will be performed automatically when starting Docker for Mac.

- New
  - Enable ceph & rbd modules in LinuxKit virtual machine.

- Bug fixes and minor changes
  - Fix upgrade straight from pre-17.12 versions where Docker for Mac cannot restart once the upgrade has been performed. Fixes [docker/for-mac#2739](https://github.com/docker/for-mac/issues/2739)

### Docker Community Edition 18.03.0-ce-mac58 2018-03-26

- Upgrades
  - [Docker 18.03.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce)
  - [Docker compose 1.20.1](https://github.com/docker/compose/releases/tag/1.20.1)

### Docker Community Edition 18.03.0-ce-rc4-mac57 2018-03-15

- Upgrades
  - [Docker 18.03.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce-rc4)
  - AUFS 20180312

- Bug fixes and minor changes
  - Fix support for AUFS. Fixes [docker/for-win#1831](https://github.com/docker/for-win/issues/1831)
  - Fix synchronization between CLI `docker login` and GUI login.

### Docker Community Edition 18.03.0-ce-rc3-mac56 2018-03-13

- Upgrades
  - [Docker 18.03.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce-rc3)
  - [Docker Machine 0.14.0](https://github.com/docker/machine/releases/tag/v0.14.0)
  - [Docker compose 1.20.0-rc2](https://github.com/docker/compose/releases/tag/1.20.0-rc2)
  - [Notary 0.6.0](https://github.com/docker/notary/releases/tag/v0.6.0)
  - Linux Kernel 4.9.87

- Bug fixes and minor changes
  - Fix for the HTTP/S transparent proxy when using "localhost" names (for example "host.docker.internal", "docker.for.mac.host.internal", "docker.for.mac.localhost").
  - Fix daemon not starting properly when setting TLS-related options. Fixes [docker/for-mac#2663](https://github.com/docker/for-mac/issues/2663)

### Docker Community Edition 18.03.0-ce-rc1-mac54 2018-02-27

- Upgrades
  - [Docker 18.03.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce-rc1)

- New
  - Virtual machine Swap size can be changed in settings. See [docker/for-mac#2566](https://github.com/docker/for-mac/issues/2566), [docker/for-mac#2389](https://github.com/docker/for-mac/issues/2389)
  - Support NFS Volume sharing. Also works in Kubernetes.

- Bug fixes and minor changes
  - Revert the default disk format to qcow2 for users running macOS 10.13 (High Sierra). There are confirmed reports of file corruption using the raw format which uses sparse files on APFS. This change only takes effect after a reset to factory defaults (from the Whale menu -> Preferences -> Reset). Related to [docker/for-mac#2625](https://github.com/docker/for-mac/issues/2625)
  - DNS name `host.docker.internal` should be used for host resolution from containers. Older aliases (still valid) are deprecated in favor of this one. (See https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06).
  - Kubernetes Load balanced services are no longer marked as `Pending`.
  - Fix hostPath mounts in Kubernetes.
  - Update Compose on Kubernetes to v0.3.0 rc4. Existing Kubernetes stacks will be removed during migration and need to be re-deployed on the cluster.

### Docker Community Edition 18.02.0-ce-mac53 2018-02-09

- Upgrades
  - [Docker 18.02.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.02.0-ce)
  - [Docker compose 1.19.0](https://github.com/docker/compose/releases/tag/1.19.0)

- Bug fixes and minor changes
  - Fix update startup failure in some cases.
  - Fix empty registry added by mistake in some cases in the Preference Daemon Pane. Fixes [docker/for-mac#2537](https://github.com/docker/for-mac/issues/2537)
  - Clearer error message when incompatible hardware is detected. Diagnostics are not proposed in the error popup in this case.

### Docker Community Edition 18.02.0-ce-rc2-mac51 2018-02-02

- Upgrades
  - [Docker 18.02.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v18.02.0-ce-rc2)
  - [Docker compose 1.19.0-rc2](https://github.com/docker/compose/releases/tag/1.19.0-rc2)
  - [Kubernetes 1.9.2](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.9.md#v192). If you have Kubernetes enabled, the upgrade will be performed automatically when starting Docker for Mac.

- Bug fixes and minor changes
  - Fix Kubernetes-compose integration update that was causing startup failure. Fixes [docker/for-mac#2536](https://github.com/docker/for-mac/issues/2536)
  - Fix some cases where selecting "Reset" after an error did not reset properly.
  - Fix incorrect NTP config. Fixes [docker/for-mac#2529](https://github.com/docker/for-mac/issues/2529)

### Docker Community Edition 18.02.0-ce-rc1-mac50 2018-01-26

- Upgrades
  - [Docker 18.02.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v18.02.0-ce-rc1)

- Bug fixes and minor changes
  - Added "Restart" menu item. See [docker/for-mac#2407](https://github.com/docker/for-mac/issues/2407)
  - Keep any existing kubectl binary when activating Kubernetes in Docker for Mac, and restore it when disabling Kubernetes. Fixes [docker/for-mac#2508](https://github.com/docker/for-mac/issues/2508), [docker/for-mac#2368](https://github.com/docker/for-mac/issues/2368)
  - Fix Kubernetes context selector. Fixes [docker/for-mac#2495](https://github.com/docker/for-mac/issues/2495)

### Docker Community Edition 18.01.0-ce-mac48 2018-01-19

- Upgrades
  - [Docker 18.01.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.01.0-ce)
  - Linux Kernel 4.9.75

- New
  - The directory holding the disk images was renamed (from `~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux` to ~/Library/Containers/com.docker.docker/Data/vms/0`).

- Bug fixes and minor changes
  - Fix error during resize/create Docker.raw disk image in some cases. Fixes [docker/for-mac#2383](https://github.com/docker/for-mac/issues/2383), [docker/for-mac#2447](https://github.com/docker/for-mac/issues/2447), [docker/for-mac#2453], (https://github.com/docker/for-mac/issues/2453), [docker/for-mac#2420](https://github.com/docker/for-mac/issues/2420)
  - Fix additional allocated disk space not available in containers. Fixes [docker/for-mac#2449](https://github.com/docker/for-mac/issues/2449)
  - VPNkit port max idle time default restored to 300s. Fixes [docker/for-mac#2442](https://github.com/docker/for-mac/issues/2442)
  - Fix using an HTTP proxy with authentication. Fixes [docker/for-mac#2386](https://github.com/docker/for-mac/issues/2386)
  - Allow HTTP proxy excludes to be written as .docker.com as well as \*.docker.com
  - Allow individual IP addresses to be added to HTTP proxy excludes.
  - Avoid hitting DNS timeouts when querying docker.for.mac.\* when the upstream DNS servers are slow or missing.
  - Fix for `docker push` to an insecure registry. Fixes [docker/for-mac#2392](https://github.com/docker/for-mac/issues/2392)
  - Separate internal ports used to proxy HTTP and HTTPS content.
  - If kubectl was already installed before Docker For Mac, restore the existing kubectl when switching Kubernetes off in Docker for Mac.
  - Migration of Docker Toolbox images is not proposed anymore in Docker For Mac installer (still possible to migrate Toolbox images manually).

### Docker Community Edition 17.12.0-ce-mac45 2018-01-05

- Upgrades
  - [Docker 17.12.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce)

- New
  - Experimental Kubernetes Support. You can now run a single-node Kubernetes cluster from the "Kubernetes" Pane in Docker For Mac Preferences and use kubectl commands as well as docker commands. See [the Kubernetes section](../use-desktop/kubernetes.md)
  - DNS name `docker.for.mac.host.internal` should be used instead of `docker.for.mac.localhost` (still valid) for host resolution from containers, since since there is an RFC banning the use of subdomains of localhost (See https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06).

- Bug fixes and minor changes
  - The docker engine is configured to use VPNKit as an HTTP proxy, fixing 'docker pull' in environments with no DNS. Fixes [docker/for-mac#2320](https://github.com/docker/for-mac/issues/2320)

## Edge Releases of 2017

### Docker Community Edition 17.12.0-ce-rc4-mac44 2017-12-21

- Upgrades
  - [Docker 17.12.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce-rc4)
  - [Docker compose 1.18.0](https://github.com/docker/compose/releases/tag/1.18.0)

- Bug fixes and minor changes
  - Display actual size used by the virtual machine disk, especially useful for disks using raw format. See [docker/for-mac#2297](https://github.com/docker/for-mac/issues/2297).
  - Fix more specific edge cases in filesharing settings migration.

### Docker Community Edition 17.12.0-ce-rc3-mac43 2017-12-15

- Upgrades
  - [Docker 17.12.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce-rc3)

- Bug fixes and minor changes
  - Fix filesharing migration issue ([docker/for-mac#2317](https://github.com/docker/for-mac/issues/2317))

### Docker Community Edition 17.12.0-ce-rc2-mac41 2017-12-13

- Upgrades
  - [Docker 17.12.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce-rc2)
  - [Docker compose 1.18.0-rc2](https://github.com/docker/compose/releases/tag/1.18.0-rc2)

- New
  - Virtual machine disk size can be changed in settings. (See [docker/for-mac#1037](https://github.com/docker/for-mac/issues/1037)).

- Bug fixes and minor changes
  - Avoid virtual machine reboot when changing host proxy settings.
  - Don't break HTTP traffic between containers by forwarding them through the external proxy [docker/for-mac#981](https://github.com/docker/for-mac/issues/981)
  - Filesharing settings are now stored in settings.json
  - Daemon restart button has been moved to settings / Reset Tab
  - Display various component versions in About box
  - Better virtual machine state handling and error messages in case of virtual machine crashes

### Docker Community Edition 17.11.0-ce-mac40 2017-11-22

- Upgrades
  - [Docker 17.11.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce)

### Docker Community Edition 17.11.0-ce-rc4-mac39 2017-11-17

- Upgrades
  - [Docker 17.11.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce-rc4)
  - [Docker compose 1.17.1](https://github.com/docker/compose/releases/tag/1.17.1)
  - Linux kernel 4.9.60

- Bug fixes and minor changes
  - Fix login into private repository with certificate issue. [docker/for-mac#2201](https://github.com/docker/for-mac/issues/2201)

- New
  - For systems running APFS on SSD on High Sierra, use `raw` format virtual machine disks by default. This increases disk throughput (from 320MiB/sec to 600MiB/sec in `dd` on a 2015 MacBook Pro) and disk space handling.
    Existing disks are kept in qcow format, if you want to switch to raw format you need to "Reset to factory defaults". To query the space usage of the file, use a command like:
    `$ cd ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/`
    `$ ls -ls Docker.raw`
    `3944768 -rw-r--r--@ 1 user  staff  68719476736 Nov 16 11:19 Docker.raw`
    The first number (`3944768`) is the allocated space in blocks; the larger number `68719476736` is the maximum total amount of space the file may consume in future in bytes.

### Docker Community Edition 17.11.0-ce-rc3-mac38 2017-11-09

- Upgrades
  - [Docker 17.11.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce-rc3)

- Bug fixes and minor changes
  - Fix Docker build exits successfully but fails to build image [moby/#35413](https://github.com/moby/moby/issues/35413).

### Docker Community Edition 17.11.0-ce-rc2-mac37 2017-11-02

- Upgrades
  - [Docker 17.11.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce-rc2)
  - [Docker compose 1.17.0](https://github.com/docker/compose/releases/tag/1.17.0)
  - Linuxkit blueprint updated to [linuxkit/linuxkit#2633](https://github.com/linuxkit/linuxkit/pull/2633), fixes CVE-2017-15650

- Bug fixes and minor changes
  - Fix centos:5 & centos:6 images not starting properly with LinuxKit virtual machine (fixes [docker/for-mac#2169](https://github.com/docker/for-mac/issues/2169)).

### Docker Community Edition 17.10.0-ce-mac36 2017-10-24

- Upgrades
  - [Docker 17.10.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.10.0-ce)
  - [Docker Machine 0.13.0](https://github.com/docker/machine/releases/tag/v0.13.0)
  - [Docker compose 1.17.0-rc1](https://github.com/docker/compose/releases/tag/1.17.0-rc1)

- New
  - Virtual machine entirely built with Linuxkit

### Docker Community Edition 17.09.0-ce-mac34 2017-10-06

- Bug fixes and minor changes
  - Fix Docker For Mac unable to start in some cases : removed use of libgmp sometimes causing the vpnkit process to die.

### Docker Community Edition 17.09.0-ce-mac31 2017-09-29

- Upgrades
  - [Docker 17.09.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce)
  - DataKit update (fix instability on High Sierra)

- Bug fixes and minor changes
  - Fix password encoding/decoding. May require to re-login to docker cloud after this version is installed. (Fixes:docker/for-mac#2008, docker/for-mac#2016, docker/for-mac#1919, docker/for-mac#712, docker/for-mac#1220).

### Docker Community Edition 17.09.0-ce-rc3-mac30 2017-09-22

- Upgrades
  - [Docker 17.09.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce-rc3)

### Docker Community Edition 17.09.0-ce-rc2-mac29 2017-09-19

- Upgrades
  - [Docker 17.09.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce-rc2)
  - Linux Kernel 4.9.49
  - AUFS 20170911

- Bug fixes and minor changes
  - Kernel: Enable TASK_XACCT and TASK_IO_ACCOUNTING [docker/for-mac#1608](https://github.com/docker/for-mac/issues/1608)
  - Rotate logs in the virtual machine more often

### Docker Community Edition 17.09.0-ce-rc1-mac28 2017-09-07

- Upgrades
  - [Docker 17.09.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce-rc1)
  - [Docker compose 1.16.1](https://github.com/docker/compose/releases/tag/1.16.1)
  - Linux Kernel 4.9.46

- Bug fixes and minor changes
  - VPNKit: change protocol to support error messages reported back from the server

### Docker Community Edition 17.07.0-ce-mac26, 2017-09-01

- Upgrades
  - [Docker 17.07.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce)
  - [Docker compose 1.16.0](https://github.com/docker/compose/releases/tag/1.16.0)
  - [Docker Credential Helpers 0.6.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.0)

### Docker Community Edition 17.07.0-ce-rc4-mac25, 2017-08-24

**Upgrades**

- [Docker 17.07.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc4)
- [Docker compose 1.16.0-rc1](https://github.com/docker/compose/releases/tag/1.16.0-rc1)

**Bug fixes and minor changes**

- Fixed string validation in daemon options (related to [docker/for-mac#1971](https://github.com/docker/for-mac/issues/1971))
- VPNKit: Fixed a bug which causes a socket to leak if the corresponding
  TCP connection is idle for more than five minutes (related to
  [docker/for-mac#1374](https://github.com/docker/for-mac/issues/1374))

### Docker Community Edition 17.07.0-ce-rc3-mac23, 2017-08-21

**Upgrades**

- [Docker 17.07.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc3)

**New**

- VPNKit: Added support for ping!
- VPNKit: Added `slirp/port-max-idle-timeout` to allow the timeout to be adjusted or even disabled
- VPNKit: Bridge mode is default everywhere now

**Bug fixes and minor changes**

- VPNKit: Improved the logging around the UNIX domain socket connections
- VPNKit: Automatically trim whitespace from `int` or `bool` database keys

### Docker Community Edition 17.07.0-ce-rc2-mac22, 2017-08-11

**Upgrades**

- [Docker 17.07.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc2)
- Linux Kernel 4.9.41

### Docker Community Edition 17.07.0-ce-rc1-mac21, 2017-07-31

**Upgrades**

- [Docker 17.07.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc1)
- [Docker compose 1.15.0](https://github.com/docker/compose/releases/tag/1.15.0)
- [Docker Machine 0.12.2](https://github.com/docker/machine/releases/tag/v0.12.2)
- Linux Kernel 4.9.38

**New**

- Transparent proxy using macOS system proxies (if defined) directly
- GUI settings are now stored in `~/Library/Group\ Containers/group.com.docker/settings.json`. `daemon.json` in now a file in `~/.docker/`
- You can now change the default IP address used by Hyperkit if it collides with your network

**Bug fixes and minor changes**

- Add daemon options validation
- Diagnose can be cancelled & Improved help information. Fixes [docker/for-mac#1134](https://github.com/docker/for-mac/issues/1134), [docker/for-mac#1474](https://github.com/docker/for-mac/issues/1474)
- Support paging of Docker Cloud [repositories](../../docker-hub/repos/index.md) and [organizations](../../accounts/organization/setup/orgs.md). Fixes [docker/for-mac#1538](https://github.com/docker/for-mac/issues/1538)

### Docker Community Edition 17.06.1-ce-mac20, 2017-07-18

**Upgrades**

- [Docker 17.06.1-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.06.1-ce-rc1)
- Linux Kernel 4.9.36
- AUFS 20170703

### Docker Community Edition 17.06.0-ce-mac17, 2017-06-28

**Upgrades**

- [Docker 17.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce)

### Docker Community Edition 17.06.0-rc5-ce-mac16, 2017-06-21

**Upgrades**

- [Docker 17.06.0-ce-rc5](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc5)
- [Docker compose 1.14.0](https://github.com/docker/compose/releases/tag/1.14.0)

### Docker Community Edition 17.06.0-rc4-ce-mac15, 2017-06-16

**Upgrades**

- [Docker 17.06.0-rc4-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc4)
- [Docker Credential Helpers 0.5.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.2)
- Linux Kernel 4.9.31

### Docker Community Edition 17.06.0-rc2-ce-mac14, 2017-06-08

**Upgrades**

- [Docker 17.06.0-rc2-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc2)
- [Docker Machine 0.12.0](https://github.com/docker/machine/releases/tag/v0.12.0)
- [Docker compose 1.14.0-rc2](https://github.com/docker/compose/releases/tag/1.14.0-rc2)

### Docker Community Edition 17.06.0-rc1-ce-mac13, 2017-06-01

**Upgrades**

- [Docker 17.06.0-rc1-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc1)
- [Docker Credential Helpers 0.5.1](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.1)
- `qcow-tool` v0.10.0 (improve the performance of `compact`: `mirage/ocaml-qcow#94`)
- OS X Yosemite 10.10 is marked as deprecated
- Linux Kernel 4.9.30

**New**

- GUI option to opt out of credential store
- GUI option to reset docker data without losing all settings (fixes [docker/for-mac#1309](https://github.com/docker/for-mac/issues/1309))
- Add an experimental DNS name for the host: `docker.for.mac.localhost`
- Support for client (such as "login") certificates for authenticating registry access (fixes [docker/for-mac#1320](https://github.com/docker/for-mac/issues/1320))

**Bug fixes and minor changes**

- Resync HTTP(S) proxy settings on application start
- Interpret system proxy setting of localhost correctly (see [docker/for-mac#1511](https://github.com/docker/for-mac/issues/1511))
- All docker binaries bundled with Docker for Mac are now signed
- Display all docker cloud organizations and repositories in the whale menu (fixes [docker/for-mac#1538](https://github.com/docker/for-mac/issues/1538))
- OSXFS: improved latency for many common operations, such as read and write by approximately 25%

### Docker Community Edition 17.05.0-ce-mac11, 2017-05-12

**Upgrades**

- Security fix for CVE-2017-7308

### Docker Community Edition 17.05.0-ce-mac9, 2017-05-09

**Upgrades**

- [Docker 17.05.0-ce](https://github.com/docker/docker/releases/tag/v17.05.0-ce)
- [Docker Compose 1.13.0](https://github.com/docker/compose/releases/tag/1.13.0)
- [Docker Machine 1.11.0](https://github.com/docker/machine/releases/tag/v0.11.0)

**Bug fixes and minor changes**

- Fixed GUI crash when text table view was selected and windows re-opened (fixes [docker/for-mac#1477](https://github.com/docker/for-mac/issues/1477))
- Reset to default / uninstall also remove `config.json` and `osxkeychain` credentials
- More detailed VirtualBox uninstall requirements ( [docker/for-mac#1343](https://github.com/docker/for-mac/issues/1343))
- You are now prompted for your password, if you changed it in Docker Cloud.
- Request time sync after waking up to improve [docker/for-mac#17](https://github.com/docker/for-mac/issues/17)

### Docker Community Edition 17.05.0-ce-rc1-mac8, 2017-04-13

**Upgrades**

- [Docker 17.05.0-ce-rc1](https://github.com/docker/docker/releases/tag/v17.05.0-ce-rc1)

### Docker Community Edition 17.04.0-ce-mac7, 2017-04-06

**New**

- OSXFS: support for `cached` mount flag to improve performance of macOS mounts when strict consistency is not necessary

**Upgrades**

- [Docker 17.04.0-ce](https://github.com/docker/docker/releases/tag/v17.04.0-ce)
- [Docker Compose 1.12.0](https://github.com/docker/compose/releases/tag/1.12.0)
- Linux Kernel 4.9.19

**Bug fixes and minor changes**

- VPNKit: Improved DNS timeout handling (fixes [docker/for-mac#202](https://github.com/docker/vpnkit/issues/202))
- VPNKit: Use DNSServiceRef API by default (only enabled for new installs or after factory reset)
- Add a reset to factory defaults button when application crashes
- Toolbox import dialog now defaults to "Skip"

### Docker Community Edition 17.04.0-ce-rc2-mac6, 2017-04-03

**Upgrades**

- [Docker 17.04.0-ce-rc2](https://github.com/docker/docker/releases/tag/v17.04.0-ce-rc2)
- [Docker Compose 1.12.0-rc2](https://github.com/docker/compose/releases/tag/1.12.0-rc2)
- Linux Kernel 4.9.18

**Bug fixes and minor changes**

- Buffered data should be treated correctly when Docker client requests are upgraded to raw streams
- Removed an error message from the output related to experimental features handling
- `vmnetd` should not crash when user home directory is on an external drive
- Improved settings database schema handling
- Disk trimming should work as expected
- Diagnostics now contains more settings data

### Docker Community Edition 17.03.1-ce-rc1-mac3, 2017-03-28

**Upgrades**

- [Docker 17.03.1-ce-rc1](https://github.com/docker/docker/releases/tag/v17.03.1-ce-rc1)
- [Docker Credential Helpers 0.5.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.0)
- Linux Kernel 4.9.14

**Bug fixes and minor changes**

- Use `fsync` rather than `fcntl`(`F_FULLFSYNC`)
- Update max-connections to 2000 ([docker/for-mac#1374](https://github.com/docker/for-mac/issues/1374) and [docker/for-mac#1132](https://github.com/docker/for-mac/issues/1132))
- VPNKit: capture up to 64KiB of NTP traffic for diagnostics, better handling of DNS
- UI: fix edge cases which crash the application
- QCOW: numerous bugfixes
- osxfs: buffer readdir

### Docker Community Edition 17.03.0-ce-mac2, 2017-03-06

**Hotfixes**

- Set the ethernet MTU to 1500 to prevent a hyperkit crash
- Fix Docker build on private images

**Upgrades**

- [Docker Credential Helpers 0.4.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.4.2)

### Docker Community Edition 17.03.0-ce-mac1, 2017-03-02

**New**

- Renamed to Docker Community Edition
- Integration with Docker Cloud: control remote Swarms from the local CLI and view your repositories. This feature is going to be rolled out to all users progressively
- Docker will now securely store your IDs in the macOS keychain

**Upgrades**

- [Docker 17.03.0-ce](https://github.com/docker/docker/releases/tag/v17.03.0-ce)
- [Docker Compose 1.11.2](https://github.com/docker/compose/releases/tag/1.11.2)
- [Docker Machine 0.10.0](https://github.com/docker/machine/releases/tag/v0.10.0)
- Linux Kernel 4.9.12

**Bug fixes and minor changes**

- VPNKit: fix unmarshalling of DNS packets containing pointers to pointers to labels
- osxfs: catch EPERM when reading extended attributes of non-files
- Add page_poison=1 to boot args
- Add a new disk flushing option

### Docker Community Edition 17.03.0 RC1 Release Notes (2017-02-22 17.03.0-ce-rc1-mac1)

**New**

- Introduce Docker Community Edition
- Integration with Docker Cloud to control remote Swarms from the local CLI and view your repositories. This feature will be rolled out to all users progressively
- Docker will now use keychain access to secure your IDs

**Upgrades**

- Docker 17.03.0-ce-rc1
- Linux Kernel 4.9.11

**Bug fixes and minor changes**

- VPNKit: fixed unmarshalling of DNS packets containing pointers to pointers to labels
- osxfs: catch EPERM when reading extended attributes of non-files
- Added `page_poison=1` to boot args
- Added a new disk flushing option

### Beta 42 Release Notes (2017-02-09 1.13.1-beta42)

**Upgrades**

- [Docker 1.13.1](https://github.com/docker/docker/releases/tag/v1.13.1)
- [Docker Compose 1.11.1](https://github.com/docker/compose/releases/tag/1.11.1)

### Beta 41 Release Notes (2017-02-07-2017-1.13.1-rc2-beta41)

**Upgrades**

- Docker 1.13.1-rc2
- [Docker Compose 1.11.0-rc1](https://github.com/docker/compose/releases/tag/1.11.0-rc1)
- Linux kernel 4.9.8

**Bug fixes and minor improvements**

- VPNKit: set the Recursion Available bit on DNS responses from the cache
- Don’t use port 4222 inside the Linux VM

### Beta 40 Release Notes (2017-01-31 1.13.1-rc1-beta40)

**Upgrades**

- [Docker 1.13.1-rc1](https://github.com/docker/docker/releases/tag/v1.13.1-rc1)
- Linux kernel 4.9.6

**New**

- Allow to reset faulty `daemon.json` through a link in advanced subpanel
- Add link to experimental features
- Hide restart button in settings window
- Increase the maximum number of vCPUs to 64

**Bug fixes and minor improvements**

- VPNKit: Avoid diagnostics to capture too much data
- VPNKit: Fix a source of occasional packet loss (truncation) on the virtual ethernet link
- HyperKit: Dump guest physical and linear address from VMCS when dumping state
- HyperKit: Kernel boots with `panic=1` arg

### Beta 39 Release Notes (2017-01-26 1.13.0-beta39)

**Upgrades**

- Linux kernel 4.9.5

**New**

- More options when moving disk image
- Filesharing and daemon table empty fields are editable
- DNS forwarder ignores responses from malfunctioning servers ([docker/for-mac#1025](https://github.com/docker/for-mac/issues/1025))
- DNS forwarder send all queries in parallel, process results in order
- DNS forwarder includes servers with zones in general searches ([docker/for-mac#997](https://github.com/docker/for-mac/issues/997))
- Parses aliases from /etc/hosts ([docker/for-mac#983](https://github.com/docker/for-mac/issues/983))
- Can resolve DNS requests through servers listed in the /etc/resolver directory on the host

**Bug fixes and minor improvements**

- Fix bug where update window hides when app not focused
- Limit vCPUs to 16 ([docker/for-mac#1144](https://github.com/docker/for-mac/issues/1144))
- Fix for swap not being mounted
- Fix AUFS xattr delete issue ([docker/docker#30245](https://github.com/docker/docker/issues/30245))

### Beta 38 Release Notes (2017-01-20 1.13.0-beta38)

**Upgrades**

- [Docker 1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)
- [Docker Compose 1.10](https://github.com/docker/compose/releases/tag/1.10.0)
- [Docker Machine 0.9.0](https://github.com/docker/machine/releases/tag/v0.9.0)
- [Notary 0.4.3](https://github.com/docker/notary/releases/tag/v0.4.3)
- Linux kernel 4.9.4
- QCOW-tool 0.7.2

**New**

- The storage location of the Linux volume can now be moved
- Reclaim disk size on reboot
- You can now edit filesharing paths
- Memory can be allocated with 256 MiB steps
- Proxy can now be completely disabled
- Support for arm, aarch64, ppc64le architectures using qemu
- Dedicated preference pane for advanced configuration of the docker daemon (edit daemon.json)
- Docker Experimental mode can be toggled
- Better support for Split DNS VPN configurations
- Use more DNS servers, respect order

**Bug fixes and minor improvements**

- You can't edit settings while docker is restarting
- Support Copy/Paste in About box
- Auto update polling every 24h
- Kernel boots with vsyscall=emulate arg and CONFIG_LEGACY_VSYSCALL is set to NONE in Moby
- Fixed vsock deadlock under heavy write load
- If you opt-out of analytics, you're prompted for approval before a bug report is sent
- Fixed bug where search domain could be read as `DomainName`
- Dedicated preference pane for HTTP proxy settings.
- Dedicated preference pane for CPU & Memory computing resources.
- Privacy settings moved to the general preference pane
- Fixed an issue where the preference pane disappeared when the welcome whale menu was closed.
- HyperKit: code cleanup and minor fixes
- Improvements to Logging and Diagnostics
- osxfs: switch to libev/kqueue to improve latency
- VPNKit: improvements to DNS handling
- VPNKit: Improved diagnostics
- VPNKit: Forwarded UDP datagrams should have correct source port numbers
- VPNKit: add a local cache of DNS responses
- VPNKit: If one request fails, allow other concurrent requests to succeed.
  For example this allows IPv4 servers to work even if IPv6 is broken.
- VPNKit: Fix bug which could cause the connection tracking to
  underestimate the number of active connections

### Beta 37 Release Notes (2017-01-16 1.13.0-rc7-beta37)

**Upgrades**

- Docker 1.13.0-rc7
- Notary 0.4.3
- Linux kernel 4.9.3

### Beta 36 Release Notes (2017-01-12 1.13.0-rc6-beta36)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Upgrades**

- Docker 1.13.0-rc6
- Docker Compose 1.10-rc2
- Linux Kernel 4.9.2

**Bug fixes and minor improvements**

- Uninstall should be more reliable

### Beta 35 Release Notes (2017-01-06 1.13.0-rc5-beta35)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Upgrades**

- Docker 1.13.0-rc5
- Docker Compose 1.10-rc1

## Edge Releases of 2016

### Beta 34.1 Release Notes (2016-12-22 1.13.0-rc4-beta34.1)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Hotfix**

- Fixed issue where Docker would fail to start after importing containers from Toolbox

**Upgrades**

- qcow-tool 0.7.2

### Beta 34 Release Notes (2016-12-20 1.13.0-rc4-beta34)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**New**

- Change UI for path location and open finder
- Trim compact on reboot
- Use more DNS servers, respect order

**Upgrades**

- Docker 1.13.0-rc4
- Linux Kernel 4.8.15

**Bug fixes and minor improvements**

- New Daemon icon
- Support Copy/Paste in About box
- Fix advanced daemon check json changes
- Auto update polling every 24h

### Beta 33.1 Release Notes (2016-12-16 1.13.0-rc3-beta33.1)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Hotfix**

- Fixed issue where sometimes TRIM would cause the virtual machine to hang

### Beta 33 Release Notes (2016-12-15 1.13.0-rc3-beta33)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**New**

- You can now edit filesharing paths
- YOu can allocate memory with 256 MiB steps
- You can move the storage location of the Linux volume
- More explicit proxy settings
- You can completely disable Proxy
- You can switch daemon tabs without losing your settings
- You can't edit settings while Docker is restarting

**Upgrades**

- Linux Kernel 4.8.14

**Bug fixes and minor improvements**

- Kernel boots with `vsyscall=emulate arg` and `CONFIG_LEGACY_VSYSCALL` set to `NONE` in Moby

### Beta 32 Release Notes (2016-12-07 1.13.0-rc3-beta32)

**New**

- Support for arm, aarch64, ppc64le architectures using qemu

**Upgrades**

- Docker 1.13.0-rc3
- Docker Machine 0.9.0-rc2
- Linux kernel 4.8.12

**Bug fixes and minor improvements**

- VPNKit: Improved diagnostics
- Fix vsock deadlock under heavy write load
- On the beta channel you can't opt-out of analytics
- If you opt-out of analytics, you're prompted for approval before a bug report is sent

### Beta 31 Release Notes (2016-12-01 1.13.0-rc2-beta31)

**New**

- Dedicated preference pane for advanced configuration of the docker daemon (edit daemon.json). See [Daemon Advanced (JSON configuration file)](../settings-and-maintenance/settings.md#docker-engine).

- Docker Experimental mode can be toggled. See [Daemon Basic (experimental mode and registries)](../settings-and-maintenance/settings.md#docker-engine).

**Upgrades**

- Docker 1.13.0-rc2
- Docker Compose 1.9.0
- Docker Machine 0.9.0-rc1
- Linux kernel 4.8.10

**Bug fixes and minor improvements**

- Fixed bug where search domain could be read as `DomainName`
- VPNKit: don't permute resource records in responses
- VPNKit: reduced the amount of log spam
- Dedicated preference pane for HTTP proxy settings
- Dedicated preference pane for CPU & Memory computing resources
- Privacy settings moved to the general preference pane
- Fixed an issue where proxy settings were erased if registries or mirrors changed.
- Tab key is now cycling through tabs while setting proxy parameters
- Fixed an issue where the preference pane disappeared when the welcome whale menu was closed

### Beta 30 Release Notes (2016-11-10 1.12.3-beta30)

**New**

- Better support for Split DNS VPN configurations

**Upgrades**

- Docker Compose 1.9.0-rc4
- Linux kernel 4.4.30

**Bug fixes and minor changes**

- HyperKit: code cleanup and minor fixes
- VPNKit: improvements to DNS handling
- Improvements to Logging and Diagnostics
- osxfs: switched to `libev/kqueue` to improve latency

### Beta 29.3 Release Notes (2016-11-02 1.12.3-beta29.3)

**Upgrades**

- Docker Compose 1.9.0-rc2
- `osxfs`: Fixed a simultaneous volume mount race which can result in a crash

### Beta 29.2 Release Notes (2016-10-27 1.12.2-beta29.2)

**Hotfixes**

- Upgrade to Docker 1.12.3

### Beta 29.1 Release Notes (2016-10-26 1.12.1-beta29.1)

**Hotfixes**

- Fixed missing `/dev/pty/ptmx`

### Beta 29 Release Notes (2016-10-25 1.12.3-rc1-beta29)

**New**

- Overlay2 is now the default storage driver. You must do a factory reset for overlay2 to be automatically used. (#5545)

**Upgrades**

- Docker 1.12.3-rc1
- Linux kernel 4.4.27

**Bug fixes and minor changes**

- Fixed an issue where the whale animation during setting change was inconsistent
- Fixed an issue where some windows stayed hidden behind another app
- Fixed application of system or custom proxy settings over container restart
- Increased default ulimit for memlock (fixes [docker/for-mac#801](https://github.com/docker/for-mac/issues/801) )
- Fixed an issue where the Docker status would continue to be
  yellow/animated after the VM had started correctly
- osxfs: fixed the prohibition of chown on read-only or mode 0 files (fixes [docker/for-mac#117](https://github.com/docker/for-mac/issues/117), [docker/for-mac#263](https://github.com/docker/for-mac/issues/263), [docker/for-mac#633](https://github.com/docker/for-mac/issues/633) )

### Beta 28 Release Notes (2016-10-13 1.12.2-rc3-beta28)

**Upgrades**

- Docker 1.12.2
- Kernel 4.4.24
- Notary 0.4.2

**Bug fixes and minor changes**

- Fixed an issue where Docker for Mac was incorrectly reported as updated
- osxfs: Fixed race condition causing some reads to run forever
- Channel is now displayed in About box
- Crash reports are sent over Bugsnag rather than HockeyApp

### Beta 27 Release Notes (2016-09-28 1.12.2-rc1-beta27)

**Upgrades**

- Docker 1.12.2-rc1
- Docker Machine 0.8.2
- Docker compose 1.8.1
- Kernel vsock driver v7
- Kernel 4.4.21
- AUFS 20160912

**Bug fixes and minor changes**

- Fixed an issue where some windows did not claim focus correctly
- Added UI when switching channel to prevent user losing containers and settings
- Check disk capacity before Toolbox import
- Import certificates in `etc/ssl/certs/ca-certificates.crt`
- DNS: reduce the number of UDP sockets consumed on the host
- VPNkit: improve the connection-limiting code to avoid running out of sockets on the host
- UDP: handle diagrams bigger than 2035, up to the configured macOS kernel limit
- UDP: made the forwarding more robust; now, drop packets and continue rather than stopping
- disk: made the "flush" behaviour configurable for database-like workloads. This works around a performance regression in `v1.12.1`.

### Beta 26 Release Notes (2016-09-14 1.12.1-beta26)

**New**

- Improved support for macOS 10.12 Sierra

**Upgrades**

- Linux kernel 4.4.20
- AUFS 20160905

**Bug fixes and minor changes**

- Fixed communications glitch when UI talks to `com.docker.vmnetd`. Fixes [docker/for-mac#90](https://github.com/docker/for-mac/issues/90)

- UI fix for macOs 10.12

- Windows open on top of full screen app are available in all spaces

- Reporting a bug, while not previously logged into GitHub now works

- When a diagnostic upload fails, the error is properly reported

- `docker-diagnose` displays and records the time the diagnosis was captured

- Ports are allowed to bind to host addresses other than `0.0.0.0` and `127.0.0.1`. Fixes issue reported in [docker/for-mac#68](https://github.com/docker/for-mac/issues/68).

- We no longer compute the container folder in `com.docker.vmnetd`. Fixes [docker/for-mac#47](https://github.com/docker/for-mac/issues/47).

**Known Issues**

- `Docker.app` sometimes uses 200% CPU after macOS wakes up from sleep mode. The
  issue is being investigated. The workaround is to restart Docker.app.

- There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and
  traversals of large directories are currently slow. Additionally, containers
  that perform large numbers of directory operations, such as repeated scans of
  large directory trees, may suffer from poor performance. More information is
  available in [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md) in Troubleshooting.

- Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart `Docker.app`.

### Beta 25 Release Notes (2016-09-07 1.12.1-beta25)

**Upgrades**

- Experimental support for macOS 10.12 Sierra (beta)

**Bug fixes and minor changes**

- VPNKit supports search domains
- Entries from `/etc/hosts` should now resolve from within containers
- osxfs: fix thread leak

**Known issues**

- Several problems have been reported on macOS 10.12 Sierra and are being
  investigated. This includes failure to launch the app and being unable to
  upgrade to a new version.

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The
  issue is being investigated. The workaround is to restart Docker.app

- There are a number of issues with the performance of directories bind-mounted
  with `osxfs`. In particular, writes of small blocks and traversals of large
  directories are currently slow. Additionally, containers that perform large
  numbers of directory operations, such as repeated scans of large directory
  trees, may suffer from poor performance. More information is available in
  [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md) in Troubleshooting.

- Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app.

### Beta 24 Release Notes (2016-08-23 1.12.1-beta24)

**Upgrades**

- Docker 1.12.1
- Docker Machine 0.8.1
- Linux kernel 4.4.19
- AUFS 20160822

**Bug fixes and minor changes**

- osxfs: fixed a malfunction of new directories that have the same name as an old directory that is still open

- osxfs: rename events now trigger DELETE and/or MODIFY `inotify` events (saving with TextEdit works now)

- slirp: support up to 8 external DNS servers

- slirp: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules will time out earlier than expected

- The app warns user if BlueStacks is installed (potential kernel panic)

**Known issues**

- Several problems have been reported on macOS 10.12 Sierra and are being investigated. This includes failure to launch the app and being unable to upgrade to a new version.

- `Docker.app` sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart `Docker.app`.

- There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and traversals of large
  directories are currently slow. Additionally, containers that perform large
  numbers of directory operations, such as repeated scans of large directory
  trees, may suffer from poor performance. For more information and workarounds, see the bullet on performance of bind-mounted directories in [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md) in Troubleshooting.

- Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart `Docker.app`.

### Beta 23 Release Notes (2016-08-16 1.12.1-rc1-beta23)

**Upgrades**

- Docker 1.12.1-rc1
- Linux kernel 4.4.17
- AUFS 20160808

**Bug fixes and minor changes**

- Moby: use default sysfs settings, transparent huge pages disabled
- Moby: cgroup mount to support systemd in containers
- osxfs: fixed an issue that caused `inotify` failure and crashes
- osxfs: fixed a directory fd leak
- Zsh completions

**Known issues**

- Docker for Mac is not supported on macOS 10.12 Sierra

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app

- There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. For more information and workarounds, see the bullet on performance of bind-mounted directories in [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md) in Troubleshooting.

- Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app

### Beta 22 Release Notes (2016-08-11 1.12.0-beta22)

**Upgrades**

- Linux kernel to 4.4.16

**Bug fixes and minor changes**

- Increase Moby fs.file-max to 524288
- Use Mac System Configuration database to detect DNS
- HyperKit updated with dtrace support and lock fixes
- Fix Moby Diagnostics and Update Kernel
- UI Fixes
- osxfs: fix socket chowns

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app

- There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. More information is available in [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

- Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app

### Beta 21.1 Release Notes (2016-08-03 1.12.0-beta21.1)

This bug fix release contains osxfs improvements. The fixed issues may have
been seen as failures with apt-get and npm in containers, missed `inotify`
events or unexpected unmounts.

**Hotfixes**

- osxfs: fixed an issue causing access to children of renamed directories to fail (symptoms: npm failures, apt-get failures)

- osxfs: fixed an issue causing some ATTRIB and CREATE `inotify` events to fail delivery and other `inotify` events to stop

- osxfs: fixed an issue causing all `inotify` events to stop when an ancestor directory of a mounted directory was mounted

- osxfs: fixed an issue causing volumes mounted under other mounts to spontaneously unmount (docker/docker#24503)

### Docker for Mac 1.12.0 (2016-07-28 1.12.0-beta21)

**New**

- Docker for Mac is now available from 2 channels: **stable** and **beta**. New features and bug fixes will go out first in auto-updates to users in the beta channel. Updates to the stable channel are much less frequent and happen in sync with major and minor releases of the Docker Engine. Only features that are well-tested and ready for production are added to the stable channel releases. For downloads of both and more information, see the [installation guide](../setup/install/mac-install.md).

**Upgrades**

- Docker 1.12.0 with experimental features
- Docker Machine 0.8.0
- Docker Compose 1.8.0

**Bug fixes and minor changes**

- Check for updates, auto-update and diagnose can be run by non-admin users
- osxfs: fixed an issue causing occasional incorrect short reads
- osxfs: fixed an issue causing occasional EIO errors
- osxfs: fixed an issue causing `inotify` creation events to fail
- osxfs: increased the `fs.inotify.max_user_watches` limit in Moby to 524288
- The UI shows documentation link for sharing volumes
- Clearer error message when running with outdated VirtualBox version
- Added link to sources for qemu-img

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app

- There are a number of issues with the performance of directories bind-mounted with `osxfs`. In particular, writes of small blocks, and traversals of large directories are currently slow. Additionally, containers that perform large numbers of directory operations, such as repeated scans of large directory trees, may suffer from poor performance. For more information and workarounds, see [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md) in [Logs and Troubleshooting](../troubleshoot-and-support/troubleshoot/index.md).

- Under some unhandled error conditions, `inotify` event delivery can fail and become permanently disabled. The workaround is to restart Docker.app

### Beta 20 Release Notes (2016-07-19 1.12.0-rc4-beta20)

**Bug fixes and minor changes**

- Fixed `docker.sock` permission issues
- Don't check for update when the settings panel opens
- Removed obsolete DNS workaround
- Use the secondary DNS server in more circumstances
- Limit the number of concurrent port forwards to avoid running out of resources
- Store the database as a "bare" git repo to avoid corruption problems

**Known issues**

- `Docker.app` sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker for Mac (`Docker.app`).

### Beta 19 Release Notes (2016-07-14 1.12.0-rc4-beta19)

**New**

- Added privacy tab in settings
- Allow the definition of HTTP proxy overrides in the UI

**Upgrades**

- Docker 1.12.0 RC4
- Docker Compose 1.8.0 RC2
- Docker Machine 0.8.0 RC2
- Linux kernel 4.4.15

**Bug fixes and minor changes**

- Filesystem sharing permissions can only be configured in the UI (no more `/Mac` in moby)
- `com.docker.osx.xhyve.hyperkit`: increased max number of fds to 10240
- Improved Moby syslog facilities
- Improved file-sharing tab
- `com.docker.slirp`: included the DNS TCP fallback fix, required when UDP responses are truncated
- `docker build/events/logs/stats...` won't leak when interrupted with Ctrl-C

**Known issues**

- See [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 18.1 Release Notes (2016-07-07 1.12.0-rc3-beta18.1)

> [!NOTE]
>
> Docker 1.12.0 RC3 release introduces a backward incompatible change from RC2. You can fix this by recreating or updating your containers.

**Hotfix**

- Fixed issue resulting in error "Hijack is incompatible with use of CloseNotifier", reverts previous fix for `Ctrl-C` during build.

**New**

- New host/container file sharing UI
- `/Mac` bind mount prefix is deprecated and will be removed soon

**Upgrades**

- Docker 1.12.0 RC3

**Bug fixes and minor changes**

- VPNKit: Improved scalability as number of network connections increases
- The docker API proxy was failing to deal with some 1.12 features, such as health check.

**Known issues**

- See [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 18 Release Notes (2016-07-06 1.12.0-rc3-beta18)

**New**

- New host/container file sharing UI
- `/Mac` bind mount prefix is deprecated and will be removed soon

**Upgrades**

- Docker 1.12.0 RC3

**Bug fixes and minor changes**

- VPNKit: Improved scalability as number of network connections increases
- Interrupting a `docker build` with Ctrl-C will actually stop the build
- The docker API proxy was failing to deal with some 1.12 features, such as health check.

**Known issues**

- See [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 17 Release Notes (2016-06-29 1.12.0-rc2-beta17)

**Upgrades**

- Linux kernel 4.4.14, AUFS 20160627

**Bug fixes and minor changes**

- Documentation moved to [/desktop/mac/](../index.md)
- Allow non-admin users to launch the app for the first time (using admin creds)
- Prompt non-admin users for admin password when needed in Preferences
- Fixed download links, documentation links
- Fixed "failure: No error" message in diagnostic panel
- Improved diagnostics for networking and logs for the service port openers

**Known issues**

- See [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 16 Release Notes (2016-06-17 1.12.0-rc2-beta16)

**Upgrades**

- Docker 1.12.0 RC2
- docker-compose 1.8.0 RC1
- docker-machine 0.8.0 RC1
- notary 0.3
- Alpine 3.4

**Bug fixes and minor changes**

- VPNKit: Fixed a regressed error message when a port is in use
- Fixed UI crashing with `NSInternalInconsistencyException` / fixed leak
- HyperKit API: Improved error reporting
- osxfs: fix sporadic EBADF due to fd access/release races (#3683)

**Known issues**

- See [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 15 Release Notes (2016-06-10 1.11.2-beta15)

**New**

- Registry mirror and insecure registries can now be configured from Preferences
- Virtual machine can now be restarted from Preferences
- `sysctl.conf` can be edited from Preferences

**Upgrades**

- Docker 1.11.2
- Linux 4.4.12, `aufs` 20160530

**Bug fixes and minor changes**

- Timekeeping in Moby VM improved
- Number of concurrent TCP/UDP connections increased in VPNKit
- Hyperkit: `vsock` stability improvements
- Fixed crash when user is admin

**Known issues**

- See [Known Issues](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 14 Release Notes (2016-06-02 1.11.1-beta14)

**New**

- New settings menu item, **Diagnose & Feedback**, is available to run diagnostics and upload logs to Docker.

**Known issues**

- `Docker.app` sometimes uses 200% CPU after macOS wakes up from sleep mode with macOS 10.10. The issue is being investigated. The workaround is to restart `Docker.app`.

**Bug fixes and minor changes**

- `osxfs`: now support `statfs`
- **Preferences**: updated toolbar icons
- Fall back to secondary DNS server if primary fails.
- Added a link to the documentation from menu.

### Beta 13.1 Release Notes (2016-05-28 1.11.1-beta13.1)

**Hotfixes**

- `osxfs`:
  - Fixed sporadic EBADF errors and End_of_file crashes due to a race corrupting node table invariants
  - Fixed a crash after accessing a sibling of a file moved to another directory caused by a node table invariant violation
- Fixed issue where Proxy settings were applied on network change, causing docker daemon to restart too often
- Fixed issue where log file sizes doubled on docker daemon restart

### Beta 13 Release Notes (2016-05-25 1.11.1-beta13)

**New**

- `osxfs`: Enabled 10ms dcache for 3x speedup on a `go list ./...` test against docker/machine. Workloads heavy in file system path resolution (common among dynamic languages and build systems) will have those resolutions performed in amortized constant time rather than time linear in the depth of the path so speedups of 2-10x will be common.

- Support multiple users on the same machine, non-admin users can use the app as long as `vmnetd` has been installed. Currently, only one user can be logged in at the same time.

- Basic support for using system HTTP/HTTPS proxy in docker daemon

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app.

**Bug fixes and minor changes**

- `osxfs`:
  - setting `atime` and `mtime` of nodes is now supported
  - Fixed major regression in Beta 12 with ENOENT, ENOTEMPY, and other spurious errors after a directory rename. This manifested as `npm install` failure and other directory traversal issues.
  - Fixed temporary file ENOENT errors
  - Fixed in-place editing file truncation error, such as when running `perl -i`
- improved time synchronisation after sleep

### Beta 12 Release (2016-05-17 1.11.1-beta12)

**Upgrades**

- FUSE 7.23 for osxfs

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app.

**Bug fixes and minor changes**

- UI improvements
- Fixed a problem in osxfs where`mkdir` returned EBUSY but directory was created.

### Beta 11 Release (2016-05-10 1.11.1-beta11)

**New**

The `osxfs` file system now persists ownership changes in an extended attribute.

**Upgrades**

- docker-compose 1.7.1 (see [changelog](https://github.com/docker/compose/releases/tag/1.7.1))
- Linux kernel 4.4.9

**Bug fixes and minor changes**

- Desktop notifications after successful update
- No "update available" popup during install process
- Fixed repeated bind of privileged ports
- `osxfs`: Fixed the block count reported by stat
- Moby (Backend) fixes:
  - Fixed `vsock` half closed issue
  - Added NFS support
  - Hostname is now Moby, not Docker
  - Fixes to disk formatting scripts
  - Linux kernel upgrade to 4.4.9

### Beta 10 Release (2016-05-03 1.11.0-beta10)

**New**

- Token validation is now done over an actual SSL tunnel (HTTPS). (This should fix issues with antivirus applications.)

**Upgrades**

- Docker 1.11.1

**Bug fixes and minor changes**

- UCP now starts again
- Include debugging symbols in HyperKit
- vsock stability improvements
- Addressed glitches in **Preferences** panel
- Fixed issues impacting the “whale menu”
- Fixed uninstall process
- HyperKit vcpu state machine improvements, may improve suspend/resume

### Beta 9 Release (2016-04-26 1.11.0-beta9)

**New**

- New Preferences window - memory and vCPUs now adjustable
- `localhost` is now used for port forwarding by default.`docker.local` will no longer work as of Beta 9.

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app.

**Bug fixes and minor changes**

- Fix loopback device naming
- Improved docker socket download and osxfs sequential write by 20%
- `com.docker.osxfs`
  - improved sequential read throughput by up to 20%
  - improved `readdir` performance by up to 6x
  - log all fatal exceptions
- More reliable DNS forwarding over UDP and TCP
- UDP ports can be proxied over vsock
- Fixed EADDRINUSE (manifesting as errno 526) when ports are re-used
- Send ICMP when asked to not fragment and we can't guarantee it
- Fixed parsing of UDP datagrams with IP socket options
- Drop abnormally large ethernet frames
- Improved HyperKit logging
- Record virtual machine start and stop events

### Beta 8 Release (2016-04-20 1.11.0-beta8)

**New**

- Networking mode switched to VPN compatible by default, and as part of this change the overall experience has been improved:

* `docker.local` now works in VPN compatibility mode
* exposing ports on the Mac is available in both networking modes
* port forwarding of privileged ports now works in both networking modes
* traffic to external DNS servers is no longer dropped in VPN mode

- `osxfs` now uses `AF_VSOCK` for transport giving ~1.8x speedup for large sequential read/write workloads but increasing latency by ~1.3x. `osxfs` performance engineering work continues.

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart `Docker.app`

**Bug fixes and minor changes**

- Apple System Log now used for most logs instead of direct filesystem logging
- `docker_proxy` fixes
- Merged HyperKit upstream patches
- Improved error reporting in `nat` network mode
- `osxfs` `transfused` client now logs over `AF_VSOCK`
- Fixed a `com.docker.osx.HyperKit.linux` supervisor deadlock if processes exit during a controlled shutdown
- Fixed VPN mode malformed DNS query bug preventing some resolutions

### Beta 7 Release (2016-04-12 1.11.0-beta7)

**New**

- Docs are updated per the Beta 7 release
- Use AF_VSOCK for docker socket transport

**Upgrades**

- docker 1.11.0-rc5
- docker-machine 0.7.0-rc3
- docker-compose 1.7.0rc2

**Known issues**

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app

- If VPN mode is enabled and then disabled and then re-enabled again, `docker ps` will block for 90s

**Bug fixes and minor changes**

- Logging improvements
- Improve process management

### Beta 6 Release (2016-04-05 1.11.0-beta6)

**New**

- Docs are updated per the Beta 6 release
- Added uninstall option in user interface

**Upgrades**

- docker 1.11.0-rc5
- docker-machine 0.7.0-rc3
- docker-compose 1.7.0rc2

**Known issues**

- `Docker.app` sometimes uses 200% CPU after macOS wakes up from sleep mode.
  The issue is being investigated. The workaround is to restart
  `Docker.app`.

- If VPN mode is enabled, then disabled and re-enabled again,
  `docker ps` will block for 90 seconds.

**Bug fixes and minor changes**

- Fixed osxfs multiple same directory bind mounts stopping inotify
- Fixed osxfs `setattr` on mode 0 files (`sed` failures)
- Fixed osxfs blocking all operations during `readdir`
- Fixed osxfs mishandled errors which crashed the file system and VM
- Removed outdated `lofs`/`9p` support
- Added more debugging info to logs uploaded by `pinata diagnose`
- Improved diagnostics from within the virtual machine
- VirtualBox version check now also works without VBoxManage in path
- VPN mode now uses same IP range as NAT mode
- Tokens are now verified on port 443
- Removed outdated uninstall scripts
- Increased default ulimits
- Port forwarding with `-p` and `-P` should work in VPN mode
- Fixed a memory leak in `com.docker.db`
- Fixed a race condition on startup between Docker and networking which can
  lead to `Docker.app` not starting on reboot

### Beta 5 Release (2016-03-29 1.10.3-beta5)

**New**

- Docs are updated per the Beta 5 release!

**Known issues**

- There is a race on startup between docker and networking which can lead to Docker.app not starting on reboot. The workaround is to restart the application manually.

- Docker.app sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart Docker.app.

- In VPN mode, the `-p` option needs to be explicitly of the form `-p <host port>:<container port>`. `-p <port>` and `-P` will not work yet.

**Bug fixes and minor changes**

- Updated DMG background image
- Show correct VM memory in Preferences
- Feedback opens forum, not email
- Fixed RAM amount error message
- Fixed wording of CPU error dialog
- Removed status from Preferences
- Check for incompatible versions of VirtualBox

### Beta 4 Release (2016-03-22 1.10.3-beta4)

**New Features and Upgrades**

- File system/sharing: Support `inotify` events so that file system events on the Mac will trigger file system activations inside Linux containers

- Install Docker Machine as a part of Docker for Mac install in `/usr/local`

- Added animated popover window to help first-time users get started

- Added a Beta icon to About box

**Known Issues**

- There is a race on startup between Docker and networking that can lead to `Docker.app` not starting on reboot. The workaround is to restart the application manually.

- `Docker.app` sometimes uses 200% CPU after macOS wakes up from sleep mode. The issue is being investigated. The workaround is to restart `Docker.app`.

- VPN/Hostnet: In VPN mode, the `-p` option needs to be explicitly of the form
  `-p <host port>:<container port>`. `-p <port>` and `-P` will not
  work yet.

**Bug fixes and minor changes**

- Hostnet/VPN mode: Fixed Moby DNS resolver failures by proxying the "Recursion Available" flag.

- `docker ps` shows IP address rather than `docker.local`

- Re-enabled support for macOS Yosemite version 10.10

- Ensured binaries are built for 10.10 rather than 10.11

- Fixed “Notification Center”-related crash on startup

- Fixed watchdog crash on startup

### Beta 3 Release (2016-03-15 1.10.3-beta3)

**New Features and Upgrades**

- Improved file sharing write speed in osxfs

- User space networking: Renamed `bridged` mode to `nat` mode

- Docker runs in debug mode by default for new installs

- Docker Engine: Upgraded to 1.10.3

**Bug fixes and minor changes**

- GUI: Auto update automatically checks for new versions again

- File System
  - Fixed osxfs chmod on sockets
  - FixED osxfs EINVAL from `open` using O_NOFOLLOW

- Hypervisor stability fixes, resynced with upstream repository

- Hostnet/VPN mode
  - Fixed get/set VPN mode in Preferences (GUI)
  - Added more verbose logging on errors in `nat` mode
  - Show correct forwarding details in `docker ps/inspect/port` in `nat` mode

- New lines ignored in token entry field

- Feedback mail has app version in subject field

- Clarified open source licenses

- Crash reporting and error handling
  - Fixed HockeyApp crash reporting
  - Fatal GUI errors now correctly terminate the app again
  - Fix proxy panics on EOF when decoding JSON
  - Fix long delay/crash when switching from `hostnet` to `nat` mode

- Logging
  - Moby logs included in diagnose upload
  - App version included in logs on startup

### Beta 2 Release (2016-03-08 1.10.2-beta2)

**New Features and Upgrades**

- GUI
  - Added VPN mode/`hostnet` to Preferences
  - Added disable Time Machine backups of VM disk image to Preferences

- Added `pinata` configuration tool for experimental Preferences

- File System: Added guest-to-guest FIFO and socket file support

- Upgraded Notary to version 0.2

**Bug fixes and minor changes**

- Fixed data corruption bug during cp (use of sendfile/splice)
- Fixed About box to contain correct version string

- Hostnet/VPN mode
  - Stability fixes and tests
  - Fixed DNS issues when changing networks

- Cleaned up Docker startup code related to Moby

- Fixed various problems with linking and dependencies

- Various improvements to logging

### Beta 1 Release (2016-03-01 1.10.2-b1)

- GUI
  - Added dialog to explain why we need admin rights
  - Removed shutdown/quit window
  - Improved machine migration
  - Added “Help” option in menu to open documentation web pages
  - Added license agreement
  - Added MixPanel support

- Added HockeyApp crash reporting
- Improve signal handling on task manager
- Use ISO timestamps with microsecond precision for logging
- Clean up logging format

- Packaging
  - Create /usr/local if it doesn't exist
  - docker-uninstall improvements
  - Remove docker-select as it's no longer used

- Hypervisor
  - Added PID file
  - Networking reliability improvements

- Hostnet
  - Fixed port forwarding issue
  - Stability fixes
  - Fixed setting hostname

- Fixed permissions on `usr/local` symbolic links


---

# Docker Desktop for Windows Edge Release notes

*Sección: Desktop*

This page contains information about Docker Desktop Edge releases. Edge releases give you early access to our newest features. Note that some of the features may be experimental, and some of them may not ever reach the Stable release.

 For Docker Desktop system requirements, see
[What to know before you install](../setup/install/windows-install.md#system-requirements).

## Docker Desktop Community 2.5.4
2020-12-07


### Upgrades

- [Docker Engine 20.10.0-rc2](https://github.com/docker/docker-ce/blob/master/CHANGELOG.md#20100)
- [Go 1.15.6](https://github.com/golang/go/issues?q=milestone%3AGo1.15.6+label%3ACherryPickApproved+)

### Bug fixes and minor changes

- Fixed an issue causing the background update to fail when the current user is not an administrator.
- Downgraded the kernel to [4.19.121](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.121-2a1dbedf3f998dac347c499808d7c7e029fbc4d3-amd64/images/sha256-4e7d94522be4f25f1fbb626d5a0142cbb6e785f37e437f6fd4285e64a199883a?context=repo) to reduce the CPU usage of hyperkit. Fixes [docker/for-mac#5044](https://github.com/docker/for-mac/issues/5044)

## Docker Desktop Community 2.5.3
2020-11-30


### Upgrades

- [Compose CLI v1.0.3](https://github.com/docker/compose-cli/releases/tag/v1.0.3)

## Docker Desktop Community 2.5.2
2020-11-26


### New

- Use of three digit version number.
- Starting with Docker Desktop 2.5.2, updates will be much smaller as they will be applied using delta patches.

### Bug fixes and minor changes

- Fixed an unexpected EOF error when trying to start a non-existing container with `-v /var/run/docker.sock:`. See [docker/for-mac#5025](https://github.com/docker/for-mac/issues/5025).

## Docker Desktop Community 2.5.1.0
2020-11-18


This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing Docker Desktop.

### Upgrades

- [Docker Engine 20.10.0-rc1](https://github.com/docker/docker-ce/blob/master/CHANGELOG.md#20100)
- [Compose CLI v1.0.2](https://github.com/docker/compose-cli/releases/tag/v1.0.2)
- [Snyk v1.424.4](https://github.com/snyk/snyk/releases/tag/v1.424.4)
- [Kubernetes 1.19.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.3)

### Bug fixes and minor changes

- Renamed 'Run Diagnostics' to 'Get support'.
- Fixed an issue with the WSL 2 backend where some network plugins may fail to load, provoking a crash of the Docker daemon.
- Fixed an unexpected EOF error when trying to start a non-existing container. See [docker/for-mac#5025](https://github.com/docker/for-mac/issues/5025).

## Docker Desktop Community 2.4.2.0
2020-10-19


### New

- If you have enabled [Vulnerability Scanning](../../docker-hub/repos/manage/vulnerability-scanning.md) in Docker Hub, the scan results will now appear in Docker Desktop.

### Upgrades

- [Docker Engine 20.10.0 beta1](https://github.com/docker/docker-ce/blob/0fc7084265b3786a5867ec311d3f916af7bf7a23/CHANGELOG.md)
- [Docker Compose CLI - 0.1.22](https://github.com/docker/compose-cli/releases/tag/v0.1.22)
- [Linux kernel 5.4.39](https://hub.docker.com/layers/linuxkit/kernel/5.4.39-f39f83d0d475b274938c86eaa796022bfc7063d2/images/sha256-8614670219aca0bb276d4749e479591b60cd348abc770ac9ecd09ee4c1575405?context=explore)
- [Kubernetes 1.19.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.19.2)
- [Go 1.15.2](https://github.com/golang/go/issues?q=milestone:Go1.15.2+label:CherryPickApproved)

* Deprecation
  - Docker Desktop cannot be installed on Windows 1703 (build 15063) anymore.

### Bug fixes and minor changes

- Fixed an issue that can intermittently cause the WSL 2 backend to fail to start.
- Fixed an issue related to NFS mounting. See [docker/for-mac#4958](https://github.com/docker/for-mac/issues/4958).
- Fixed an issue with http proxy exclude lists containing entries such as `localhost` or `127.0.0.1`. Fixes [docker/for-win#8750](https://github.com/docker/for-win/issues/8750).
- When WSL integration process unexpectedly stops, the user is now notified and can decide to restart it or not, instead of always try to restart it in a loop. fixes [docker/for-win#8968](https://github.com/docker/for-win/issues/8968).
- Fixed an issue related to container logs that lag under heavy load. Fixes [docker/for-win#8216](https://github.com/docker/for-win/issues/8216).
- Diagnostics: avoid hanging when Kubernetes is in a broken state.
- When sharing a file into a container (e.g. `docker run -v ~/.gitconfig`) Docker Desktop does not watch the parent directory. Fixes [docker/for-mac#4981](https://github.com/docker/for-mac/issues/4981).
- Always flush file system caches synchronously on container start. See [docker/for-mac#4943](https://github.com/docker/for-mac/issues/4943).

## Docker Desktop Community 2.4.1.0
2020-10-01


### Upgrades

- [Docker Compose CLI - 0.1.18](https://github.com/docker/compose-cli)
- [Docker Compose 1.27.4](https://github.com/docker/compose/releases/tag/1.27.4)
- [Snyk v1.399.1](https://github.com/snyk/snyk/releases/tag/v1.399.1)
- [Docker Engine 19.03.13](https://github.com/docker/docker-ce/releases/tag/v19.03.13)

### Bug fixes and minor changes

- Fixed the path to the installer log file default location when the username contains a space. Fixes [docker/for-win#7941](https://github.com/docker/for-win/issues/7941).

## Docker Desktop Community 2.3.7.0
2020-09-17


### New

- [Amazon ECR Credential Helper](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.4.0)

### Upgrades

- [Docker ACI integration 0.1.15](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.15)
- [Snyk v0.393.0](https://github.com/snyk/snyk/releases/tag/v1.393.0)

### Bug fixes and minor changes

**WSL 2**

  - Fixed an issue that intermittently made the backend fail to start.
  - Fixed a proxy crash that happened when glibc was not compatible. See [docker/for-win#8183](https://github.com/docker/for-win/issues/8183).
  - Fixed an issue where restarting Docker Desktop may delete files mounted in a container.
  - Fixed an issue where restarting Docker Desktop truncates files when a single file is mounted in a container. See [docker/for-win#8439](https://github.com/docker/for-win/issues/8439).

**Other fixes**

- Fixed the VM debug shell used for low-level debugging.
- Fixed compatibility with Go 1.15 clients. See [docker/for-mac#4855](https://github.com/docker/for-mac/issues/4855).
- Avoid exposing `/host_mnt` paths in `docker container inspect` and `docker volume inspect`. Fixes [docker/for-mac#4859](https://github.com/docker/for-mac/issues/4859).
- Fixed container logs lagging under heavy load. See [docker/for-win#8216](https://github.com/docker/for-win/issues/8216).

### Known issues

- The `clock_gettime64` system call returns `EPERM` rather than `ENOSYS`
in i386 images. To work around this issue, disable `seccomp` by using
the `--privileged` flag. See [docker/for-win#8326](https://github.com/docker/for-win/issues/8326).

## Docker Desktop Community 2.3.6.2
2020-09-09


### Upgrades

- [Docker Compose 1.27.0](https://github.com/docker/compose/releases/tag/1.27.0)

### Bug fixes and minor changes

- Fixed an issue with mount shadowing in WSL 2. See [docker/for-win#8183](https://github.com/docker/for-win/issues/8183) and [docker/for-win#8316](https://github.com/docker/for-win/issues/8316).

## Docker Desktop Community 2.3.6.0
2020-09-01


### New

- In partnership with Snyk, Docker Desktop launches vulnerability scanning for Docker local images.
- Docker ECS plugin has been replaced by ECS cloud integration
- Docker UI:
  - The Images view now has search and filter options.
  - You can now push an image to Docker Hub using the Remote repositories drop-down menu.

### Upgrades

- [Alpine 3.12](https://alpinelinux.org/posts/Alpine-3.12.0-released.html)
- [Kubernetes 1.18.8](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.8)

### Bug fixes and minor changes

- Fixed an issue with Docker Desktop integration with other WSL 2 distributions. See [docker/for-win#6894](https://github.com/docker/for-win/issues/6894)
- Fixed DNS resolution of short names. See [docker/for-win#4425](https://github.com/docker/for-win/issues/4425)

## Docker Desktop Community 2.3.5.1
2020-08-25


### Bug fixes and minor changes

- Fixed an issue which broke WSL 2 integration when stopping Docker Desktop while containers with bind mounts are present. See [docker/for-win#8164](https://github.com/docker/for-win/issues/8164)

## Docker Desktop Community 2.3.5.0
2020-08-20


### New

- The **Images** view on the Dashboard now allows you to interact with images on Docker Hub. You can now pull a remote repository with specific tags from Docker Hub, or view the details of the repository on the Docker Hub page. To access the new Images view, from the Docker menu, select **Dashboard** > **Images**.

- Docker Desktop now enables BuildKit by default after a reset to factory defaults. To revert to the old docker build experience, go to **Preferences** > **Docker Engine** and then disable the BuildKit feature.

- Docker Desktop now supports running on WSL 2 on the latest updates of Windows 10 versions 1903 and 1909 (in addition to the existing support for version 2004). This also means that Docker Desktop can be installed on those builds of Windows 10 Home.

### Upgrades

- [Go 1.14.7](https://github.com/golang/go/issues?q=milestone:Go1.14.7+label:CherryPickApproved)
- [Docker ECS integration v1.0.0-beta.5](https://github.com/docker/ecs-plugin/releases/tag/v1.0.0-beta.5)
- [Docker Engine 19.03.13-beta2](https://github.com/docker/docker-ce/releases/tag/v19.03.13-beta2)
- [Docker ACI integration 0.1.12](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.12)

### Bug fixes and minor changes

- Moved **Dashboard** to the top of the whale menu.
- The systray icon now responds to dark or light mode. See [docker/for-win#4113](https://github.com/docker/for-win/issues/4113)
- Improved the error handling when `dockerd` crashes.
- Fixed minor bugs in the **Images** view.

## Docker Desktop Community 2.3.4.0
2020-07-28


### New

- Docker Desktop introduces the new **Images** view to the Docker Dashboard. The Images view allows users to view a list of Docker images on the disk, run an image as a container, pull the latest version of an image from Docker Hub, inspect images, and remove any unwanted images from the disk.

  To access the new Images view, from the Docker menu, select **Dashboard** > **Images**.

### Upgrades

- [Docker ECS integration v1.0.0-beta.4](https://github.com/docker/ecs-plugin/releases/tag/v1.0.0-beta.4)
- [Kubernetes 1.18.6](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.6)

### Bug fixes and minor changes

- UI changes to dark or light theme depending on Windows default app mode.
- Copying the container logs from the dashboard does not copy the ANSI color codes to the clipboard anymore.

## Docker Desktop Community 2.3.3.2
2020-07-21


### Upgrades

- [Docker ECS integration v1.0.0-beta.2](https://github.com/docker/ecs-plugin/releases/tag/v1.0.0-beta.2)
- [Docker ACI integration 0.1.10](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.10)

## Docker Desktop Community 2.3.3.1
2020-07-10


### Bug fixes and minor changes

- Fixed a bug where the ECS plugin was not visible from WSL 2.

## Docker Desktop Community 2.3.3.0
2020-07-09


### Upgrades

- Beta release of Docker ECS integration v1.0.0-beta.1.
- [Docker ACI integration v0.1.7](https://github.com/docker/aci-integration-beta/releases/tag/v0.1.7)
- [Docker Compose 1.26.2](https://github.com/docker/compose/releases/tag/1.26.2)

### Bug fixes and minor changes

- Compose-on-Kubernetes is no longer included in the Docker Desktop installer. You can download it separately from the compose-on-kubernetes [release page](https://github.com/docker/compose-on-kubernetes/releases).

## Docker Desktop Community 2.3.2.1
2020-06-29


### Security

- Fixed a regression in Docker Desktop Edge 2.3.2.0 on Windows where the Docker API was exposed by default on a random port on all interfaces.

## Docker Desktop Community 2.3.2.0
2020-06-25

### Upgrades

- [Docker 19.03.12](https://github.com/docker/docker-ce/releases/tag/v19.03.12)
- [Docker Compose 1.26.0](https://github.com/docker/compose/releases/tag/1.26.0)
- [Kubernetes 1.18.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.18.3)
- Beta release of the [Docker ACI integration](/engine/context/aci-integration/)

### Bug fixes and minor changes

- Fixed application startup if `hosts` is specified inside the Docker `daemon.json`. See [docker/for-win#6895](https://github.com/docker/for-win/issues/6895#issuecomment-637429117).
- Fixed opening a CLI from the dashboard for Windows containers. See [docker/for-win#7079](https://github.com/docker/for-win/issues/7079).
- Fixed an issue where adding a folder on a non-existing drive in the settings would create an empty entry. See [docker/for-win#6797](https://github.com/docker/for-win/issues/6797).
- Fixed an issue when updating Windows to a WSL 2 capable version, where a configuration file is locked by the old Hyper-V VM.
- Pinning the application to the taskbar and clicking on it will launch the container view if Docker is already running.
- Left-clicking on the Docker icon in the system tray now launches the container view Dashboard. See [docker/for-win#6650](https://github.com/docker/for-win/issues/6650).
- Fixed an issue which blocks Docker Desktop startup if `localhost:2375` is used by another program. See [docker/for-win#6929](https://github.com/docker/for-win/issues/6929) and [docker/for-win#6961](https://github.com/docker/for-win/issues/6961).
- Docker contexts are now synced between Windows and WSL 2 distributions.
- Docker Desktop now prompts users to share drives for paths like `////c/Users/foo`, rather than only paths like `C:\Users\foo` and `C:/Users/foo`.
- The installer now returns a non-zero exit code on error or when the user cancels the installation.
- Avoid failing withFixed an issue which caused Docker Desktop to fail with `Function not implemented` error during file I/O on shared volumes. See [docker/for-win#5955](https://github.com/docker/for-win/issues/5955).
- Fixed an issue when bind mounting a mounted host directory inside a container. See [docker/for-win#5089](https://github.com/docker/for-win/issues/5089).
- Removed the legacy Kubernetes context `docker-for-desktop`. The context `docker-desktop` should be used instead. See [docker/for-win#5089](https://github.com/docker/for-win/issues/5089).

## Docker Desktop Community 2.3.1.0
2020-05-20


### Upgrades

- [Docker Compose 1.26.0-rc4](https://github.com/docker/compose/releases/tag/1.26.0-rc4)
- Upgrade to Qemu 4.2.0, add Risc-V support

### Bug fixes and minor changes

**Hyper-V**

- Create drive symlinks in VM at startup to avoid breaking setup that was using them. Fixes [docker/for-win#6628](https://github.com/docker/for-win/issues/6628).
- Implement `fallocate` for shared filesystems. See [docker/for-win#6658](https://github.com/docker/for-win/issues/6658#issuecomment-627736820).

**WSL 2**

- Configure CLI to use Docker Desktop credential store.
- Adds a restart button to the popup prompting the user to install the Linux kernel.
- More reliable bootstrap, do not rely on `wslpath` for path translation, retry mounts on errors at startup.

**Dashboard**

- Fixed containers logs which were sometimes truncated. Fixes [docker/for-win#5954](https://github.com/docker/for-win/issues/5954)
- Fixed `open with vs code` button for compose app deployed from a WSL 2 Linux Workspace.

**Other fixes**

- Fixed an installer crash when an old and/or partially uninstalled version of Docker Desktop was present on the system. [Fixes docker/for-win/6536](https://github.com/docker/for-win/issues/6536).
- Fixed home expansion when using tilde in bind mounts source (for example, `-v ~/dir:/vm-dir`)
- `localhost` and `127.0.0.1` can both be used in the proxy settings to redirect to a proxy on the host. Fixes [docker/for-win#5715](https://github.com/docker/for-win/issues/5715).
- Fixed a typo in the backend destroy notification. Fixes [docker/for-win#6739](https://github.com/docker/for-win/issues/6739).
- Fixed a crash which sometimes occurred when Docker Desktop loads a corrupted Docker CLI configuration file. Fixes [docker/for-win#6657](https://github.com/docker/for-win/issues/6657).
- Fixed a delay when opening the systray menu. Fixes [docker/for-win#1011](https://github.com/docker/for-win/issues/1011).

### Known issues

**WSL 2**

- Swarm service bind mounts are not always restored correctly.
- Bind mounts of files living outside of the root mount point (files within `/mnt/c`, `/tmp`, `/run...`) don't work correctly when multiple containers mount them.

## Docker Desktop Community 2.3.0.1
2020-04-28



### Bug fixes and minor changes

- Fixed an upgrade bug where users on versions still using the PowerShell-based VM management experience a silent un-installation crash leading to Docker Desktop being uninstalled instead of upgraded.
- Fixed a crash when failing to login due to no Internet connection.
- Fixed bug in handling shared volume paths with `..` characters. Fixes [docker/for-win#5375](https://github.com/docker/for-win/issues/5375).
- WSL 2: Docker Desktop detects when the wsl-distribution is stopped and displays an actionable error message.
- Fixed a bug in `ftruncate` which prevented [libgit2sharp](https://github.com/libgit2/libgit2sharp) from cloning repositories on shared volumes. See [docker/for-win#5808](https://github.com/docker/for-win/issues/5808#issuecomment-610996272).
- Fixed a bug that caused starting and stopping of a Compose application from the UI to fail when the path contains whitespace.

## Docker Desktop Community 2.3.0.0
2020-04-20



### Upgrades

- [Docker Compose 1.25.5](https://github.com/docker/compose/releases/tag/1.25.5)
- [Go 1.13.10](https://github.com/golang/go/issues?q=milestone%3AGo1.13.10+label%3ACherryPickApproved)
- [Linux kernel 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-ce15f646db9b062dc947cfc0c1deab019fa63f96-amd64/images/sha256-6c252199aee548e4bdc8457e0a068e7d8e81c2649d4c1e26e4150daa253a85d8?context=repo)
- LinuxKit [init](https://hub.docker.com/layers/linuxkit/init/1a80a9907b35b9a808e7868ffb7b0da29ee64a95/images/sha256-64cc8fa50d63940dbaa9979a13c362c89ecb4439bcb3ab22c40d300b9c0b597e?context=explore), [runc](https://hub.docker.com/layers/linuxkit/runc/69b4a35eaa22eba4990ee52cccc8f48f6c08ed03/images/sha256-57e3c7cbd96790990cf87d7b0f30f459ea0b6f9768b03b32a89b832b73546280?context=explore), and [containerd](https://hub.docker.com/layers/linuxkit/containerd/09553963ed9da626c25cf8acdf6d62ec37645412/images/sha256-866be7edb0598430709f88d0e1c6ed7bfd4a397b5ed220e1f793ee9067255ff1?context=explore)

### Bug fixes and minor changes

> Docker Desktop Edge 2.3.0.0 fixes 10 issues reported on the [docker/for-win](https://github.com/docker/for-win/issues) GitHub repository.

**WSL 2**

- Detect when the WSL 2 backend stops and allow the user to restart it.
- Added support for chmod/chown on WSL 2 bind mounts. Fixed [docker/for-win#6284](https://github.com/docker/for-win/issues/6284).
- Fixed a race condition when exposing ports.
- Prevent the WSL 2 dialog from blocking other windows.
- Added a check that virtualization is enabled in the BIOS.

**Filesharing**

- Fixed a bug when parent directories of shared folders are renamed, leading to spurious `File not found` errors. Fixes [docker/for-win#6200](https://github.com/docker/for-win/issues/6200).
- Fixed bug where a letter and two digit root folder name causes Docker Compose to fail creating directories inside the volume. Fixes [docker/for-win#6248](https://github.com/docker/for-win/issues/6248).
- Fixed a bug which prevented containers from seeing file updates on shared volumes, when under load and a container restarts. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530#issuecomment-608804192)
- Fixed a bug where host paths are incorrectly translated into VM paths. Fixes [docker/for-win#6209](https://github.com/docker/for-win/issues/6209).
- Fixed bug receiving file events on long paths (> 260 characters). Fixes [docker/for-win#6337](https://github.com/docker/for-win/issues/6337).

**Other fixes**

- Fixed a bug where containers disappeared from the UI when Kubernetes context is invalid. Fixes [docker/for-win#6037](https://github.com/docker/for-win/issues/6037).
- Fixed Windows event logs filtering when copying them to the Docker Desktop log files. Fixes [docker/for-win#6258](https://github.com/docker/for-win/issues/6258).
- Fixed a handle leak in `vpnkit-bridge`. Fixed [docker/for-win#5841](https://github.com/docker/for-win/issues/5841)
- Fixed a bug when removing Docker Desktop virtual switch.
- Added a link to the Stable channel from the Docker Desktop UI.
- IPv6 has been re-enabled in the embedded Linux kernel, so listening on IPv6 addresses works again. Fixed [docker/for-win#6206](https://github.com/docker/for-win/issues/6206) and [docker/for-mac#4415](https://github.com/docker/for-mac/issues/4415).
- Made the embedded terminal resizable.
- Fixed a bug which only respected the "expose on TCP" Docker engine API setting on application restart. Setting will now take effect when the Apply button is clicked.
- Fixed a bug where diagnostic upload would fail if the username contained spaces.

## Docker Desktop Community 2.2.3.0
2020-04-02



### Upgrades

- [Docker 19.03.8](https://github.com/docker/docker-ce/releases/tag/v19.03.8)
- [Docker Compose 1.26.0-rc3](https://github.com/docker/compose/releases/tag/1.26.0-rc3)
- [Linux 4.19.76](https://hub.docker.com/layers/docker/for-desktop-kernel/4.19.76-4e5d9e5f3bde0abf236f97e4a81b029ae0f5f6e7-amd64/images/sha256-11dc0f6ee3187088219ba1463ebb378f5093a7d98f176ddfd62dd6b741c2dd2d?context=repo)

### New

- Docker Desktop introduces a new onboarding tutorial upon first startup. The Quick Start tutorial guides users to get started with Docker in a few easy steps. It includes a simple exercise to build an example Docker image, run it as a container, push and save the image to Docker Hub.

### Bug fixes and minor changes

> Docker Desktop Edge 2.2.3.0 fixes 28 issues reported on the [docker/for-win](https://github.com/docker/for-win/issues) GitHub repository.

**WSL 2**
- Docker Desktop only exposes host ports in Linux if the Windows port is available.
- Docker Desktop now allows users to refresh the list of Linux distributions.
- Docker Desktop defaults to WSL 2 on install on compatible OS versions.
- Docker Desktop detects missing Linux kernel and adds a pointer to the Microsoft documentation to download the kernel.

**File sharing**
- Kubernetes: Persistent volumes created by claims are now stored in the virtual machine. Fixes [for-win/issues/5665](https://github.com/docker/for-win/issues/5665).
- Docker Desktop ensures that host paths accessed by containers are within the shared folders list.
- Fixed a bug where opening a read-only file would fail with an `Operation not permitted error`. Fixes [docker/for-win#6016](https://github.com/docker/for-win/issues/6016) and [docker/for-win#6017](https://github.com/docker/for-win/issues/6017).
- Fixed path handling for `docker volume create -o type=none -o o=bind -o device=C:\Some\Windows\path`.
- Fixed a bug which prevented open files from being deleted. Fixes [docker/for-win#5565](https://github.com/docker/for-win/issues/5565).
- Docker Desktop now avoids locking files on the host which are open in containers.
- Docker Desktop generates `fsnotify.WRITE` events in Linux containers when files are changed on the host. [docker/for-win#5530](https://github.com/docker/for-win/issues/5530#issuecomment-585572414)
- Docker Desktop now displays hidden files on shared volumes. Fixes [docker/for-win#5808](https://github.com/docker/for-win/issues/5808).
- Fixed cache invalidation and event injection for shared volumes with long paths.
- Docker Desktop now handles case-insensitivity correctly during file creation.
- Docker Desktop represents valid directory junctions as directories (rather than symlinks) and handles cache invalidation and event injection properly. Fixes [docker/for-win#5582](https://github.com/docker/for-win/issues/5582).
- Fixed a race condition in `readlink` on shared volumes using "mfsymlinks". Fixes [docker/for-win#5793](https://github.com/docker/for-win/issues/5793)
- Fixed a bug where files did not change in shared volumes when using `volumes_from` in docker-compose.yml. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530).

**Other fixes**
- Reduced the size of the Docker Desktop installer from 960 MB to 400 MB.
- Added an option to delete container and image data from the **Troubleshoot** screen.
- Docker Desktop now reads the Hyper-V VM disk max size on startup and uses it as the value to display in the Settings.
- Fixed the Hyper-V used disk image size being reported incorrectly.
- Fixed the Hyper-V VM disk size increase. Fixes [docker/for-win#5881](https://github.com/docker/for-win/issues/5881).
- Fixed container time drift when system hibernates. Fixes [docker/for-win#4526](https://github.com/docker/for-win/issues/4526).
- Fixed a bug where the Docker Desktop UI could be started without the engine. Fixes [docker/for-win#5376](https://github.com/docker/for-win/issues/5376).
- Docker Desktop now uses the least possible privilege for querying the `Server service`. Fixes [docker/for-win#5150](https://github.com/docker/for-win/issues/5150).
- Fixed a bug where diagnostics upload could fail silently.
- Capturing diagnostics is now faster and easier.
- Fixed an issue where a container port could not be exposed on a specific host IP. See [docker/for-win#5546](https://github.com/docker/for-mac/issues/5546).
- Removed port probing from dashboard, just unconditionally showing links to ports that should be available. Fixes [docker/for-win#5903](https://github.com/docker/for-win/issues/5903).

### Known issues

- Loopback and unspecified IPv6 addresses (`::` and `::1`) within a container do not currently work. Some web servers and other programs may be using these addresses in their configuration files.

## Docker Desktop Community 2.2.2.0
2020-03-02



This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installing Docker Desktop.

### Upgrades

- [Kubernetes 1.16.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.16.5)
- [Go 1.13.8](https://golang.org/doc/devel/release.html#go1.13)

### New

- Windows 10 Home users can now use Docker Desktop through the experimental WSL 2 support. This requires Windows Insider Preview Build 19018 or later.
- Docker Desktop now allows sharing individual folders, rather than whole drives, giving more control to users over what is being shared.

### Bug fixes and minor changes

- Added a prerequisite check in the installer for the `LanmanServer` service. Fixes [docker/for-win#5150](https://github.com/docker/for-win/issues/5150).
- DockerNAT has been removed from Docker Desktop as using an IP address to communicate from the host to a container is not a supported feature. To communicate from a container to the host, you must use the special DNS name `host.docker.internal`. We also recommend using ports to communicate from the host to a container. For more information, see [Networking](/manuals/desktop/features/networking.md).
- Ceph support has been removed from Docker Desktop to save disk space.
- Fixed an issue that caused the Windows log file archive to grow indefinitely. Fixes [docker/for-win#5113](https://github.com/docker/for-win/issues/5113).

## Docker Desktop Community 2.2.1.0
2020-02-12



### Upgrades

- [Docker Compose 1.25.4](https://github.com/docker/compose/releases/tag/1.25.4)
- [Go 1.12.16](https://golang.org/doc/devel/release.html#go1.12)

### Bug fixes and minor changes

- Fixed an issue that prevented users from creating files with special characters in the filenames within a shared volume. Fixes [docker/for-win#5520](https://github.com/docker/for-win/issues/5520).
- Fixed handling of shared volumes with relative paths in `docker-compose.yml`. Fixes [docker/for-win#5516](https://github.com/docker/for-win/issues/5516).
- Fixed handling of shared volumes where the path case (uppercase / lowercase) did not exactly match the host. Fixes [docker/for-win#5516](https://github.com/docker/for-win/issues/5516).
- Fixed an issue where changing a file in the Windows file system did not update the file within the container. Fixes [docker/for-win#5530](https://github.com/docker/for-win/issues/5530), [docker/for-win#5550](https://github.com/docker/for-win/issues/5550), and [docker/for-win#5318](https://github.com/docker/for-win/issues/5318).
- Fixed an issue that prevented users from sharing drives and sometimes incorrectly prompted users to enter file system credentials. Fixes [docker/for-win#5567](https://github.com/docker/for-win/issues/5567).
- Fixed an issue which prevented users from mounting nested volumes. Fixes [docker/for-win#5540](https://github.com/docker/for-win/issues/5540).
- Fixed a file synchronization issue on bind mounts. Fixes [docker/for-win#5533](https://github.com/docker/for-win/issues/5533).
- Fixed an issue where timestamps were reset to zero on files within shared volumes. Fixes [docker/for-win#5528](https://github.com/docker/for-win/issues/5528) and [docker/for-win#5543](https://github.com/docker/for-win/issues/5543).
- Fixed a bug which caused Docker Desktop to fail when sharing file paths longer than 260 characters. Fixes [docker/for-win#5572](https://github.com/docker/for-win/issues/5572).
- Fixed an issue where some users were unable to start a container if there is a symlink in a shared volume. Fixes [docker/for-win#5582](https://github.com/docker/for-win/issues/5582).
- Fixed a bug where users were unable to modify the **Manual proxy configuration** settings through the Docker Desktop UI. Fixes [docker/for-win#5606](https://github.com/docker/for-win/issues/5606) and [docker/for-win#5548](https://github.com/docker/for-win/issues/5548).
- Fixed an issue where the Docker Desktop UI failed to start if the `no_proxy` environment variable has an entry that starts with a dot (.). Fixes [docker/for-win/5551](https://github.com/docker/for-win/issues/5551).
- Fixed a bug that did not allow users to access the Docker Desktop UI on machines with a policy preventing access to the Windows registry. Fixes [docker/for-win#5536](https://github.com/docker/for-win/issues/5536).
- Fixed an issue where disabling the WSL2 integration and re-enabling it later resulted in broken symlinks. Fixes [docker/for-win#5613](https://github.com/docker/for-win/issues/5613).
- Fixed a race condition when starting the WSL engine which caused Docker Desktop to incorrectly report that the containers have exited. Fixes [docker/for-win#5607](https://github.com/docker/for-win/issues/5607).
- Fixed an issue where editing code inside a container resulted in an error. Fixes [docker/for-win#5528](https://github.com/docker/for-win/issues/5528).
- Fixed a bug where running the command `DockerCli.exe -SharedDrives` failed to display a list of drives that are shared. Fixes [docker/for-win#5625](https://github.com/docker/for-win/issues/5625).

### Known issues

- DockerNAT has been removed from Docker Desktop 2.2.0.0 as using an IP address to communicate from the host to a container is not a supported feature. To communicate from a container to the host, you must use the special DNS name `host.docker.internal`. We also recommend using ports to communicate from the host to a container. For more information, see [Networking](/manuals/desktop/features/networking.md).

  However, if your current setup relies on IP addresses for communication, you can use a temporary workaround to reinstate DockerNAT. To do this, open
`C:\Program Files\Docker\Docker\resources\MobyLinux.ps1` and add `$SwitchName = "DockerNAT"` between line 175 and 176. Note that the temporary workaround to reinstate DockerNAT may be removed from future releases.
- Directory junctions in shared volumes pointing outside the shared volume do not work.
- It is currently not possible to rename open files within shared volumes.
- In some cases, Docker containers do not synchronize time with the host when the host machine is put to sleep.
- It is not possible to use `localhost` in the proxy settings. You can instead use `host.docker.internal` to work around this issue.

## Docker Desktop Community 2.1.7.0
2019-12-11



> [!NOTE]
>
> Docker Desktop Edge 2.1.7.0 is the release candidate for the upcoming major Stable release. Please help us test this version before the wider release and report any issues in the [docker/for-win](https://github.com/docker/for-win/issues) GitHub repository.

### Upgrades

- [Docker Compose 1.25.1-rc1](https://github.com/docker/compose/releases/tag/1.25.1-rc1)

### New

- Added the **WSL Integration** option in **Settings** > **Resources** to select WSL 2 distributions. This option will be visible only after enabling WSL 2 on your machine.
- File sharing: The new gRPC FUSE system is no longer experimental and is enabled by default even when experimental features are turned off.

### Bug fixes and minor changes

- The Docker Desktop Dashboard now displays port information inline with the container status.
- Fixed an issue which caused the 'back' button on the Dashboard UI to behave inconsistently when repeatedly switching between container details and the Settings window.
- Various minor improvements to the Dashboard UI.
- Fixed a bug that caused a rare crash when uninstalling Docker Desktop.
- Fixed an issue when overwriting existing files with the WSL 2 CLI bundle, such as kubectl.
- Fixed an issue where WSL 2 failed to start when the distribution directory is compressed or encrypted. Fixes [docker/for-win#5256](https://github.com/docker/for-win/issues/5256).
- Fixed an issue that caused Docker Desktop to fail on startup when there is an incomplete Kubernetes config file.
- Fixed various stability issues.

### Known issues

- The Dashboard stops updating when you switch the container mode between Linux and Windows. To work around this issue, close and reopen the Dashboard.
- The new gRPC FUSE file sharing implementation does not support connecting to new drives after Docker Desktop starts (for example, a USB drive). If you would like to share the new drive in Docker Desktop, you must quit Docker Desktop and then start the application to refresh the list of drives in Settings.

## Docker Desktop Community 2.1.6.1
2019-11-20



### Bug fixes and minor changes

- Fixed an issue that prevented Kubernetes to start with WSL 2 on machines with multiple CPU cores.
- Fixed a rare issue that caused to Docker Desktop to crash with the error `Unable to stop Hyper-V VM: Cannot validate argument on parameter 'SwitchName'. The argument is null or empty.`

### Known issue

Windows Insider Preview Slow Ring users running OS builds older than 19025 cannot run WSL 2 following upgrade to Docker Desktop Edge 2.1.6.1. WSL 2 requires Windows 10 Insider Preview build 19018 or greater.

### Docker Desktop Community 2.1.6.0
2019-11-18



### Upgrades

- [Docker 19.03.5](https://github.com/docker/docker-ce/releases/tag/v19.03.5)
- [Go 1.12.13](https://golang.org/doc/devel/release.html#go1.12)

### New

Added the ability to start and stop Compose-based applications and view combined logs in the Docker Desktop **Dashboard** UI.

### Bug fixes and minor changes

- Docker Desktop now automatically restarts after an update.
- Fixed an issue where Docker Desktop auto-start was not being disabled properly on some machines.
- Fixed a container start error when a container has more than one port with an arbitrary or not-yet-configured external port number. For example, `docker run -p 80 -p 443 nginx`). Fixes [docker/for-win#4935](https://github.com/docker/for-win/issues/4935) and [docker/compose#6998](https://github.com/docker/compose/issues/6998).
- Fixed an issue which caused Docker Desktop to crash when resetting to factory defaults while running Windows containers.
- Fixed multiple issues related to Fast Startup.
- Injected Docker CLI, CLI plugins, Docker Compose, Notary, and kubectl into WSL distributions when Docker Desktop WSL integration is enabled.
- Fixed an issue where bind mounts created with Docker Compose from a WSL distribution were incorrectly translated. Fixes [docker/for-win#5084](https://github.com/docker/for-win/issues/5084).
- Docker Desktop now supports inotify events on shared filesystems for Windows file sharing.
- Fixed a cache invalidation bug when a file in a shared volume is renamed on the host for Windows file sharing.
- Fixed a handle leak when calling `Mknod` on a shared volume for Windows file sharing.
- To make VM startup more reliable, Docker Desktop now avoids adding a Hyper-V NIC to the Windows VM when using Hypervisor sockets for Windows file sharing (rather than Samba).

### Known issue

Windows Insider Preview Slow Ring users running OS builds older than 19025 cannot run WSL 2 following upgrade to Docker Desktop Edge 2.1.6.0. WSL 2 requires Windows 10 Insider Preview build 19018 or greater.

## Docker Desktop Community 2.1.5.0
2019-11-04



This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installation.

### Upgrades

- [Kubernetes 1.15.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.15.5)
- [Docker Compose 1.25.0-rc4](https://github.com/docker/compose/releases/tag/1.25.0-rc4)
- Linux kernel 4.19.76

### New

- **Docker Desktop Dashboard:** The new Docker Desktop **Dashboard** provides a user-friendly interface which enables you to interact with containers and applications, and manage the lifecycle of your applications directly from the UI. In addition, it allows you to access the logs, view container details, and monitor resource utilization to explore the container behavior.

  To access the Dashboard UI, select the Docker menu from the system tray and then click **Dashboard**.

- **WSL 2 backend:** The new Docker Desktop WSL 2 backend replaces the Docker Desktop WSL 2 Tech Preview. The WSL 2 backend architecture introduces support for Kubernetes, provides an updated Docker daemon, offers VPN-friendly networking, and additional features. For more information, see [Docker Desktop WSL 2 backend](../features/wsl/index.md).

- **New file sharing implementation:** Docker Desktop introduces a new file sharing implementation which uses gRPC, FUSE, and Hypervisor sockets instead of Samba, CIFS, and Hyper-V networking. The new implementation  offers improved I/O performance. Additionally, when using the new file system:

  - Users don't have to expose the Samba port, and therefore do not experience issues related to IT firewall or the drive-sharing policy.
  - There is no need to provide user credentials to Docker Desktop. File access rights are automatically enforced when accessing mounted folders through containers.

  > To switch back to the Samba file system:
  >
  > From the Docker menu, select **Settings** > **Command line**, and then clear the **Enable experimental features** check box. Alternatively, install a Docker Desktop Stable release.

### Known issues

- When you start a Docker Compose application and then start a Docker App which has the same name as the Compose application, Docker Desktop displays only one application on the Dashboard. However, when you expand the application, containers that belong to both applications are displayed on the Dashboard.

- When you deploy a Docker App with multiple containers on Kubernetes, Docker Desktop displays each Pod as an application on the Dashboard.

## Docker Desktop Community 2.1.4.0
2019-10-15



### Upgrades

- [Docker 19.03.3](https://github.com/docker/docker-ce/releases/tag/v19.03.3)
- [Kubernetes 1.15.4](https://github.com/kubernetes/kubernetes/releases/tag/v1.15.4)
- [Go 1.12.10](https://github.com/golang/go/issues?q=milestone%3AGo1.12.10+label%3ACherryPickApproved) for [CVE-2019-16276](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16276)
- [Kitematic 0.17.9](https://github.com/docker/kitematic/releases/tag/v0.17.9)

### Bug fixes and minor changes

- Improved the navigation in **Settings** and **Troubleshoot** UI.
- Fixed a bug that prevented users from accessing WSL 2 Tech Preview. Fixes [docker/for-win#4734](https://github.com/docker/for-win/issues/4734).
- Docker Machine is no longer included in the Docker Desktop installer. You can download it separately from the [Docker Machine releases](https://github.com/docker/machine/releases) page.

## Docker Desktop Community 2.1.3.0
2019-09-16



### Bug fixes and minor changes

- Added a loading overlay to the **Settings** and **Troubleshoot** windows to prevent editing conflicts.
- Deactivated the **Reset Kubernetes** button when Kubernetes is not activated.

## Docker Desktop Community 2.1.2.0
2019-09-09



#### Upgrades

- [Docker 19.03.2](https://github.com/docker/docker-ce/releases/tag/v19.03.2)
- [Kubernetes 1.14.6](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.6)
- [Go 1.12.9](https://github.com/golang/go/issues?q=milestone%3AGo1.12.9+label%3ACherryPickApproved)
- [Qemu 4.0.1](https://github.com/docker/binfmt)
- [Docker Machine 0.16.2](https://github.com/docker/machine/releases/tag/v0.16.2)
- [Kitematic 0.17.8](https://github.com/docker/kitematic/releases/tag/v0.17.8)

#### Bug fixes and minor changes

- Reduced the Virtual Machine (VM) startup time.
- Added support for `Expect: 100-continue` headers in the Docker API proxy. Some HTTP clients such as `curl` send this header when the payload is large, for example, when creating containers. Fixes [moby/moby#39693](https://github.com/moby/moby/issues/39693).

## Docker Desktop Community 2.1.1.0
2019-08-12



#### Upgrades

- Linux Kernel 4.14.131

#### New

- [Docker Desktop WSL 2 Tech Preview](../features/wsl/index.md)

#### Bug fixes and minor changes

- Fixed a PowerShell script signing issue that caused `AuthorizationManager check failed` errors on machines with strict group policies on PowerShell script signing. [docker/for-win#4376](https://github.com/docker/for-win/issues/4376)
- Fixed an issue where attempts to upgrade Docker Desktop to version 2.1.0.0 sometimes failed with the error value cannot be null. [docker/for-win#3375](https://github.com/docker/for-win/issues/3375), [docker/for-win#4381](https://github.com/docker/for-win/issues/4381), [docker/for-win#4343](https://github.com/docker/for-win/issues/4343), [docker/for-win#4359](https://github.com/docker/for-win/issues/4359)
- Fixed an issue to ensure Docker Desktop Community installer does not prompt for UAC when UAC is disabled.
- Improved the error messages displayed during VM lifecycle operations. [docker/for-win#4348](https://github.com/docker/for-win/issues/4348)
- Docker Desktop now supports a configurable user timeout for VMs on slower machines. [docker/for-win#4393](https://github.com/docker/for-win/issues/4393)
- Enabled Windows features such as Hyper-V and Containers during installation, thereby reducing the need for another restart after installation.

## Docker Desktop Community 2.1.0.0
2019-07-30



This release contains Kubernetes security improvements. Note that your local Kubernetes PKI and cluster will be reset after installation.

#### Upgrades

 - [Docker 19.03.1](https://github.com/docker/docker-ce/releases/tag/v19.03.1)
 - [Docker Compose 1.24.1](https://github.com/docker/compose/releases/tag/1.24.1)
 - [Alpine 3.10](https://alpinelinux.org/posts/Alpine-3.10.0-released.html)
 - Linux Kernel 4.9.184
 - [Docker Credential Helpers 0.6.3](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.3)

#### New

 - Introduced a new user interface for the Docker Desktop **Settings** menu.
 - The **Restart** and **Reset** options are now available on the **Troubleshoot** menu.

#### Bug fixes and minor changes

 - Changed the host's kubernetes context to ensure `docker run -v .kube:kube ... kubectl` works.
 - Restricted the `cluster-admin` role on local Kubernetes cluster to `kube-system` namespace.
 - Fixed Kubernetes installation with VPNkit subnet.
 - Fixed an issue where Docker Desktop restarts when a user logs out of Windows and logs back in, which results in retaining the
   exported ports on containers.
 - Reduced the VM startup time. `swap` is not created every time a virtual machine boots.
 - Fixed a bug which caused Docker Desktop to crash when a user cancels switching the version using Windows User Account Control (UAC)    settings.
 - Fixed a bug where the process output was not redirected to stdout when gathering diagnostics on Windows, which sometimes resulted in    a crash.


## Docker Community Edition 2.0.5.0 2019-06-12



This is the Edge channel, which gives you early access to our newest features. Be aware that some of them may be experimental, and some of them may not ever reach the Stable release.

This release contains a Kubernetes upgrade. Note that your local Kubernetes cluster will be reset after installation.

* Upgrades
  - [Docker 19.03.0-rc2](https://github.com/docker/docker-ce/releases/tag/v19.03.0-rc2)
  - [Kubernetes 1.14.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.14.3)
  - [Compose on Kubernetes 0.4.23](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.23)
  - [linuxkit v0.7](https://github.com/linuxkit/linuxkit/releases/tag/v0.7)
  - [Qemu 4.0.0](https://github.com/docker/binfmt) for cross compiling for ARM

* New
  - Docker Desktop includes the `buildx` plugin (currently experimental).
  - Selecting the `Experimental features` checkbox on the Docker Desktop settings Daemon page enables experimental features in the Docker daemon and the Docker CLI.
  - Docker Desktop now checks for stored credentials at startup before attempting to mount any shared drives. This prompts users to reenter the credentials if they are invalid.

* Bug fixes and minor changes
  - Fixed race condition where Kubernetes sometimes fails to start after the app is restarted.
  - The system tray icon now opens the Docker Desktop menu with left or right mouse button.
  - When displaying the crash report window, Docker Desktop does not send a bugsnag crash report unless the user needs the report to upload diagnostics.
  - Docker Desktop has removed the ability to log in using email address as a username as the Docker command line does not support this.
  - For Linux containers on Windows (LCOW), at least one physical computer running Windows 10 Professional or Windows 10 Enterprise version 1809 or later is required.
  - The `Send usage statistics` checkbox is selected by default in Docker Desktop for Windows (Community). This option cannot be modified.
  - Docker Desktop has added a new dialog box during startup which allows users to retry mounting a shared drive or remove it from the shared drives list after a failed attempt.


* Known issues
  - Windows containers networking does not work properly on Windows 1903.

## Docker Community Edition 2.0.4.1 2019-05-07



* Bug fixes and minor changes
  - Upgrade QEMU from 2.8.0 to 3.1.0 to fix an emulation issue when building and running Java applications on Arm64 devices.

## Docker Community Edition 2.0.4.0 2019-04-30



* Upgrades
  - [Docker 19.03.0-beta3](https://github.com/docker/docker-ce/releases/tag/v19.03.0-beta3)
  - [Docker Compose 1.24.0](https://github.com/docker/compose/releases/tag/1.24.0)
  - [Compose on Kubernetes 0.4.22](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.22)
  - [Kubernetes 1.14.1](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.14.md#changelog-since-v1141)

* New

  - App: Docker CLI plugin to configure, share, and install applications

    - Extend Compose files with metadata and parameters
    - Reuse the same application across multiple environments (Development/QA/Staging/Production)
    - Multi-orchestrator installation (Swarm or Kubernetes)
    - Push/Pull/Promotion/Signing supported for application, with the same workflow as images
    - Fully CNAB compliant
    - Full support for Docker Contexts

  - Buildx (Tech Preview): Docker CLI plugin for extended build capabilities with BuildKit

    - Familiar UI from docker build
    - Full BuildKit capabilities with container driver
    - Multiple builder instance support
    - Multi-node builds for cross-platform images (out-of-the-box support for linux/arm/v7 and linux/arm64)
    - Concurrent building of compose files
    - High-level build constructs with `bake`

* Bug fixes and minor changes

  - Fix `Delete` of persistent volume claims
  - Truncate UDP DNS responses which are over 512 bytes in size

## Docker Community Edition 2.0.3.0 2019-03-05



* Upgrades
  - [Docker 18.09.3](https://github.com/docker/docker-ce/releases/tag/v18.09.3)

* Bug fixes and minor changes
  - Fixed docker not added to PATH after install in some cases
  - Fixed port 8080 that was used on localhost when starting Kubernetes.
  - Fixed "create issue" link in diagnostics windows.

## Docker Community Edition 2.0.2.1 2019-02-15



* Upgrades
  - [Docker 18.09.2](https://github.com/docker/docker-ce/releases/tag/v18.09.2), fixes [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736)

## Docker Community Edition 2.0.2.0 2019-02-06



* Upgrades
  - [Docker Compose 1.24.0-rc1](https://github.com/docker/compose/releases/tag/1.24.0-rc1)
  - [Docker Machine 0.16.1](https://github.com/docker/machine/releases/tag/v0.16.1)
  - [Compose on Kubernetes 0.4.18](https://github.com/docker/compose-on-kubernetes/releases/tag/v0.4.18)

* New
  - Rebranded UI

* Bug fixes and minor changes
  - Kubernetes: use default maximum number of pods for kubelet. [docker/for-mac#3453](https://github.com/docker/for-mac/issues/3453)

## Docker Community Edition 2.0.1.0 2019-01-11



* Upgrades
  - [Docker 18.09.1](https://github.com/docker/docker-ce/releases/tag/v18.09.1)
  - [Kubernetes 1.13.0](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.13.md#v1130)
  - [Kitematic 0.17.6](https://github.com/docker/kitematic/releases/tag/v0.17.6)
  - Golang 1.10.6, fixes CVEs: [CVE-2018-16875](https://www.cvedetails.com/cve/CVE-2018-16875), [CVE-2018-16873](https://www.cvedetails.com/cve/CVE-2018-16873) and [CVE-2018-16874](https://www.cvedetails.com/cve/CVE-2018-16874)

  WARNING: If you have an existing Kubernetes cluster created with Docker Desktop, this upgrade will reset the cluster. If you need to back up your Kubernetes cluster or persistent volumes you can use [Ark](https://github.com/heptio/ark).

* Bug fixes and minor changes
  - Fix service log collection in diagnostics
  - Gather /etc/hosts to help diagnostics
  - Add 18.09 missing daemon options
  - Rename Docker for Windows to Docker Desktop
  - Partially open services ports if possibles
  - Quit will not check if service is running anymore
  - Fix UI lock when changing kubernetes state

## Edge Releases of 2018

### Docker Community Edition 2.0.0.0-win82 2018-12-07

* Upgrades
  - [Docker compose 1.23.2](https://github.com/docker/compose/releases/tag/1.23.2)

* Bug fixes and minor changes
  - Compose: Fixed a bug where build context URLs would fail to build on Windows. Fixes [docker/for-win#2918](https://github.com/docker/for-win/issues/2918)

### Docker Community Edition 2.0.0.0-win77 2018-11-14

* Upgrades
  - [Docker 18.09.0](https://github.com/docker/docker-ce-packaging/releases/tag/v18.09.0)
  - [Docker compose 1.23.1](https://github.com/docker/compose/releases/tag/1.23.1)
  - [Docker Machine 0.16.0](https://github.com/docker/machine/releases/tag/v0.16.0)
  - [Kitematic 0.17.5](https://github.com/docker/kitematic/releases/tag/v0.17.5)

* Bug fixes and minor changes
  - Windows Containers: Fix group daemon option settings. Fixes [docker/for-win#2647](https://github.com/docker/for-win/issues/2647)
  - Windows Containers: Improve host.docker.internal ip resolution
  - Do not try to update samba share mounts when using Windows containers
  - Improved dns update too verbose in logs
  - VPNKit: Improved scalability of port forwarding.
  - VPNKit: Limit the size of the UDP NAT table. This ensures port forwarding and regular TCP traffic continue even when running very chatty UDP protocols.

### Docker Community Edition 2.0.0.0-beta1-win75 2018-09-14

* Upgrades
  - [Docker 18.09.0-ce-beta1](https://github.com/docker/docker-ce/releases/tag/v18.09.0-ce-beta1)
  - Linux Kernel 4.9.125

* New
  - New version scheme

* Deprecation
  - Removed support of AUFS

* Bug fixes and minor changes
  - LCOW does not anymore need --platform flag on multi-arch images
  - Better WCOW host.docker.internal resolution on host, don't rewrite it if not modified. From [docker/for-win#1976](https://github.com/docker/for-win/issues/1976)
  - Disk size can now be adjusted from 32GiB to drive space.
  - Fix dns update too verbose in logs
  - Fix panic in diagnose

### Docker Community Edition 18.06.1-ce-win74 2018-08-29

* Upgrades
  - [Docker 18.06.1-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.1-ce)

* Bug fixes and minor changes
  - Fix bug in virtual machine activity detection, preventing Docker Desktop from starting. Fixes [docker/for-win#2404](https://github.com/docker/for-win/issues/2404)
  - Fix bug in detection when Windows service is not running, and proposes to restart the service.
  - Fix local DNS failing to resolve inside containers. Fixes [docker/for-win#2301](https://github.com/docker/for-win/issues/2301), [docker/for-win#2304](https://github.com/docker/for-win/issues/2304)
  - Fix Kubernetes status display after reset to factory default
  - Fix bug where `host.docker.internal` is not resolved in some cases. Fixes [docker/for-win#2402](https://github.com/docker/for-win/issues/2402)
  - Use a 1MB vhdx blocksize instead of the default 32MB. See [docker/for-win#244](https://github.com/docker/for-win/issues/244). Also see [Microsoft Best Practices for running Linux on Hyper-V](https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/best-practices-for-running-linux-on-hyper-v)
  - Fix diagnostics in specific cases when Windows service is not started.
  - Changed samba default file permissions back to avoid issue with too-open rights. Fixes [docker/for-win#2170](https://github.com/docker/for-win/issues/2170)
  - On RS5 insider, fix wrong detection of missing feature "Containers" requiring to install feature + reboot.

### Docker Community Edition 18.06.0-ce-win71 2018-07-27

* Bug fixes and minor changes
  - Fix bug in automatic feature enabling if "Hyper-V" and "Containers" Windows features are not enabled already when starting Docker Desktop.

### Docker Community Edition 18.06.0-ce-win69 2018-07-25

* Upgrades
  - [Docker 18.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.06.0-ce)

### Docker Community Edition 18.06.0-ce-rc3-win68 2018-07-19

* Upgrades
  - [Docker 18.06.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v18.06.0-ce-rc3)
  - [Docker Machine 0.15.0](https://github.com/docker/machine/releases/tag/v0.15.0)
  - [Docker compose 1.22.0](https://github.com/docker/compose/releases/tag/1.22.0)

* New
  - New Kubernetes menu item allowing to switch Kubernetes context & connect to clusters other than the local one.

* Bug fixes and minor changes
  - AUFS storage driver is deprecated in Docker Desktop and AUFS support will be removed in the next major release. You can continue with AUFS in Docker Desktop 18.06.x, but you will need to reset disk image (in Settings > Reset menu) before updating to the next major update. You can check documentation to [save images](/reference/cli/docker/image/save/#examples) and [back up volumes](../../engine/storage/volumes.md#back-up-restore-or-migrate-data-volumes)
  - Fix startup issue with AUFS
  - Fix status bug which could prevent the kubernetes cluster from starting.
  - Fix bug which would cause VM logs to be written to RAM rather than disk in some cases, and the VM to hang.
  - Fix security issue with named pipe connection to docker service.

### Docker Community Edition 18.05.0-ce-win67 2018-06-07

* Upgrades
  - [LinuxKit v0.4](https://github.com/linuxkit/linuxkit/releases/tag/v0.4)
  - Linux Kernel 4.9.93 with CEPH, DRBD, RBD, MPLS_ROUTING and MPLS_IPTUNNEL enabled
  - [Kubernetes 1.10.3](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.10.md#v1103). If Kubernetes is enabled, the upgrade will be performed automatically when starting Docker for Windows.

* Bug fixes and minor changes
  - Fix VPNKit memory leak. Fixes [docker/for-win#2087](https://github.com/docker/for-win/issues/2087), [moby/vpnkit#371](https://github.com/moby/vpnkit/issues/371)
  - Fix potential loss of Kubernetes local cluster certificates on reboot.

### Docker Community Edition 18.05.0-ce-win66 2018-05-17

* Upgrades
  - [Docker 18.05.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.05.0-ce)
  - [Docker compose 1.21.2](https://github.com/docker/compose/releases/tag/1.21.2)

* New
  - Allow orchestrator selection from the UI in the "Kubernetes" pane, to allow "docker stack" commands to deploy to swarm clusters, even if Kubernetes is enabled in Docker for Windows.

* Bug fixes and minor changes
  - Fix restart issue when using Windows fast startup on latest 1709 Windows updates. Fixes [docker/for-win#1741](https://github.com/docker/for-win/issues/1741), [docker/for-win#1741](https://github.com/docker/for-win/issues/1741)
  - DNS name `host.docker.internal` can be used for host resolution from Windows containers.  Fixes [docker/for-win#1976](https://github.com/docker/for-win/issues/1976)
  - Fix broken link in diagnostics window.

### Docker Community Edition 18.05.0-ce-rc1-win63 2018-04-26

* Upgrades
  - [Docker 18.05.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v18.05.0-ce-rc1)
  - [Notary 0.6.1](https://github.com/docker/notary/releases/tag/v0.6.1)

* Bug fixes and minor changes
  - Fix startup issue due to incompatibility with other programs (like Razer Synapse 3). Fixes [docker/for-win#1723](https://github.com/docker/for-win/issues/1723)
  - Fix Kubernetes hostPath translation for PersistentVolumeClaim (PVC). Previously failing PVCs must be deleted and recreated. Fixes [docker/for-win#1758](https://github.com/docker/for-win/issues/1758)
  - Fix Kubernetes status when resetting to factory defaults.


### Docker Community Edition 18.04.0-ce-win62 2018-04-12

* Upgrades
  - [Docker 18.04.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.04.0-ce)
  - [Docker compose 1.21.0](https://github.com/docker/compose/releases/tag/1.21.0)

### Docker Community Edition 18.04.0-ce-rc2-win61 2018-04-09

* Upgrades
  - [Docker 18.04.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v18.04.0-ce-rc2)
  - [Kubernetes 1.9.6](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.9.md#v196). If Kubernetes is enabled, the upgrade will be performed automatically when starting Docker for Windows.

* New
  - Enable ceph & rbd modules in LinuxKit VM.

* Bug fixes and minor changes
  - Fix ApyProxy not starting properly when Docker for Windows is started with the `HOME` environment variable already defined (typically started from the command line). Fixes [docker/for-win#1880](https://github.com/docker/for-win/issues/1880)

### Docker Community Edition 18.03.0-ce-win58 2018-03-26

* Upgrades
  - [Docker 18.03.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce)
  - [Docker compose 1.20.1](https://github.com/docker/compose/releases/tag/1.20.1)

* Bug fixes and minor changes
  - Adding Docker for Windows icon on desktop is optional in the installer. Fixes [docker/for-win#246](https://github.com/docker/for-win/issues/246)

### Docker Community Edition 18.03.0-ce-rc4-win57 2018-03-15

* Upgrades
  - [Docker 18.03.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce-rc4)
  - AUFS 20180312

* Bug fixes and minor changes
  - Fix support for AUFS. Fixes [docker/for-win#1831](https://github.com/docker/for-win/issues/1831)

### Docker Community Edition 18.03.0-ce-rc3-win56 2018-03-13

* Upgrades
  - [Docker 18.03.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce-rc3)
  - [Docker Machine 0.14.0](https://github.com/docker/machine/releases/tag/v0.14.0)
  - [Docker compose 1.20.0-rc2](https://github.com/docker/compose/releases/tag/1.20.0-rc2)
  - [Notary 0.6.0](https://github.com/docker/notary/releases/tag/v0.6.0)
  - Linux Kernel 4.9.87

* Bug fixes and minor changes
  - Fix port Windows Containers port forwarding on windows 10 build 16299 post KB4074588. Fixes [docker/for-win#1707](https://github.com/docker/for-win/issues/1707), [docker/for-win#1737](https://github.com/docker/for-win/issues/1737)
  - Fix for the HTTP/S transparent proxy when using "localhost" names (for example "host.docker.internal", "docker.for.win.host.internal", "docker.for.win.localhost").
  - If Kubernetes is enabled, switch CLI orchestrator option back to "swarm" when switching to Windows Containers.
  - Fix daemon not starting properly when setting TLS-related options.

### Docker Community Edition 18.03.0-ce-rc1-win54 2018-02-27

* Upgrades
  - [Docker 18.03.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v18.03.0-ce-rc1)

* New
  - VM Swap size can be changed in settings.
  - Support NFS Volume sharing. Also works in Kubernetes. See [docker/for-win#1700](https://github.com/docker/for-win/issues/1700)
  - Allow users to activate Windows container during installation (avoid vm disk creation and vm boot when working only on win containers). See [docker/for-win#217](https://github.com/docker/for-win/issues/217).

* Bug fixes and minor changes
  - DNS name `host.docker.internal` should be used for host resolution from containers. Older aliases (still valid) are deprecated in favor of this one. (See https://tools.ietf.org/html/draft-west-let-localhost-be-localhost-06).
  - Fix Linuxkit start on Windows Insider. Fixes [docker/for-win#1458](https://github.com/docker/for-win/issues/1458), [docker/for-win#1514](https://github.com/docker/for-win/issues/1514), [docker/for-win#1640](https://github.com/docker/for-win/issues/1640)
  - Fix risk of privilege escalation. (https://www.tenable.com/sc-report-templates/microsoft-windows-unquoted-service-path-vulnerability)
  - All users present in the docker-users group are now able to use docker. Fixes [docker/for-win#1732](https://github.com/docker/for-win/issues/1732)
  - Kubernetes Load balanced services are no longer marked as `Pending`.
  - Fix hostPath mounts in Kubernetes.
  - Update Compose on Kubernetes to v0.3.0 rc4. Existing Kubernetes stacks will be removed during migration and need to be re-deployed on the cluster.


### Docker Community Edition 18.02.0-ce-win52 2018-02-08

* Upgrades
  - [Docker 18.02.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.02.0-ce)
  - [Docker compose 1.19.0](https://github.com/docker/compose/releases/tag/1.19.0)

### Docker Community Edition 18.02.0-ce-rc2-win51 2018-02-02

* Upgrades
  - [Docker 18.02.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v18.02.0-ce-rc2)
  - [Docker compose 1.19.0-rc2](https://github.com/docker/compose/releases/tag/1.19.0-rc2)
  - [Kubernetes 1.9.2](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.9.md#v192). If you have Kubernetes enabled, the upgrade will be performed automatically when starting Docker for Windows.

* New
  - Virtual machine disk size can be changed in settings. Fixes [docker/for-win#105](https://github.com/docker/for-win/issues/105)
  - New menu item to restart Docker.

* Bug fixes and minor changes
  - Migration of Docker Toolbox images is not proposed anymore in Docker For Windows installer (still possible to migrate Toolbox images manually).

### Docker Community Edition 18.02.0-ce-rc1-win50 2018-01-26

* Upgrades
  - [Docker 18.02.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v18.02.0-ce-rc1)

* New
  - Experimental Kubernetes Support. You can now run a single-node Kubernetes cluster from the "Kubernetes" Pane in Docker for Windows settings and use kubectl commands as well as docker commands. See [the Kubernetes section](../use-desktop/kubernetes.md).
  - LCOW containers can now be run next to Windows containers (on Windows RS3 build 16299 and later). Use `--platform=linux` in Windows container mode to run Linux Containers On Windows. Note that LCOW is still experimental, and requires daemon `experimental` option.

* Bug fixes and minor changes
  - Better cleanup for Windows containers and images on reset/uninstall. Fixes [docker/for-win#1580](https://github.com/docker/for-win/issues/1580), [docker/for-win#1544](https://github.com/docker/for-win/issues/1544), [docker/for-win#191](https://github.com/docker/for-win/issues/191)
  - Do not recreate Desktop icon on upgrade (effective on next upgrade). Fixes [docker/for-win#246](https://github.com/docker/for-win/issues/246), [docker/for-win#925](https://github.com/docker/for-win/issues/925), [docker/for-win#1551](https://github.com/docker/for-win/issues/1551)
  - Fix proxy for docker.for.win.localhost and docker.for.win.host.internal. Fixes [docker/for-win#1130](https://github.com/docker/for-win/issues/1130)

### Docker Community Edition 18.01.0-ce-win48 2018-01-19

* Upgrades
  - [Docker 18.01.0-ce](https://github.com/docker/docker-ce/releases/tag/v18.01.0-ce)
  - Linux Kernel 4.9.75

* Bug fixes and minor changes
  - Fix linuxKit port-forwarder sometimes not being able to start. Fixes [docker/for-win#1506](https://github.com/docker/for-win/issues/1506)
  - Fix certificate management when connecting to a private registry. Fixes [docker/for-win#1512](https://github.com/docker/for-win/issues/1512)
  - Fix Mount compatibility when mounting drives with `-v //c/...`, now mounted in /host_mnt/c in the LinuxKit VM. Fixes [docker/for-win#1509](https://github.com/docker/for-win/issues/1509), [docker/for-win#1516](https://github.com/docker/for-win/issues/1516), [docker/for-win#1497](https://github.com/docker/for-win/issues/1497)

### Docker Community Edition 17.12.0-ce-win45 2018-01-05

* Upgrades
  - [Docker 17.12.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce)

## Edge Releases of 2017
### Docker Community Edition 17.12.0-ce-rc4-win44 2017-12-21

* Upgrades
  - [Docker 17.12.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce-rc4)
  - [Docker compose 1.18.0](https://github.com/docker/compose/releases/tag/1.18.0)

* Bug fixes and minor changes
  - Fix DNS "search domain" and "domain name" settings. See [docker/for-win#1437](https://github.com/docker/for-win/issues/1437).
  - Fix VPNkit issue when username has spaces. See [docker/for-win#1429](https://github.com/docker/for-win/issues/1429).
  - Diagnostic improvements to get virtual machine logs before virtual machine shutdown.

### Docker Community Edition 17.12.0-ce-rc3-win43 2017-12-15

* Upgrades
  - [Docker 17.12.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce-rc3)

* Bug fixes and minor changes
  - Fix installer check for not supported Windows `CoreCountrySpecific` Edition.

### Docker Community Edition 17.12.0-ce-rc2-win41 2017-12-13

* Upgrades
  - [Docker 17.12.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.12.0-ce-rc2)
  - [Docker compose 1.18.0-rc2](https://github.com/docker/compose/releases/tag/1.18.0-rc2)


* Bug fixes and minor changes
  - Fix a class of startup failures where the database fails to start, see [docker/for-win#498](https://github.com/docker/for-win/issues/498)
  - Display various component versions in About box
  - Better removal of LCOW images and containers when uninstalling Docker
  - Links in update changelog open the default browser instead of IE (fixes [docker/for-win#1311](https://github.com/docker/for-win/issues/1311))

### Docker Community Edition 17.11.0-ce-win40 2017-11-22

* Upgrades
  - [Docker 17.11.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce)

### Docker Community Edition 17.11.0-ce-rc4-win39 2017-11-17

* Upgrades
  - [Docker 17.11.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce-rc4)
  - [Docker compose 1.17.1](https://github.com/docker/compose/releases/tag/1.17.1)
  - Linux Kernel 4.9.60

* Bug fixes and minor changes
  - Increased timeout for virtual machine boot startup to 2 minutes.

### Docker Community Edition 17.11.0-ce-rc3-win38 2017-11-09

* Upgrades
  - [Docker 17.11.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce-rc3)

* New
  - Use Microsoft localhost port forwarder for Windows and LCOW Containers when it is available (insider build RS4)

* Bug fixes and minor changes
  - Fix docker build exits successfully but fails to build image [moby/#35413](https://github.com/moby/moby/issues/35413)
  - Fix bug during Windows fast-startup process. Fixes [for-win/#953](https://github.com/docker/for-win/issues/953)
  - Fix uninstaller issue (in some specific cases dockerd process was not killed properly)
  - Do not propose toolbox migration popup after clicking "Try LCOW" on first startup
  - Fix `docker.for.win.localhost` not working in proxy settings. Fixes [for-win/#1130](https://github.com/docker/for-win/issues/1130)

### Docker Community Edition 17.11.0-ce-rc2-win37 2017-11-02

* Upgrades
  - [Docker 17.11.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.11.0-ce-rc2)
  - [Docker compose 1.17.0](https://github.com/docker/compose/releases/tag/1.17.0)
  - Linuxkit blueprint updated to [linuxkit/linuxkit#2633](https://github.com/linuxkit/linuxkit/pull/2633), fixes CVE-2017-15650

* New
  - Add localhost port forwarder for Windows and LCOW Containers (thanks @simonferquel)

* Bug fixes and minor changes
  - Fix centos:5 and centos:6 images not starting properly with LinuxKit virtual machine (fixes [docker/for-win#1245](https://github.com/docker/for-win/issues/1245)).

### Docker Community Edition 17.10.0-ce-win36 2017-10-24

* Upgrades
  - [Docker 17.10.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.10.0-ce)
  - [Docker Machine 0.13.0](https://github.com/docker/machine/releases/tag/v0.13.0)
  - [Docker compose 1.17.0-rc1](https://github.com/docker/compose/releases/tag/1.17.0-rc1)

* New
  - Virtual machine entirely built with Linuxkit
  - Experimental support for Microsoft Linux Containers On Windows, on Windows 10 RS3.


### Docker Community Edition 17.09.0-ce-win34 2017-10-06

* Bug fixes
  - Fix Docker For Windows unable to start in some cases: removed use of libgmp sometimes causing the VPNkit process to die.


### Docker Community Edition 17.09.0-ce-win31 2017-09-29

* Upgrades
  - [Docker 17.09.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce)

* Bug fixes and minor changes
  - VPNKit: security fix to reduce the risk of DNS cache poisoning attack (reported by Hannes Mehnert https://hannes.nqsb.io/)


### Docker Community Edition 17.09.0-ce-rc3-win30 2017-09-22

* Upgrades
  - [Docker 17.09.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce-rc3)

### Docker Community Edition 17.09.0-ce-rc2-win29 2017-09-19

* Upgrades
  - [Docker 17.09.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce-rc2)
  - Linux Kernel 4.9.49
  - AUFS 20170911

* Bug fixes and minor changes
  - Kernel: Enable TASK_XACCT and TASK_IO_ACCOUNTING
  - Rotate logs in the VM more often (docker/for-win#244)
  - VPNkit: do not block startup when ICMP permission is denied. (Fixes docker/for-win#1036, docker/for-win#1035, docker/for-win#1040)
  - Fix minor bug on update checks

### Docker Community Edition 17.09.0-ce-rc1-win28 2017-09-07

* Upgrades
  - [Docker 17.09.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.09.0-ce-rc1)
  - [Docker compose 1.16.1](https://github.com/docker/compose/releases/tag/1.16.1)
  - Linux Kernel 4.9.46

* New
  - Add `Skip this version` button in update window

* Bug fixes and minor changes
  - VPNKit: change protocol to support error messages reported back from the server
  - Reset to default stops all engines and removes settings including all daemon.json files
  - Better backend service checks (related to https://github.com/docker/for-win/issues/953)
  - Fix auto updates checkbox, no need to restart the application
  - Fix check for updates menu when auto updates was disable

### Docker Community Edition 17.07.0-win26 Release Notes (2017-09-01 17.07.0-win26)

* Upgrades
  - [Docker 17.07.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce)
  - [Docker compose 1.16.0](https://github.com/docker/compose/releases/tag/1.16.0)
  - [Docker Credential Helpers 0.6.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.6.0)

### Docker Community Edition 17.07.0-rc4-win25 Release Notes (2017-08-24 17.07.0-win25)

**Upgrades**

- [Docker 17.07.0-ce-rc4](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc4)
- [Docker compose 1.16.0-rc1](https://github.com/docker/compose/releases/tag/1.16.0-rc1)

**Bug fixes and minor changes**

- VPNKit: Fixed a bug which causes a socket to leak if the corresponding
TCP connection is idle for more than 5 minutes (related to
[docker/for-mac#1374](https://github.com/docker/for-mac/issues/1374))

> [!NOTE]
>
> The link above goes to Docker for Mac issues because a
Mac user reported this problem, which applied to both Mac and Windows and was fixed on both.

### Docker Community Edition 17.07.0-rc3-win23 Release Notes (2017-08-21 17.07.0-win23)

**Upgrades**

- [Docker 17.07.0-ce-rc3](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc3)

**New**

- Store Linux daemon configuration in `~\.docker\daemon.json` instead of settings file
- Store Windows daemon configuration in `C:\ProgramData\Docker\config\daemon.json` instead of settings file
- VPNKit: Added support for ping!
- VPNKit: Added `slirp/port-max-idle-timeout` to allow the timeout to be adjusted or even disabled
- VPNKit: Bridge mode is default everywhere now

**Bug fixes and minor changes**

- VPNKit: Improved the logging around the UNIX domain socket connections
- VPNKit: Automatically trim whitespace from `int` or `bool` database keys

### Docker Community Edition 17.07.0-ce-rc2-win22 Release Notes (2017-08-11 17.06.0-win22)

**Upgrades**

- [Docker 17.07.0-ce-rc2](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc2)
- Linux Kernel 4.9.41

### Docker Community Edition 17.07.0-ce-rc1-win21 Release Notes (2017-07-31 17.07.0-win21)

**Upgrades**

- [Docker 17.07.0-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.07.0-ce-rc1)
- [Docker compose 1.15.0](https://github.com/docker/compose/releases/tag/1.15.0)
- [Docker Machine 0.12.2](https://github.com/docker/machine/releases/tag/v0.12.2)
- Linux Kernel 4.9.38

**New**

- Windows Docker daemon is now started as service for better lifecycle management

**Bug fixes and minor changes**

- Keep Docker info in the same place as before in the registry, used by Visual Studio 2017 (Fixes [docker/for-win#939](https://github.com/docker/for-win/issues/939))
- Fix `config.json` not being released properly (Fixes [docker/for-win#867](https://github.com/docker/for-win/issues/867))
- Do not anymore move credentials in credential store at startup

### Docker Community Edition 17.06.1-ce-rc1-win20 Release Notes (2017-07-18 17.06.1-win20)

**Upgrades**

- [Docker 17.06.1-ce-rc1](https://github.com/docker/docker-ce/releases/tag/v17.06.1-ce-rc1)
- Linux Kernel 4.9.36
- AUFS 20170703

**Bug fixes and minor changes**

- Fix locked container id file (Fixes [docker/for-win#818](https://github.com/docker/for-win/issues/818))
- Avoid expanding variables in PATH env variable (Fixes [docker/for-win#859](https://github.com/docker/for-win/issues/859))

### Docker Community Edition 17.06.0-win17 Release Notes (2017-06-28 17.06.0-win17)

**Upgrades**

- [Docker 17.06.0-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce)

### Docker Community Edition 17.06.0-win16 Release Notes (2017-06-21 17.06.0-rc5-ce-win16)

**Upgrades**

- [Docker 17.06.0-ce-rc5](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc5)
 - [Docker compose 1.14.0](https://github.com/docker/compose/releases/tag/1.14.0)

### Docker Community Edition 17.06.0-win15 Release Notes (2017-06-16 17.06.0-rc4-ce-win15)

**Upgrades**

- [Docker 17.06.0-rc4-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc4)
- [Docker Credential Helpers 0.5.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.2)
- Linux Kernel 4.9.31


### Docker Community Edition 17.06.0-win14 Release Notes (2017-06-08 17.06.0-rc2-ce-win14)

**Upgrades**

  - [Docker 17.06.0-rc2-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc2)
  - [Docker Machine 0.12.0](https://github.com/docker/machine/releases/tag/v0.12.0)
  - [Docker compose 1.14.0-rc2](https://github.com/docker/compose/releases/tag/1.14.0-rc2)

**New**

- Added reset to defaults button in error report window
- Unified login between Docker CLI and Docker Hub, Docker Cloud.

**Bug fixes and minor changes**

- Fixed group access check for users logged in with Active Directory (fixes [docker/for-win#785](https://github.com/docker/for-win/issues/785))
- Check environment variables and add some warnings in logs if they can cause docker to fail

### Docker Community Edition 17.06.0-win13 Release Notes (2017-06-01 17.06.0-rc1-ce-win13)

**Upgrades**

- [Docker 17.06.0-rc1-ce](https://github.com/docker/docker-ce/releases/tag/v17.06.0-ce-rc1)
- [Docker Credential Helpers 0.5.1](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.1)
- Linux Kernel 4.9.30

**New**

- Sharing a drive can be done on demand, the first time a mount is requested
- Add an experimental DNS name for the host: `docker.for.win.localhost`
- Support for client (i.e. "login") certificates for authenticating
registry access (fixes [docker/for-win#569](https://github.com/docker/for-win/issues/569))

**Bug fixes and minor changes**

- Many processes that were running in admin mode are now running within the user identity
- Cloud federation command lines now opens in the user home directory
- Named pipes are now created with more constrained security descriptors to improve security
- Security fix: Users must be part of a specific group "docker-users" to run Docker for Windows

### Docker Community Edition 17.0.5-win11 Release Notes (2017-05-12 17.05.0-ce-win11)

**Upgrades**

- Security fix for CVE-2017-7308

### Docker Community Edition 17.0.5-win9 Release Notes (2017-05-09 17.05.0-ce-win9)

**Upgrades**

- [Docker 17.05.0-ce](https://github.com/docker/docker/releases/tag/v17.05.0-ce)
- [Docker Compose 1.13.0](https://github.com/docker/compose/releases/tag/1.13.0)
- [Docker Machine 1.11.0](https://github.com/docker/machine/releases/tag/v0.11.0)

**Security**

- Disable TCP exposition of the Daemon (tcp://localhost:2375), now an opt-in feature.

**Bug fixes and minor changes**

- Reset to default / uninstall and also reset docker cli settings and logout user from Docker Cloud and registries
- Detected a bitlocker policy preventing windows containers from working
- Fixed an issue on filesharing when explicitly disabled on VMswitch interface
- Fixed virtual machine not starting when machine had very long name
- Fixed a bug where Windows daemon.json file was not written (fixes [docker/for-win#670](https://github.com/docker/for-win/issues/670))

### Docker Community Edition 17.0.5-win8 Release Notes (2017-04-13 17.05.0-ce-rc1-win8)

**Upgrades**

- [Docker 17.05.0-ce-rc1](https://github.com/docker/docker/releases/tag/v17.05.0-ce-rc1)

### Docker Community Edition 17.0.4-win7 Release Notes (2017-04-06 17.04.0-ce-win7)

**New**

- New installer experience
- Experimental Windows Server 2016 support

**Upgrades**

- [Docker 17.04.0-ce](https://github.com/docker/docker/releases/tag/v17.04.0-ce)
- [Docker Compose 1.12.0](https://github.com/docker/compose/releases/tag/1.12.0)
- Linux Kernel 4.9.19

**Bug fixes and minor changes**

- Added patches to the kernel to fix VMBus crash

### Docker Community Edition 17.04.0-ce-win6 Release Notes (2017-04-03 17.04.0-ce-rc2-win6)

**Upgrades**

- [Docker 17.04.0-ce-rc2](https://github.com/docker/docker/releases/tag/v17.04.0-ce-rc2)
- [Docker Compose 1.12.0-rc2](https://github.com/docker/compose/releases/tag/1.12.0-rc2)
- Linux Kernel 4.9.18

**Bug fixes and minor changes**

- Named pipe client connection should not trigger dead locks on `docker run` with data in stdin anymore
- Buffered data should be treated correctly when docker client requests are upgraded to raw streams

### Docker Community Edition 17.03.1 Release Notes (2017-03-28 17.03.1-ce-rc1-win3)

**Upgrades**

- [Docker 17.03.1-ce-rc1](https://github.com/docker/docker/releases/tag/v17.03.1-ce-rc1)
- [Docker Credential Helpers 0.5.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.5.0)
- Linux Kernel 4.9.14

**Bug fixes and minor changes**

- VPNKit: capture up to 64KiB of NTP traffic for diagnostics, better handling of DNS

### Docker Community Edition 17.03.0 Release Notes (2017-03-06 17.03.0-ce-win1)

**New**

- Renamed to Docker Community Edition
- Integration with Docker Cloud: control remote Swarms from the local CLI and view your repositories. This feature is going to be rolled out to all users progressively

**Upgrades**

- [Docker 17.03.0-ce](https://github.com/docker/docker/releases/tag/v17.03.0-ce)
- [Docker Compose 1.11.2](https://github.com/docker/compose/releases/tag/1.11.2)
- [Docker Machine 0.10.0](https://github.com/docker/machine/releases/tag/v0.10.0)
- Linux Kernel 4.9.12

**Bug fixes and minor changes**

- VPNKit: fix unmarshalling of DNS packets containing pointers to pointers to labels
- Match Hyper-V Integration Services by ID, not name
- Don't consume 100% CPU when the service is stopped
- Log the diagnostic id when uploading
- Improved Firewall handling: stop listing the rules since it can take a lot of time
- Don't rollback to the previous engine when the desired engine fails to start

### Docker Community Edition 17.03.0 Release Notes (2017-02-22 17.03.0-ce-rc1-win1)

**New**

- Introduce Docker Community Edition
- Integration with Docker Cloud: control remote Swarms from the local CLI and view your repositories. This feature is being rolled out to all users progressively.

**Upgrades**

- Docker 17.03.0-ce-rc1
- Linux Kernel 4.9.11

**Bug fixes and minor changes**

- VPNKit: Fixed unmarshalling of DNS packets containing pointers to pointers to labels
- Match Hyper-V Integration Services by ID, not name
- Don't consume 100% CPU when the service is stopped
- Log the diagnostic ID when uploading
- Improved Firewall handling: stop listing the rules since it can take a lot of time
- Don't rollback to the previous engine when the desired engine fails to start

### Beta 41 Release Notes (2017-02-07 1.13.1-rc2-beta41)

**Upgrades**

- Docker 1.13.1-rc2
- [Docker Compose 1.11.0-rc1](https://github.com/docker/compose/releases/tag/1.11.0-rc1)
- Linux kernel 4.9.8

**Bug fixes and minor improvements**

- VPNKit: set the Recursion Available bit on DNS responses from the cache
- Don't use port 4222 inside the Linux VM

### Beta 40 Release Notes (2017-01-31 1.13.1-rc1-beta40)

**Upgrades**

- [Docker 1.13.1-rc1](https://github.com/docker/docker/releases/tag/v1.13.1-rc1)
- Linux kernel 4.9.6

**Bug fixes and minor improvements**

- Fix startup error of `ObjectNotFound` in Set-VMFirmware
- Add detailed logs when firewall is configured
- Add a link to the Experimental Features documentation
- Fixed the Copyright in About Dialog
- VPNKit: Avoid diagnostics to capture too much data
- VPNKit: fix a source of occasional packet loss (truncation) on the virtual ethernet link
- Fix negotiation of TimeSync protocol version (through kernel update)

### Beta 39 Release Notes (2017-01-26 1.13.0-beta39)

**Upgrades**

- Linux kernel 4.9.5

**New**

- DNS forwarder ignores responses from malfunctioning servers
- DNS forwarder send all queries in parallel, process results in order
- DNS forwarder includes servers with zones in general searches
- Significantly increased single-stream TCP throughput

**Bug fixes and minor improvements**

- Fix some timeout issues in port forwarding
- Fix for swap not being mounted ([docker/for-win#403](https://github.com/docker/for-win/issues/403))
- Fix aufs xattr delete issue ([docker/docker#30245](https://github.com/docker/docker/issues/30245))

### Beta 38 Release Notes (2017-01-20 1.13.0-beta38)

**Upgrades**

- [Docker 1.13.0](https://github.com/docker/docker/releases/tag/v1.13.0)
- [Docker Compose 1.10](https://github.com/docker/compose/releases/tag/1.10.0)
- [Docker Machine 0.9.0](https://github.com/docker/machine/releases/tag/v0.9.0)
- [Notary 0.4.3](https://github.com/docker/notary/releases/tag/v0.4.3)
- Linux kernel 4.9.4
- qcow-tool 0.7.2

**New**

- The storage location of the Linux volume can now be moved
- Reclaim disk size on reboot
- You can now edit filesharing paths
- Memory can be allocated with 256 MiB steps
- Proxy can now be completely disabled
- Support for arm, aarch64, ppc64le architectures using qemu
- Dedicated preference pane for advanced configuration of the docker daemon (edit daemon.json)
- Docker Experimental mode can be toggled
- Better support for Split DNS VPN configurations
- Use more DNS servers, respect order

**Bug fixes and minor changes**

- You cannot edit settings while Docker is restarting
- Support Copy/Paste in About box
- Auto update polling every 24h
- Kernel boots with vsyscall=emulate arg and CONFIG_LEGACY_VSYSCALL is set to NONE in Moby
- Fixed vsock deadlock under heavy write load
- If you opt-out of analytics, you're prompted for approval before a bug report is sent
- Fixed bug where search domain could be read as `DomainName`
- Dedicated preference pane for HTTP proxy settings.
- Dedicated preference pane for CPU and Memory computing resources.
- Privacy settings moved to the general preference pane.
- Fixed an issue where the preference pane disappeared when the welcome whale menu was closed.
- HyperKit: code cleanup and minor fixes
- Improvements to Logging and Diagnostics
- osxfs: switch to libev/kqueue to improve latency
- VPNKit: improvements to DNS handling
- VPNKit: Improved diagnostics
- VPNKit: Forwarded UDP datagrams should have correct source port numbers
- VPNKit: add a local cache of DNS responses
- VPNKit: If one request fails, allow other concurrent requests to succeed.
  For example this allows IPv4 servers to work even if IPv6 is broken.
- VPNKit: Fixed bug which could cause the connection tracking to
  underestimate the number of active connections

### Beta 37 Release Notes (2017-01-16 1.13.0-rc7-beta37)

**Upgrades**

- Docker 1.13.0-rc7
- Notary 0.4.3
- Linux kernel 4.9.3

### Beta 36 Release Notes (2017-01-12 1.13.0-rc6-beta36)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Upgrades**

- Docker 1.13.0-rc6
- Docker Compose 1.10-rc2
- Linux Kernel 4.9.2

**Bug fixes and minor improvements**

- Uninstall should be more reliable

### Beta 35 Release Notes (2017-01-06 1.13.0-rc5-beta35)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Upgrades**

- Docker 1.13.0-rc5
- Docker Compose 1.10-rc1

## Edge Releases of 2016
### Beta 34 Release Notes (2016-12-20 1.13.0-rc4-beta34)

**New**

- Basic UI for Daemon.json editing

**Upgrades**

- Docker 1.13.0-rc4
- Linux Kernel 4.8.15

**Bug fixes and minor changes**

- Improved Proxy UI
- Better diagnostics of Windows containers
- Default Experimental/Debug flags are now set on beta for Windows Containers
- Windows Containers Reset to default script improvements
- About Box is now Copy/Paste enabled

### Beta 33 Release Notes (2016-12-15 1.13.0-rc3-beta33)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**New**

- VHDX file containing images and non-host mounted volumes can be moved (using "advanced" tab in the UI)

**Upgrades**

- Linux Kernel 4.8.14

**Bug fixes and minor changes**

- Bugsnag reports should work again
- Fixed a memory leak related to logs and Windows Containers

### Beta 32.1 Release Notes (2016-12-09 1.13.0-rc3-beta32.1)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**Hotfixes**

- Fix Hyper-V Windows Feature detection

**New**

- Windows containers settings panel
- Windows containers: Restart from the settings panel
- Windows containers: Factory default
- Windows containers: Modify Daemon.json
- Windows containers: Proxy settings can be modified
- Support for arm, aarch64, ppc64le architectures using qemu

**Upgrades**

- Docker 1.13.0-rc3
- Docker Machine 0.9.0-rc2
- Linux Kernel 4.8.12

**Bug fixes and minor changes**

- Time drifts between Windows and Linux containers should disappear
- VPNKit: Improved diagnostics
- Improvements in drive sharing code
- Removed the legacy "Disable oplocks" trick for enabling Windows Containers on older insider previews

### Beta 32 Release Notes (2016-12-07 1.13.0-rc3-beta32)

> [!IMPORTANT]
>
> Plugins installed using the experimental "managed plugins" feature in Docker 1.12 must be removed/uninstalled before upgrading.

**New**

- Windows containers settings panel and options are working. In previous releases, settings were not implemented for
[Windows containers mode](../troubleshoot-and-support/faqs/windowsfaqs.md#how-do-i-switch-between-windows-and-linux-containers).
- Windows containers: Restart from the settings panel works
- Windows containers: Factory default
- Windows containers: `Daemon.json` can be modified
- Windows containers: Proxy settings can be modified
- Support for arm, aarch64, ppc64le architectures using qemu

**Upgrades**

- Docker 1.13.0-rc3
- Docker Machine 0.9.0-rc2
- Linux Kernel 4.8.12

**Bug fixes and minor changes**

- Time drifts between Windows and Linux containers should disappear
- VPNKit: Improved diagnostics
- Improvements in drive sharing code
- Removed the legacy "Disable oplocks" trick for enabling Windows Containers on older insider previews

### Beta 31 Release Notes (2016-12-01 1.13.0-rc2-beta31)

**New**

- HTTP/HTTPS proxy settings are used by the Windows Container daemon to pull images
- TRIM support for disk (shrinks virtual disk)
- Virtual machine's time synchronization is forced after the host wakes from sleep mode

**Upgrades**

- Docker 1.13.0-rc2
- Dockerd 1.13.0-rc2 (Windows Containers)
- Docker Compose 1.9.0
- Docker Machine 0.9.0-rc1
- Linux kernel 4.8.10

**Bug fixes and minor changes**

- VPNKit: don't permute resource records in responses
- VPNKit: reduced the amount of log spam
- Optimized boot process
- Diagnostics are improved and faster
- Log the error when the GUI fails to initialize
- Trend Micro Office Scan made the API proxy think no drive was shared, fixed
- Show a link to the virtualizaton documentation
- Flush logs to file more often
- Fixed the URL to the SMB/firewall documentation
- Properly remove duplicate firewall rules

### Beta 30 Release Notes (2016-11-10 1.12.3-beta30)

**Upgrades**

- Docker Compose 1.9.0-rc4
- Linux kernel 4.4.30

**Bug fixes and minor changes**

- Optimized disk on stop
- Always remove the disk on factory reset
- Improvements to Logging and Diagnostics

### Beta 29.3 Release Notes (2016-11-02 1.12.3-beta29.3)

**Upgrades**

- Docker Compose 1.9.0-rc2

### Beta 29.2 Release Notes (2016-10-27 1.12.2-beta29.2)

**Hotfixes**

- Upgrade to Docker 1.12.3

### Beta 29.1 Release Notes (2016-10-26 1.12.1-beta29.1)

**Hotfixes**

- Fixed missing `/dev/pty/ptmx`

### Beta 29 Release Notes (2016-10-25 1.12.3-rc1-beta29)

Windows Container support relies on the Windows 10 container feature, which is
**experimental** at this point.  Windows 10 Pro (1607, build number 14393)
requires update `KB3192366` (soon to be released through Windows Update) to fully
work. Some insider builds may not work.

**New**

- Restore the virtual machine's configuration when it was changed by the user
- Overlay2 is now the default storage driver. After a factory reset overlay2 is automatically used
- Detect firewall configuration that might block the file sharing
- Send more GUI usage statistics to help us improve the product

**Upgrades**

- Docker 1.12.3-rc1
- Linux Kernel 4.4.27

**Bug fixes and minor changes**

- Faster mount/unmount of shared drives
- Added a timeout to mounting/unmounting a shared drive
- Added the settings to the diagnostics
- Increase default ulimit for memlock (fixes https://github.com/docker/for-mac/issues/801)
- Make sure we don't use an older Nlog library from the GAC


### Beta 28 Release Notes (2016-10-13 1.12.2-rc3-beta28)

Windows Container support relies on the Windows 10 container feature, which is
**experimental** at this point.  Windows 10 Pro (1607, build number 14393)
requires update `KB3192366` (soon to be released through Windows Update) to fully
work. Some insider builds may not work.

**New**

- Path to HyperV disks in no longer hardcoded, making the Toolbox import work with non-standard path
- Verify that ALL HyperV features are enabled
- Make it clear why user cannot switch to Windows Containers with a tooltip in the systray
- Added Moby console to the logs
- Save the current engine with the other settings
- Notary version 0.4.2 installed


**Upgrades**

- Docker 1.12.2
- Kernel 4.4.24

**Bug fixes and minor changes**

- Fixed a password escaping regression
- Support writing large values to the database, especially for trusted CAs
- VPNKit is now restarted if it dies
- Make sure invalid "DockerNat" switches are not used
- Preserve the PowerShell stacktraces
- Write OS and Application versions at the top of each log file

### Beta 27 Release Notes (2016-09-28 1.12.2-rc1-beta27)

**New**

* Reworked the File Sharing dialog and underlying mechanism
* Pre-fill username
* Faster and more reliable feedback when the user/password is not valid
* Better support for domain users
* Error message in Logs when File Sharing failed for other reasons

**Upgrades**

* Docker 1.12.2-rc1
* Docker Machine 0.8.2
* Docker Compose 1.8.1
* Kernel 4.4.21
* AUFS 20160912

**Bug fixes and minor changes**

* Improve the switching between Linux and Windows containers: better errors, more reliable, deal with more edge cases
* Kill lingering dockerd that users might have still around because they played with Windows Containers before
* Don't recreate the virtual machine if only the DNS server is set
* The uninstaller now kills the service if it failed to stop it properly
* Restart VPNKit and DataKit when the processes die
* VPNKit: impose a connection limit to avoid exhausting file descriptors
* VPNKit: handle UDP datagrams larger than 2035 bytes
* VPNKit: reduce the number of file descriptors consumed by DNS
* Improve debug information

### Beta 26 Release Notes (2016-09-14 1.12.1-beta26)

**New**

* Basic support for Windows containers. On Windows 10 build >= 14372, a switch in the `systray` icon changes which daemon (Linux or Windows) the Docker CLI talks to

* To support trusted registry transparently, all trusted CAs (root or intermediate) on the Windows host are automatically copied to Moby

* `Reset Credentials` also unshares the shared drives

* Logs are now rotated every day

**Upgrades**

* Linux kernel 4.4.20
* AUFS 20160905

**Bug fixes and minor changes**

* We no longer send the same DNS settings twice to the daemon

* Fixed the lingering net adapters removal on Windows 10 Anniversary Update

* Uploading a diagnostic now shows a proper status message in the Settings

### Beta 25 Release (2016-09-07 1.12.1-beta25)


**New**

* Support multiple DNS servers

**Bug fixes and minor changes**

* Improved name servers discovery
* VPNKit supports search domains
* Set CIFS (common internet file system) version to 3.02

**Known issues**

* Only UTF-8 passwords are supported for host filesystem sharing

* Docker automatically disables lingering net adapters. The only way to remove them is manually using `devmgmt.msc`.

### Beta 24 Release (2016-08-23 1.12.1-beta24)

**Upgrades**

* Docker 1.12.1
* Docker Machine 0.8.1
* Linux kernel 4.4.19
* AUFS 20160822

**Bug fixes and minor changes**

* `slirp`: reduce the number of sockets used by UDP NAT, reduce the probability that NAT rules time out earlier than expected

**Known issues**

* Only UTF-8 passwords are supported for host filesystem sharing.

* Docker automatically disables lingering net adapters. The only way to remove them is manually using `devmgmt.msc`.

### Beta 23 Release (2016-08-16 1.12.1-rc1-beta23)

**New**

* Added `mfsymlinks` smb option to support symlinks on bind mounted folder
* Added `nobrl` smb option to support sqlite on bind mounted folders
* Detect outdated versions of Kitematic

**Upgrades**

* Docker 1.12.1-rc1
* Linux kernel 4.4.17
* AUFS 20160808

**Bug fixes and minor changes**

* Fixed password handling for host file system sharing
* Automatically disable lingering net adapters that prevent Docker from starting or using the network
* Automatically delete duplicated MobyLinuxVMs on a `reset to factory defaults`
* Docker stops asking to import from toolbox after an upgrade
* Docker can now import from toolbox just after Hyper-V is activated
* Fixed Moby Diagnostics and Update Kernel
* Added more debug information to the diagnostics
* Sending anonymous statistics shouldn't hang anymore when Mixpanel is not available
* Improved the Hyper-V detection and activation mechanism
* VPNKit is now compiled with OCaml 4.03 rather than 4.02.3
* Support newlines in release notes
* Improved error message when docker daemon is not responding
* The configuration database is now stored in-memory
* Preserve the stacktrace of PowerShell errors
* Display service stacktrace in error windows
* Moby: use default sysfs settings, transparent huge pages disabled
* Moby: cgroup mount to support systemd in containers

**Known issues**

* Only UTF-8 passwords are supported for host filesystem sharing
* Docker automatically disables lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Troubleshooting](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 22 Release (2016-08-11 1.12.0-beta22)

Unreleased. See Beta 23 for changes.

**Known issues**

* Docker automatically disables lingering net adapters. The only way to remove them is manually using `devmgmt.msc` as documented in [Troubleshooting](../troubleshoot-and-support/troubleshoot/known-issues.md).

### Beta 21 Release (2016-07-28 1.12.0-beta21)

**New**

* Docker for Windows is now available from two channels: **stable** and **beta**. New features and bug fixes go out first in auto-updates to users in the beta channel. Updates to the stable channel are much less frequent and happen in sync with major and minor releases of the Docker Engine. Only features that are well-tested and ready for production are added to the stable channel releases. For downloads of both and more information, see [Install Docker Desktop on Windows](../setup/install/windows-install.md).

* Removed the docker host name. Containers with exported ports are reachable via localhost.

* The UI shows whether the user is on beta or stable channel

**Upgrades**

* Docker 1.12.0 with experimental features
* Docker Machine 0.8.0
* Docker Compose 1.8.0

**Bug fixes and minor changes**

* Fixed networking issue when transmitting data to a container via an exposed port.
* Include the sources for qemu-img
* Fixed the migration from toolbox when the user has a space in its login
* Disable the migration from toolbox when hyperV is not yet activated
* More windows can be closed with ESC
* Added the channel to crash reports
* Fixed a path rewriting bug that happens on Windows insider build 14367
* Simplified the MobyLinux.ps1 script

**Known issues**

* Older Kitematic versions are not compatible with Docker for Windows. You need to manually delete the `C:\Program Files\Docker\Kitematic` folder before you click **Open Kitematic...** systray link.

### Beta 20 Release (2016-07-19 1.12.0-rc4-beta20)

**New**

* The UI option to disable port forwarding to `localhost` has been removed

**Bug fixes and minor changes**

* Fixed `docker.sock` permission issues
* Don't check for update when the settings panel opens
* Removed obsolete DNS workaround
* Use the secondary DNS server in more circumstances
* Limit the number of concurrent port forwards to avoid running out of resources
* Store the database as a "bare" git repo to avoid corruption problems

### Beta 19 Release (2016-07-14 1.12.0-rc4-beta19)

**New**

* Added an option to opt-out from sending usage statistics (only on the Edge channel for now)
* New error dialog box to upload crash reports

**Upgrades**

* Docker 1.12.0 RC4
* Docker Compose 1.8.0 RC2
* Docker Machine 0.8.0 RC2
* Linux kernel 4.4.15

**Bug fixes and minor changes**

* `com.docker.slirp`: included the DNS TCP fallback fix, required when UDP responses are truncated
* `docker build/events/logs/stats...` won't leak when interrupted with Ctrl-C
* Disable all buttons on Update Window when a version is downloading

### Beta 18.1 Release (2016-07-07 1.12.0-rc3-beta18.1)

> [!NOTE]
>
> Docker 1.12.0 RC3 release introduces a backward incompatible change from RC2. You can fix this by recreating or updating your containers.

**Hotfix**

* Fixed issue resulting in error "Hijack is incompatible with use of CloseNotifier", reverts previous fix for `Ctrl-C` during build.

**New**

* Forwarding the ports to localhost is now the default
* Added `http`/`https` proxy configuration to the settings
* The toolbox default machine can be imported on first launch
* Added UI when a crash report is collected and uploaded
* The check for update runs every 6 hours

**Upgrades**

* Docker 1.12.0 RC3

**Bug fixes and minor changes**

* The docker API proxy was failing to deal with 1.12 features (health check for, for example)
* When killing the virtual machine process, ignore when the process is already stopped
* When stopping the virtual machine, always stop the docker proxy
* Prevent the update windows from downloading the `.msi` into `C:\Program Files\Docker`
* All settings should be disabled when Docker is starting. (This regression was introduced in Beta 17)
* VPNKit: Improved scalability as number of network connections increases
* Improve the connection to the database
* Ignore when the shutdown service is not available

### Beta 18 Release (2016-07-06 1.12.0-rc3-beta18)

**New**

* Forwarding the ports to localhost is now the default
* Added `http`/`https` proxy configuration to the settings
* The toolbox default machine can be imported on first launch
* Added UI when a crash report is collected and uploaded
* The check for update runs every 6 hours

**Upgrades**

* Docker 1.12.0 RC3

**Bug fixes and minor changes**

* Interrupting a `docker build` with Ctrl-C actually stops the build
* The docker API proxy was failing to deal with 1.12 features (health check for, for example)
* When killing the VM process, ignore when the process is already stopped
* When stopping the VM, always stop the docker proxy
* Prevent the update windows from downloading the `.msi` into `C:\Program Files\Docker`
* All settings should be disabled when Docker is starting. (This regression was introduced in Beta 17)
* VPNKit: Improved scalability as number of network connections increases
* Improve the connection to the database
* Ignore when the shutdown service is not available

### Beta 17 Release (2016-06-29 1.12.0-rc2-beta17)

**Upgrades**

* Linux kernel 4.4.14, aufs 20160627

**Bug fixes and minor changes**

* Support users with spaces in their login
* Fix some cases where `dotnet restore` could hang
* Fixed `docker inspect` on an image
* Removed the console from Hyper-V manager
* Improved diagnostic for VPN connection and addedlogs for the service port openers
* Improve Moby's boot sequence to adapt to longer boot time when swarm services are running
* Forcefully turn off a virtual machine that won't shut down
* Clicking on a link from the changelog opens a browser
* Fix links to the documentation
* Fix the url to download Kitematic
* Renewed the signing certificates
* Fixed errors with the firewall and the network switch
* Fixed parsing errors in the PowerShell script

### Beta 16 Release (2016-06-17 1.12.0-rc2-beta16)

**Upgrades**

* Docker 1.12.0 RC2
* docker-compose 1.8.0 RC1
* docker-machine 0.8.0 RC1
* Alpine 3.4

**Bug fixes and minor changes**

* Fixes to the VPN mode
* Fixed the localhost port forwarding performance issue
* Auto-detect mounted/unmounted drive in the list of shares
    - Changed the name of the application from "DockerforWindows" to "Docker for Windows"
    - Avoid multiple update windows being displayed at the same time

### Beta 15 Release (2016-06-10 1.11.2-beta15)

**New**

* New experimental networking mode, exposing container ports on `localhost`
* New Settings menu to configure sysctl.conf
* New Settings menu to configure http proxies
* The VPN mode setting is removed (VPN mode is now the only supported mode)
* The vSwitch NAT configuration has been removed

**Upgrades**

* Docker 1.11.2
* Linux 4.4.12, AUFS 20160530

**Bug fixes and minor changes**

* Moved `Import from toolbox` option to the General Settings
* Increased the timeout to write to the configuration database
* Fixed an issue where sending anonymous stats to Mixpanel made the application stop
* Faster boot time
* All named pipes are now prefixed with the word `docker`
* Full version number is now displayed in the update window
* Default daemon config does not have debug enabled anymore
* More responsive Settings Panel, with new whales also :-)
* Improved logs and debug information

### Beta 14 Release(2016-06-02 1.11.1-beta14)

**New**

* Enabled configuration of the docker daemon (edit `config.json`)
* The VPN mode is enabled by default
* Removed DHCP for virtual machine network configuration
* User configurable NAT prefix and DNS server
* New feedback window to upload diagnostics dialog
* New status indicator in **Settings** window
* Virtual machine logs are uploaded with a crash report
* Animated welcome whale

**Bug fixes and minor changes**

* Support non-ASCII characters in passwords
* Fixed unshare a drive operation
* Fixed deserialized of exceptions sent from the service
* If the backend service is not running, the GUI now starts it
* The app no longer complains if the backend service is not running and the user just wants to shut down.


**Known issues**

* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed.

### Beta 13 Release (2016-05-25 1.11.1-beta13)

**New**

This Beta release includes some significant changes:

* Docker communication is over Hyper-V sockets instead of the network
* Experimental VPN mode, also known as `vpnkit`
* Initial support for `datakit` for configuration
* Redesigned Settings panel
* Docker can now be restarted

**Bug fixes and minor changes**

* Support Net adapters with a different name than "vEthernet (DockerNAT)"
* Sharing now has a better support for domain users
* Fixed Toolbox migration (was broken in Beta12)
* Enabling Hyper-V (was broken in Beta12)
* Fixed error message when invalid labels are passed to `docker run`
* Mixpanel no longer uses roaming App Data
* UI improvements
* Support was added for virtual machines with other IP addresses out of the `10.0.75.0/24` range
* Improved FAQ

**Known issues**

* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed.

### Beta 12 Release (2016-17-10 1.11.1-beta12)

**New**

* The application is now separated in two parts. A back-end service and a front-end GUI. The front-end GUI no longer asks for elevated access.

**Bug fixes and minor changes**

* Excluded the network drives from the shares list
* Removed the notification when closing the application
* Minor GUI improvements

**Known issues**

* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed.


### Beta 11b Release (2016-05-11 1.11.1-beta11b)

**Hotfixes**

* Fixed an issue with named pipe permissions that prevented Docker from starting

### Beta 11 Release (2016-05-10 1.11.1-beta11)

**New**

* The GUI now runs in non-elevated mode and connects to an elevated Windows service
* Allocate virtual machine memory by 256 MB increments, instead of 1 GB
* Show a meaningful error when the user has an empty password
* Improved [Troubleshooting](../troubleshoot-and-support/troubleshoot/index.md) page

**Upgrades**

* docker-compose 1.7.1 (see [changelog](https://github.com/docker/compose/releases/tag/1.7.1))
* Kernel 4.4.9

**Bug fixes and minor changes**

* Report the virtual machine's IP in `docker port`
* Handle passwords with spaces
* Show a clear error message when trying to install on Home editions
* Slower whale animation in the system tray
* Proxy is restarting itself when it crashes
* DHCP process handles exceptions gracefully
* Moby (Backend) fixes:
  - Fixed `vsock` half closed issue
  - Added NFS support
  - Hostname is now Moby, not Docker
  - Fixes to disk formatting scripts
  - Kernel upgrade to 4.4.9

**Known issues**

* Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [Troubleshooting](../troubleshoot-and-support/troubleshoot/known-issues.md) for more details.

* Logs for the windows service are not aggregated with logs from the GUI. This is expected to be fixed in future versions.


### Beta 10 Release (2016-05-03 1.11.0-beta10)

**New**

* Improved Settings panel, allows you to configure the virtual machine’s memory and CPUs
* Co-exists with multiple internal Hyper-V switches and improved DHCP handling
* Token validation is now done over HTTPS. This should fix issues with some firewalls and antivirus software.

**Upgrades**

* Docker 1.11.1

**Bug fixes and minor changes**

* Fixed Desktop shortcut name and updated icons
* Preparation to run the backend as service
* Improved logging and Mixpanel events
* Improved code quality
* Improved the build
* New icons

**Known issues**

*  Due to limitation in the Windows NAT implementation, co-existence with other NAT prefixes needs to be carefully managed. See [Troubleshooting](../troubleshoot-and-support/troubleshoot/index.md) for more details.


### Beta 9 Release (2016-04-26 1.11.0-beta9)

**New**

* Provide one-click dialog to enable Hyper-V
* Report clear underlying Hyper-V errors

**Bug fixes and minor changes**

* Better handling of some networking issues
* Fixed help menu and start menu getting started URLs
* Restored “Docker is Initializing” notification on first run
* Better error messages during authentication
* Improved logging on error conditions
* Improved build and tests

**Known issues**

* If multiple internal Hyper-V switches exist the Moby virtual machine
may not start correctly. We have identified the issue and
are working on a solution.

### Beta 8 Release (2016-04-20 1.11.0-beta8)

**New**

* Auto-update is installed silently, and relaunches the application when it completes
* Uninstaller can be found in Windows menu
* Kitematic can be downloaded from the Dashboard menu

**Bug fixes and minor changes**

* Better UI in the ShareDrive window
* The firewall alert dialog does not come up as often as previously
* Configured MobyLinux virtual machine with a fixed memory of 2GB
* User password is no longer stored on the host-side KVP
* Uninstall shortcut is available in registry

### Beta 7 Release (2016-04-12 1.11.0-beta7)

**New**

  - Multiple drives can be shared
  - New update window
  - Welcome whale

**Upgrades**

* docker 1.11.0-rc5
* docker-machine 0.7.0-rc3
* docker-compose 1.7.0-rc2

**Bug fixes and minor changes**

* Improved networking configuration and error detection: fixed DHCP renewal and rebind issues
* Allow DNS/DHCP processes to restart on bind error
* Less destructive migration from Docker Toolbox
* Improved documentation
* Better error handling: Moby restarts itself if start takes too long.
* Kill proxy and exit docker before a new version is installed
* The application cannot start twice now
* The proxy stops automatically when the GUI is not running
* Removed existing proxy firewall rules before starting Moby
* The application now collects more and better information on crashes and other issues
* Improved all dialogs and windows
* Added the version to installer's first screen
* Better reset to defaults
* New regression test framework
* The installation MSI is now timestamped
* The Hyper-V install mentions Docker Toolbox only if it is present
* Improved Bugsnag reports: fixed a dependency bug, and added a unique ID to each new report
* Improved the build
* Improved code quality

**Known issues**

- Settings are now serialized in JSON. This install loses the current settings.

- Docker needs to open ports on the firewall. Sometimes, the user sees a firewall alert dialog. The user should allow the ports to be opened.

- The application was upgraded to 64 bits. The installation path changed to `C:\Program Files\Docker\Docker`. Users might need to close any Powershell/Cmd windows that were already open before the update to get the new `PATH`. In some cases, users may need to log off and on again.

**Bug Fixes**

  - Fixed DHCP renewal and rebind
  - Only mention toolbox on Hyper-V install if it's present
  - The application does not start twice now
  - DNS/DHCP processes are allowed to restart on bind error now
  - Removed the window that opens quickly during bugsnag reports
  - Fixed OS reported by Bugsnag
  - Improved the build
  - Improved code quality

### Beta 6 Release (2016-04-05 1.11.0.1288)

**Enhancements**

- Docs are updated for Beta 6!
- Support roaming: DNS queries are forwarded to the host
- Improved startup times by running a DHCP server on the host
- New settings dialog design
- Support Windows paths with -v
- Updated Docker CLI and daemon to 1.11.0-rc3
- Updated docker-machine to 0.7.0-rc2
- Updated docker-compose to 1.7.0-rc1
- Now install docker-credential-wincred
- Allow non-root users in containers to create files on volume mounts
- Automatically install Hyper-V
- The application is now 64 bits
- Improved wording in all dialog boxes and error messages
- Removed exit confirmation
- Show clickable URL in the Install HyperV message box
- Dashboard link to Kitematic (as on Mac)
- Moby kernel updated to 4.4.6
- The registry key was changed to HKLM\SOFTWARE\Docker Inc.\Docker\1.0

**Known issues**

- Migration from Docker Toolbox can fail sometimes. If this happens, the workaround is to restart the application.

- Docker needs to open ports on the firewall, which can activate a firewall alert dialog. Users should allow the ports to be opened.

- The application was upgraded to 64 bits. The installation path changed to `C:\Program Files\Docker\Docker`. If users have PowerShell/Cmd windows already open before the update, they might need to close them to catch the new PATH. In some cases, users need to log off and on again.

**Bug Fixes**

- Kill virtual machines that cannot be shut down properly

- Improved the diagnostic information sent with bugsnag reports

- Settings window shows when the drive is shared or not
`C:` drive can be bind mounted with `//c` or `/c`. Used to be `//c/`

- Don't try to submit empty tokens

- Fixed the version shown in the About box

- Fixed a race condition on the logs

- Fixed a race condition on the settings

- Fixed broken links in the documentation

- Replaced `sha1` with actual version in the assemblies

- Don't start the unused agent process

### Beta 5 Release (2016-03-29 1.10.6)

**Enhancements**

* Remove debug console
* Open browser with hyper-v installation instructions
* Added CloudFront for downloads from Europe
* Capture qemu logs during toolbox upgrades
* Rename alpha distribution channel to beta

**Bug Fixes**

* Fix diagnose section in bugsnag report
* Fix msi version
* Don't truncate Toolbox link

> [!NOTE]
>
> Docker for Windows skipped from Beta 1 to Beta 5 at this point to synch up the version numbering with Docker for Mac, which went into beta cycles a little earlier.

### Beta 1 Release (2016-03-24 1.10.6)

**Enhancements**

- Display the third party licenses
- Display the license agreement
- The application refuses to start if Hyper-V is not enabled
- Rename `console` to `debug console`
- Remove `machine` from notification
- Open the feedback forum
- Use same MixPanel project for Windows and macOS
- Align MixPanel events with macOS
- Added a script to diagnose problems
- Submit diagnostic with bugsnag reports
- MixPanel heartbeat every hour

**Bug Fixes**

- Accept all versions of Enterprise 10, Pro 10 and Education 10 during installation (Eval, N, ...)
- Fix Linux kernel crashes with certain applications or somesuch
- Fix notifications that are not shown
- Animate the systray whale on reset
- Shorten the enrollment process timeout
- Properly unmount shares when the user un-selects the setting
- Don't install on unsupported builds

### Alpha 4 Release (2016-03-10 1.10.4.0)

- Faster Startup & Shutdown
- Use host DNS parameters
- Enrollment System
- Recreating manually removed vm
- More MixPanel Events
- Various Bug Fixes

### Alpha 3 Release (2016-03-03 1.10.2.14)

**File sharing**

  - Create network share automatically
  - Improve Credentials management
  - Support paths with c and C drive

**Crashes and Analytics**

  - Report crashes with Bugsnag
  - Send analytics through MixPanel

**GUI**

  - Improve layout of About and Settings dialog
  - Improve Updater
  - Link to *Help*
  - Link to *Send Feedback*

**General**

  - Bug fixes

### Alpha 2 Release (2016-02-26 1.10.2.12)

**Installer**

  - Enhancements
  - Auto-update
  - License agreement

**General**

  - Bug fixes

### Alpha 1 Release (2016-02-22 1.10.1.42-1)

**Hypervisor**

  - significant performance improvements

**Security**

  - retrieving credentials from user

**Filesystem**

  - hot-mounting host filesystem with credential

**General**

  - state management
  - stability, logging
  - bugfixes, eye candies

### Alpha 0 Release (2016-02-09 1.10.0.0-0)

**Hypervision**

  - Hyper-V-backed virtual machines
  - boots Moby in a few seconds
  - installs CLI in `PATH`
  - proxies Docker commands to Moby

**Filesystem**

  - mounts host filesystem to support `--volume`
  - Samba client with a hardcoded password
  - allows live reload

**Networking**

  - live debugging Node.js application


---

# Docker Desktop release notes

*Sección: Desktop*

<!-- vale off -->

This page contains information about the new features, improvements, known issues, and bug fixes in Docker Desktop releases.

Releases are gradually rolled out to ensure quality control. If the latest version is not yet available to you, allow some time — updates typically become available within a week of the release date.

Docker Desktop versions older than 6 months from the latest release are not available for download. Previous release notes are available in our [documentation repository](https://github.com/docker/docs/tree/main/content/manuals/desktop/previous-versions).

For more frequently asked questions, see the [FAQs](troubleshoot-and-support/faqs/releases.md).

## 4.91.0

{{< release-date date="2026-09-14" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.91.0" build_path="/239619/" >}}

### Updates

- [Docker Engine v29.8.0](https://docs.docker.com/engine/release-notes/29/#2980)
- [containerd v2.3.4](https://github.com/containerd/containerd/releases/tag/v2.3.4)
- [Docker Compose v5.5.1](https://github.com/docker/compose/releases/tag/v5.5.1)
- [Docker Agent v1.136.0](https://github.com/docker/docker-agent/releases/tag/v1.131.0)
- Docker Desktop Build `v0.38.0`
- [Docker Buildx v0.37.0](https://github.com/docker/buildx/releases/tag/v0.37.0)
- Docker Offload `v0.6.17`
- [Credential helpers v0.9.9](https://github.com/docker/docker-credential-helpers/releases/tag/v0.9.9)

### Bug fixes and enhancements

#### For all platforms 

- Fixed an issue where the **Last modified** column in the Volumes and container filesystem browsers displayed inaccurate timestamps like '57 years ago' instead of a blank when modification time was unavailable.
- Fixed Docker Desktop writing invalid export PATH syntax into csh/tcsh profiles when adding `~/.docker/bin` to PATH.
- Fixed an issue where Docker Scout CLI hints would persist after upgrading.
- Fixed a bug where a corrupt Docker network database, usually caused by an abrupt shutdown, prevented Docker Engine from starting and left a factory reset as the only recovery option.
- Fixed CLI plugin updates failing repeatedly when the plugin binary was locked by another process. The update is now retried automatically on the next start.
- Fixed Docker Desktop's interface getting stuck in an indefinite restart loop on machines with certain graphics driver issues, and added a message explaining when the interface can't be displayed due to a hardware compatibility problem.
- Improved startup experience in the new UI by showing a themed skeleton layout (header, sidebar, footer) immediately instead of a blank window while the app loads.
- Fixed Docker Desktop sometimes taking five extra minutes to report the engine as stopped when the virtual machine stopped unexpectedly.
- Fix Kubernetes (kubeadm) missing CNI loopback interface name.
- Fixed MCP profile tours getting stuck or rendering tooltips off-screen.
- Fixed a bug where changing the disk image location to a different volume could delete the existing disk image if the operation was interrupted before the copy started.
- Fixed Docker Compose rebuilding locally-built images on every Resource Saver wake. Fixes [docker/desktop-feedback#507](https://github.com/docker/desktop-feedback/issues/507).
- Fixed a regression where Hub image search and tag listing would break if the Docker Hub API response included unexpected or changed fields.
- Fixed an issue where the VM could be unexpectedly shut down when the idle timeout was set to 0.

#### For Mac

- Fixed Docker Desktop adding `~/.docker/bin` to the login-shell PATH even when CLI tools were installed to the system path, which could create a `~/.bash_profile` that hid the user's existing shell environment.
- Added `kubectl` shell completions. Fixes [docker/for-mac](https://github.com/docker/for-mac/issues/7205)

#### For Windows

- Fixed a bug where switching to Windows containers with the WSL engine still enabled could incorrectly offer to continue without starting the required privileged service.
- Fixed an issue where uninstalling Docker Desktop left a stale `FeaturesRequireReboot=1` registry key, which could cause unexpected reboot prompts on subsequent installs.
- Fixed Docker Desktop staying on "Starting..." indefinitely when WSL could not access the disk image location, and reported the access failure with actionable guidance instead of a generic WSL error.
- Fixed the Windows MSI installer reporting success even when the Docker Desktop service failed to install or start.
- Fixed a spurious failure when running a command right after switching to Windows containers.

## 4.90.0

{{< release-date date="2026-09-07" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.90.0" build_path="/238679/" >}}

### Updates

- [Docker Agent v1.128.0](https://github.com/docker/docker-agent/releases/tag/v1.128.0)
- Docker Offload `v0.6.15`
- Docker Desktop CLI v0.4.4

### Bug fixes and enhancements

#### For all platforms

- Ask Gordon is now accessible as a right-side drawer, keeping users in context while chatting with Gordon alongside any page being viewed. 
- A container, image, or volume row with a detected issue now shows an Ask Gordon symbol that starts a diagnosis in one click.
- Fixed a bug where generating a diagnostics bundle could hang until its timeout if a file it collects was on an unresponsive filesystem.
- Fixed an issue where changing the auto-pause timeout while Docker Desktop was already idle would not apply until the original timer expired. 
- Fixed a crash in the **Images** view that occurred when many images loaded simultaneously on cold launch or after waking from Resource Saver mode.
- Fixed a Docker Desktop Dashboard crash issue. Fixes [docker/desktop-feedback#611](https://github.com/docker/desktop-feedback/issues/611).
- Added support for starting and stopping a Kubernetes cloud cluster via Docker Offload, with configurable Kubernetes version and node count.
- The Docker Desktop Dashboard now displays the specific reason Docker Engine failed to start, when available.
- Fixed a bug where `renameat2(RENAME_EXCHANGE)` on a shared folder overwrote the target instead of swapping the two files.
- Fixed a bug where `mmap()` of a file on a Synchronized File Share failed with "No such device", breaking git and pnpm. Fixes [docker/desktop-feedback#627](https://github.com/docker/desktop-feedback/issues/627).
- Fixed a bug where repeatedly replacing files on a shared folder leaked VM disk space until Docker Desktop was restarted. Fixes [docker/desktop-feedback#619](https://github.com/docker/desktop-feedback/issues/619).
- Fixed a bug where a bind-mount root intermittently reported ownership as 0:0, causing git to report "detected dubious ownership". Fixes [docker/desktop-feedback#628](https://github.com/docker/desktop-feedback/issues/628).

#### For Mac

- Fixed an installer crash that occurred when the user's home folder was on a different disk than `/Applications`. Fresh installs and auto-updates now complete successfully in this configuration.
- Fixed startup failures caused by `VZErrorInvalidVirtualMachineConfiguration` due to stale file locks on `Docker.raw` and APFS disk metadata sync races.

#### For Windows

- Fixed a startup hang where Docker Desktop would get stuck on 'Starting' after a WinGet upgrade due to conflicting engine settings in `install-settings.json`.
- The Docker VMM engine option is now always available and no longer flips engines shortly after startup while feature flags load.
- Fixed an issue where the `noWindowsContainers` setting in `install-settings.json` was cleared during a self-update, causing Windows containers to be re-enabled unexpectedly.
- Added a prompt during in-app updates for all-users installations, offering users the option to migrate to a per-user installation that requires no admin privileges for future updates.
- Fixed a bug where Docker Desktop could fail to start after an ungraceful shutdown left behind a stuck socket file.
- Docker Desktop now checks that a Windows host can run Docker VMM before switching to it, and offers to switch back instead of leaving no working engine.
- Fixed Docker VMM telling users to enable the Windows Hypervisor Platform feature when it was already enabled and the real cause was elsewhere.
- Fixed a bug where a failing third-party WSL plugin (for example the Microsoft Defender for Endpoint plug-in for WSL) was reported as a missing Docker Desktop disk instead of naming the plugin that blocked WSL from starting.
- Fixed the MSI installer ignoring `ENGINE=docker-vmm`, which left the Windows Hypervisor Platform feature disabled and the engine unselected.
- Fixed a bug where running the installer with only command-line flags and no `install` verb failed with exit code `4294967291` and no error message.
- Fixed a bug where Docker VMM did not explain how to fix an unavailable Windows Hypervisor Platform.

### Security 

- Updated the Kind cloud provider image to `v0.7.0`, addressing [CVE-2026-46595](https://github.com/advisories/GHSA-x527-x647-q7gg) and [CVE-2026-39834](https://github.com/advisories/GHSA-rm3j-f69w-wqmq).

## 4.89.0

{{< release-date date="2026-08-31" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.89.0" build_path="/238018/" >}}

### Updates

- [Docker Compose v5.5.0](https://github.com/docker/compose/releases/tag/v5.5.0)
- [NVIDIA Container Toolkit v1.20.0](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.20.0)
- [Docker Agent v1.127.0](https://github.com/docker/docker-agent/releases/tag/v1.127.0)

### Bug fixes and enhancements

#### For all platforms 

- Fixed an issue where background container and image polling was waking the Docker engine unnecessarily when Resource Saver mode was active.
- Fixed slow Zsh startup caused by duplicated Docker CLI completion setup in `.zshrc`. Docker Desktop now keeps a single completion block and removes existing duplicates. Fixes [docker/desktop-feedback#561](https://github.com/docker/desktop-feedback/issues/561).
- Sidebar customization permanently is now available to all users. Right-click the left-hand navigation, select **Customize**, and then select, deselect, or re-order the tabs.
- Fixed the **Disk usage** slider in **Settings** to no longer show duplicate tick marks at small ranges, now displaying values in GiB with one decimal place for ranges up to 8 TiB.
- Fixed excessive update notifications in the notification center so that pop-ups only appear for failures or when user action is required, not during in-progress update steps.
- Fixed a dashboard crash issue. Fixes [docker/desktop-feedback#611](https://github.com/docker/desktop-feedback/issues/611)

#### For Windows

- When `CONTAINERD_BUILDX_FOR_WINDOWS` is enabled, Windows Containers now uses `dockerd`'s embedded containerd and in-process BuildKit, replacing the standalone containerd and buildkitd services.
- Fixed a bug where Docker Desktop could fail to start after an ungraceful shutdown left behind a stuck socket file.
- Fixed a bug where Docker VMM did not explain how to fix an unavailable Windows Hypervisor platform.

## 4.88.1

{{< release-date date="2026-08-25" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.88.1" build_path="/237512/" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where opening the Dashboard would incorrectly redirect unauthenticated users to the sign-in prompt page.

## 4.88.0

{{< release-date date="2026-08-24" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.88.0" build_path="/237115/" >}}

### Updates

- [Docker Agent v1.124.0](https://github.com/docker/docker-agent/releases/tag/v1.124.0)
- Docker Offload `v0.6.13`
- [Docker Model Runner v1.2.8](https://github.com/docker/model-cli/releases/tag/v1.2.8)
- [containerd v2.3.3](https://github.com/containerd/containerd/releases/tag/v2.3.3)
- [Runc v1.4.3](https://github.com/opencontainers/runc/releases/tag/v1.4.3)

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where Docker Desktop reported `enable fsverity failed: operation not supported` as the crash cause instead of the real underlying error.
- Fixed a bug where changing the hypervisor type in **Settings** had no effect when Docker Desktop was in Resource saver mode.
- Fixed port bindings reported by `docker ps` to accurately reflect active listeners when using 'Localhost by default' or 'Localhost only' settings, and added `[::1]` loopback listener alongside `127.0.0.1`.
- Fixed an HTTP 500 error that could occur during Docker Desktop startup or wake from idle-shutdown when the engine socket existed but was not yet listening.
- Fixed a bug where Docker Desktop would fail to start if `~/.docker/daemon.json` was corrupted with null bytes (typically caused by a crash or power-loss during a settings save). Docker Desktop now automatically recovers to default daemon settings.
- Fixed an issue in the Docker Engine config editor in settings where validation error messages would disappear immediately while typing invalid JSON.
- Fixed a Docker VMM regression that reduced container inbound network throughput to roughly 0.3 GB per second.
- Fixed error messages shown when the Docker Desktop VM exits unexpectedly to include the exit status code and surface the actual root cause of the crash.

#### For Mac

- Docker VMM can now use more than 28GiB of host memory.

#### For Windows

- Fixed a Windows auto-update failure when a self-updated CLI plugin (e.g `docker scout` or `docker agent`) newer than the bundled version was already present in the user's CLI-plugins folder.
- Fixed an issue on per-user Windows installs where Hyper-V, Windows containers, and related settings are now correctly disabled and grayed out, preventing broken behavior caused by the unavailable priveleged helper service.

## 4.87.0

{{< release-date date="2026-08-17" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.87.0" build_path="/236836/" >}}

### Updates

- [Docker Agent v1.122.0](https://github.com/docker/docker-agent/releases/tag/v1.122.0)
- [Docker Buildx v0.36.1](https://github.com/docker/buildx/releases/tag/v0.36.1)
- Docker Offload `v0.6.10`
- [Docker Compose v5.4.0](https://github.com/docker/compose/releases/tag/v5.4.0)
- Linux kernel `v7.0.12`

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where the in-app update failed with `Source and destination path must have identical roots` when Docker Desktop was installed to a custom directory on another drive.
- Fixed a misleading proxy error that named the destination server instead of the unreachable upstream proxy, and included machine-wide proxy configuration in diagnostics.
- Fixed a bug where updating could keep failing with a `file exists` error after an earlier update had failed.
- Fixed an issue where Gordon would lose access to tools and show misleading sign-in prompts after a failed auto-login at startup, without requiring a restart of Docker Desktop.

#### For Mac

- Fixed a false `Docker Desktop encountered an unexpected error` dialog that could appear during VM shutdown on with the `libkrun` engine.
- Fixed a rare crash where the Docker Desktop with the Apple Virtualization Framework VM stopped unexpectedly right after a new connection was opened.

#### For Windows

- Fixed WSL error recovery on Windows not displaying specific, actionable error messages for errors like `HCS/0x80070569`, showing the generic fallback instead.
- Fixed an issue on Windows where per-user `.EXE` installs applying an auto-update wrote `install-settings.json` to the system-wide path instead of the correct per-user location.
- Fixed an issue on Windows where diagnostic bundles were missing network connection profile data due to an empty `Get-NetConnectionProfile.json` file.
- Fixed a bug on Windows where Docker Desktop repeatedly asked users to run `wsl --update` when WSL was installed via the Microsoft Store rather than the inbox optional component.
- Fixed an issue where the Resource Saver settings section was incorrectly shown when using Windows containers instead of Linux containers.
- Fixed an issue on Windows where the disk image usage limit was hidden in **Resources** settings when Hyper-V was selected as the hypervisor.
- Fixed an issue on Windows where installer logs from per-user installations were missing from diagnostic bundles.
- Fixed the virtual disk limit not being applied when lowered on Windows with Hyper-V.
- Fixed the disk usage limit slider being hidden and ignored for the Docker VMM backend on Windows, so users can now set and enforce disk size in **Settings** > **Resources** > **Advanced**.
- Fixed a Windows auto-update failure when a self-updated CLI plugin (`docker scout` or `docker agent`) newer than the bundled version was already present in the user's CLI-plugins folder.

## 4.86.0

{{< release-date date="2026-08-10" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.86.0" build_path="/236216/" >}}

### Updates

- [Docker Engine v29.7.2](https://docs.docker.com/engine/release-notes/29/#2972)
- [Docker Buildx v0.36.0](https://github.com/docker/buildx/releases/tag/v0.36.0)
- [Docker Scout CLI v1.24.0](https://github.com/docker/scout-cli/releases/tag/v1.24.0)
- [Docker Agent v1.119.0](https://github.com/docker/docker-agent/releases/tag/v1.119.0)

### Bug fixes and enhancements

#### For all platforms

- Docker VMM Beta performance improvements by Docker’s own container-optimized hypervisor. Available for Mac and Windows.
- Gordon now displays specific error messages for tool failures, policy-blocked actions, and loop detection instead of a generic **Agent error**.
- Fixed container stop timeouts and `unless-stopped` restart policies not being honored during engine shutdown.
- Fixed a bug where enabling Docker Offload from the Docker Desktop Dashboard failed when the proxy was configured by the operating system instead of by environment variables.
- Fixed a crash on startup after upgrading, for users whose settings file was written by a very old version.
- Fixed port forwarding for Swarm services that use automatically assigned published ports, including host-mode task ports and repeated ingress port definitions.
- Added a three-mode safety system (Strict, Balanced, Autonomous) to the Gordon AI agent's tool confirmation UI, replacing the previous binary approve/allow-all dialog, with risk-tier labels on confirmation.
- Fixed a flash of incorrect UI content on app launch, such as a brief 'Waiting for the Docker Engine...' screen or unexpected navigation away from gated pages.
- AF_UNIX sockets shared over VirtioFS now work in both directions (host to guest and guest to host).
- Fixed a bug where restarting the VM would steal the window focus.

#### For Mac

- Fixed a bug where a Kubernetes (kind) cluster with Enhanced Container Isolation could fail to recover after a Docker Desktop restart.
- Fixed nftables `fib` expressions failing with "Operation not supported" in `inet` tables on Apple Silicon.

#### For Windows

- Fixed an issue where the Windows installer reported success when it could not write its settings or enterprise policy files.
- Fixed Model Runner failing to start with `CreateJobObject: Access is denied` when Docker Desktop is launched via a Secondary Logon (run-as-user) session.
- Updated the bundled 7-Zip to 26.02 to avoid antivirus software quarantining it during an upgrade on Windows.

#### For Linux

- Fixed Docker Desktop failing to start on Linux arm64 hosts due to incorrect QEMU binary path resolution.

### Security

- Addressed CVE-2026-17106, a destination-escape flaw in `docker container cp`.

## 4.85.0

{{< release-date date="2026-08-03" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.85.0" build_path="/235549/" >}}

### Updates

- [Docker AI Agent v1.115.0](https://github.com/docker/docker-agent/releases/tag/v1.115.0)

### Bug fixes and enhancements

#### For all platforms 

- Fixed an issue where native crash reports were uploaded to Bugsnag even when analytics was disabled by the user.
- Fixed an issue where file content previews and diffs were hidden in the Gordon confirmation card when approving write or edit file actions.
- Fixed an issue where an invalid `install-settings.json` caused a ~7-minute startup delay before showing the error dialog. The error now appears immediately.
- Fixed an issue where Gordon's plan mode would silently revert to build mode after the first message, causing subsequent turns to run with full tool access despite plan mode appearing active.
- Fixed an issue where an invalid `config.json` at startup would delay the error dialog by up to 7 minutes instead of appearing within seconds.
- Fixed a Linux VM kernel panic that could hang Docker Desktop when a container's file watcher (inotify/fanotify) observed host-side changes to files on a bind mount.
- Fixed Docker Hardened Images CLI ampersands being encoded when outputting JSON to the console.
- Fixed a bug where extensions-related requests would fail on startup due to the extensions selector incorrectly defaulting to enabled before settings were loaded.
- Fixed an issue where sub-agent message attribution was lost when reloading a historical multi-agent Gordon session, causing sub-agent messages to appear as if produced by the main agent.
- Fixed Gordon's **Clean up Docker** suggestion prompt to propose a cleanup plan and wait for user confirmation before removing any resources, preventing unintended deletions.
- Fixed the Gordon AI plan-mode toggle visibility to accurately reflect backend support, showing only when the connected agent declares plan capability.

#### For Windows

- Fixed a bug where per-user uninstalls of Docker Desktop on Windows failed with an unauthorized access error when attempting to revert the hosts file.
- Added per-user install mode as the default for fresh Docker Desktop installations from the Microsoft Store on Windows, removing the need for admin privileges.
- Fixed an issue where Docker Desktop crashed when the `docker-users` group is missing, now showing a recoverable group membership dialog instead.

#### For Linux

- Removing files on a host bind mount inside an Enhanced Container Isolation container no longer fails with "Value too large for data type".

## 4.84.0

{{< release-date date="2026-07-27" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.84.0" build_path="/234817/" >}}


### Updates

- [Docker Agent v1.111.0](https://github.com/docker/docker-agent/releases/tag/v1.111.0)
- Kubernetes:
  - cri-dockerd v0.4.4
- [Docker Hardened Images CLI (`dhictl`) v0.0.7](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.7)
- Docker Desktop CLI `v0.4.3`

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where an invalid `~/.docker/config.json` caused Docker Desktop to hang with high CPU/memory and show no error dialog. Docker Desktop now surfaces an error dialog prompting the user to correct the file.
- Fixed a bug that prevented some Docker Hardened Images customizations from being created.
- Fixed a bug where deleting an unrelated credential ID could accidentally erase Docker Hub OAuth tokens, causing users to be unexpectedly signed out.
- Removed Docker Scout CLI hints that previously appeared after running `docker pull` or `docker buildx build` commands.

#### For Windows

- Fixed a bug on Windows where an empty or malformed `install-settings.json` caused Docker Desktop to hang with high CPU/memory usage and no error dialog on startup.
- The MSI installer now detects per-user Docker Desktop installations on the machine and blocks installation with a clear message naming the affected users. Affected users must uninstall their per-user Docker Desktop before the MSI can be installed.
- Fixed a bug where uninstalling Docker Desktop could permanently lock the user out of their own application data directories if the deletion failed mid-way.

## 4.83.0

{{< release-date date="2026-07-20" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.83.0" build_path="/234302/" >}}

### Updates

- Docker Desktop CLI `v0.4.2`
- [Docker Model Runner v1.2.6](https://github.com/docker/model-runner/releases/tag/v1.2.6)
- Docker Offload `v0.6.9`
- [Docker Agent v1.103.0](https://github.com/docker/docker-agent/releases/tag/v1.103.0)
- [Docker Compose v5.3.1](https://github.com/docker/compose/releases/tag/v5.3.1)
- Docker Desktop Build `v0.36.0`
- [Docker Engine v29.6.2](https://docs.docker.com/engine/release-notes/29/#2962)

### Bug fixes and enhancements

#### For all platforms

- Added support for migrating a per-machine Docker Desktop installation to a per-user installation in-place via `install --user` on Windows, preserving user data without requiring a manual uninstall.
- Fixed `kubectl exec` and `kubectl attach` functionality for v1.36.
- Fixed Docker Engine startup failures being reported as a generic `io: read/write on closed pipe` error instead of the underlying cause.
- Fixed the **Images** view showing **0 Bytes** reclaimable size for a while when many images are present.
- Fixed the volumes list not correctly sorting by size.
- Fixed an issue where a GPU process crash prevented the Docker Desktop Dashboard from loading by automatically disabling hardware acceleration and restarting the app.
- Fixed an issue where `docker ai` sessions launched directly from a terminal were killed when Docker Desktop was restarted.
- Fixed an issue where a malformed `daemon.json` would be silently overwritten with defaults on startup, causing users to lose their custom daemon configuration.
- Added a **Custom rules** tab to Gordon's permissions dialog. Users can now add allow/deny rules for specific commands or MCP tools.
- Added pulsing discovery badges to Gordon's **Plan mode** button, model selector, and **Feedback/Issues** button to help users find new features. 

#### For Mac

- Fixed an issue where a stale `com.docker.virtualization` process could prevent Docker Desktop from starting a new VM with a `VZErrorInvalidVirtualMachineConfiguration` error.

#### For Windows

- Fixed an issue where a failed delta update would leave users stranded on an old version by automatically falling back to the full installer.
- Fixed the Windows MSI installer reporting success when the component installation step actually failed.
- Fixed an issue where the Windows installer wizard froze while enabling Windows features via DISM during Docker Desktop installation.
- Fixed a UI thread deadlock in the Windows installer that caused a blank or hung window when prerequisite services were registered but not running during admin installs.
- Fixed the Windows installer silently reporting success when it could not install the Docker CLI plugins.
- Fixed the Windows installer deleting a previously installed CLI plugin when re-linking it failed.
- Fixed a bug where registry policy download failures were silently ignored, so users now see proper error reporting when the admin helper exits with a non-zero code.
- Changed the Windows installer to select a per-user installation by default.
- Fixed a WSL integration issue on WSL 2.6.x and later where Docker Desktop failed to work in user distros due to a 0-byte proxy binary, causing **Permission denied** or **Exec format error**.
- Fixed the Docker CLI in integrated WSL distributions breaking after Resource Saver stopped the VM. The VM now stays running while a WSL integration is active and wakes when one is enabled. Fixes [docker/desktop-feedback#522](https://github.com/docker/desktop-feedback/issues/522).

## 4.82.0

{{< release-date date="2026-07-13" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.82.0" build_path="/233772/" >}}

### Updates

- [Docker Compose v5.3.0](https://github.com/docker/compose/releases/tag/v5.3.0)
- [Docker Agent v1.98.0](https://github.com/docker/docker-agent/releases/tag/v1.98.0)
- [Docker Scout CLI v1.23.1](https://github.com/docker/scout-cli/releases/tag/v1.23.1)

### Bug fixes and enhancements

#### For all platforms

- Added thumbs up and thumbs down feedback buttons to Gordon responses. Users can rate replies or report issues directly from the chat.
- Fixed a bug where containers created by Docker Desktop had their stop timeout set to 1 second instead of the Docker Engine default, causing `docker stop` to terminate processes too quickly.
- Fixed reset to factory defaults not clearing MCP Toolkit profiles, catalogs, and authorizations.
- Fixed an issue where selected thumbs up/down feedback buttons in Gordon were visually indistinguishable after selecting.
- Fixed reset to factory defaults not clearing downloaded LLM models.
- Fixed a bug where the Gordon chat area would go blank when the agent requested free-text input via elicitation.
- Fixed a delay in the Kubernetes screen where the progress UI did not appear immediately after confirming cluster creation or deletion.
- Fixed a bug where a Kubernetes kind cluster failed to start with a **Failed to get API server port** error after a Docker Desktop restart.
- With `docker pass`, the `ls` command now behaves consistently across all platforms.
- Fixed an issue where users signed out due to sign-in enforcement policies were shown a generic sign-in prompt instead of a clear explanation of why they were signed out.

#### For Mac

- Fixed an issue where Docker Desktop child processes could linger after an unexpected backend exit.
- Fixed an issue where Docker Desktop failed to start for users with long home directory paths that caused Unix socket paths to exceed OS length limits.
- Fixed an issue where vsock listener failures showed a cryptic crash instead of a clear, actionable recovery dialog.

#### For Windows

- Fixed an issue where `.log` files were missing from diagnostic bundles, ensuring the Docker Desktop service log is now included.
- Lowered the priority of Docker Desktop's background processes and enabled Windows Efficiency Mode while idle to reduce power and CPU usage.
- Fixed factory reset leaving containers and images behind on Hyper-V when Docker Desktop is run by a user other than the one that installed it.
- Fixed a multi-minute hang during WSL engine startup when the wsl-bootstrap process fails unexpectedly, surfacing the error promptly instead.
- Fixed an issue where auto-updates could leave Docker Desktop stuck in a 'connecting' state due to a successful installation being incorrectly rolled back.
- Fixed an issue where vsock listener failures on Windows Hyper-V showed a cryptic crash instead of a clear, actionable recovery dialog.
- Fixed a race condition where connecting to `com.docker.service` immediately after startup could result in a **File not found** error.
- Fixed an issue where a graphical installer window would flash during background auto-updates. Updates now run silently.
- Improved security by verifying the Authenticode signature of the downloaded installer before executing it during updates.
- Fixed an issue where missing or disabled Windows feature descriptions were not shown in diagnostic output.
- Improved the installer progress screen with a single continuous progress bar that smoothly advances from 0% to 100% throughout the entire installation.
- Fixed an issue where `~` in bind mount paths was not correctly resolved to the home directory when the `HOME` environment variable was not set.

#### For Linux

- Fixed an issue where Docker Desktop failed to start for users with long home directory paths that caused Unix socket paths to exceed OS length limits.

## 4.81.0

{{< release-date date="2026-07-06" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.81.0" build_path="/232925/" >}}

### Updates

- [Docker Model Runner v1.2.5](https://github.com/docker/model-runner/releases/tag/v1.2.5)
- [Docker Agent v1.88.1](https://github.com/docker/docker-agent/releases/tag/v1.88.1)
- Docker Offload `v0.6.7`
- [Docker Compose v5.2.0](https://github.com/docker/compose/releases/tag/v5.2.0)
- [Docker Scout CLI v1.22.0](https://github.com/docker/scout-cli/releases/tag/v1.22.0)
- [DHI CLI (`dhictl`) v0.0.5](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.5)

### Bug fixes and enhancements

#### For all platforms

- Fixed an error that caused volumes, images, and containers to fail to load in the Docker Desktop Dashboard.
- Removed the deprecated `cagent` binary from Docker Desktop; use `docker agent` instead.
- Kubernetes kind cluster now works with Registry Access Management.
- Fixed a bug where the sign-in/update prompt was not shown when upgrading between versions that cross a version digit boundary (e.g., 4.9.x to 4.10.x).
- Fixed an issue in Ask Gordon where the tool call permission dialog blocked the chat view, replacing it with an inline approval card so users can read Gordon's full message before approving or rejecting.
- Fixed a rare case where Docker Desktop could shut down if the build service crashed, for example during a factory reset.
- Fixed an issue where containers ignored user-configured stop timeouts during normal operation due to a proxy-level override forcing a 1-second timeout on all containers.

#### For Mac

- Fixed Docker Desktop failing to start when the user's environment contained very long environment variables.
- Fixed a Docker Offload crash on Intel machines due to `SG_READ_ONLY` not being set in the `__DATA_CONST` segment, causing the system linker to fail to load the executable. Fixes [docker/desktop-feedback#471](https://github.com/docker/desktop-feedback/issues/471).

#### For Windows

- Fixed an issue on Windows where stopping Docker Desktop would immediately force off the Hyper-V VM without waiting for a graceful guest shutdown, reducing the risk of data corruption.
- Fixed a bug on Windows where `dockerd` failed to connect through the local HTTPS proxy due to a TLS handshake error caused by an incorrect proxy URL scheme.
- Fixed a Windows update that reverted and showed a **Mismatch patch version** error when it ran again after the target version was already installed.
- Fixed Resource Saver not stopping the Docker engine when running on WSL.
- Fixed a regression where Docker Desktop failed to start on WSL2 kernels that could not attach the Synchronized File Shares eBPF probes, such as Windows on Arm. Fixes [docker/desktop-feedback#470](https://github.com/docker/desktop-feedback/issues/470).

#### For Linux

- Fixed a bug where Docker Desktop would fail to start after a reset.

## 4.80.0

{{< release-date date="2026-06-29" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.80.0" build_path="/232116/" >}}

### Updates

- Docker Offload `v0.6.6`
- [Docker Buildx v0.35.0](https://github.com/docker/buildx/releases/tag/v0.35.0)
- [Docker Model Runner v1.2.4](https://github.com/docker/model-runner/releases/tag/v1.2.4)
- [containerd v2.2.5](https://github.com/containerd/containerd/releases/tag/v2.2.5)
- [Docker Engine v29.6.1](https://docs.docker.com/engine/release-notes/29/#2961)
- [Runc v1.3.6](https://github.com/opencontainers/runc/releases/tag/v1.3.6)
- Kubernetes v1.36.1
   - CNI plugins v1.9.1
   - cri-tools v1.35.0
   - cri-dockerd v0.3.25
- Updated Kubernetes images:
   - Kubeadm:
      - `docker/desktop-storage-provisioner:v4.0`
      - `docker/desktop-vpnkit-controller:v4.0`
      - `docker/desktop-kubernetes-etcd:3.6.8-0`
      - `docker/desktop-kubernetes-coredns:v1.14.2`
      - `docker/desktop-kubernetes-pause:3.10.2`
      - `docker/desktop-kubernetes-apiserver:v1.36.1`
      - `docker/desktop-kubernetes-controller-manager:v1.36.1`
      - `docker/desktop-kubernetes-scheduler:v1.36.1`
      - `docker/desktop-kubernetes-proxy:v1.36.1`
   - Kind:
      - `docker/desktop-containerd-registry-mirror:v0.0.4`
      - `docker/desktop-cloud-provider-kind:v0.6.0`
      - `envoyproxy/envoy:v1.36.7`

### Bug fixes and enhancements

#### For all platforms

- The experimental `docker sandbox` plugin has been removed. Migrate to [`docker sbx`](../ai/sandboxes/index.md).
- Fixed an issue where running out of disk space showed a generic error dialog instead of a clear **Disk full** message prompting users to free up space and restart.
- Fixed an issue where using `docker -c desktop-linux` while a cloud context was active would silently route commands to the cloud engine instead of the local desktop Linux engine.
- Fixed a bug where the backend would incorrectly report a stopped VM as running after an idle shutdown, especially when Enhanced Container Isolation was enabled.
- Fixed an OS update notification timing issue where users with auto-download enabled were notified when an update was available rather than when it was ready to install.

#### For Mac

- Removed the legacy osxfs file sharing. Users still on osxfs are migrated to VirtioFS.
- Increased VirtioFS filesharing performance by not persisting (fake) file ownership changes on the host. Calls to `chown` will succeed, but `stat` will not be affected.

#### For Windows

- Fixed an issue where the Windows installer failed when the destination directory contained leftover files from a previous interrupted installation.
- Fixed an issue on Windows where upgrading Docker Desktop would unnecessarily shut down and unregister unrelated WSL distros via `wsl --shutdown`.
- Fixed spurious Hyper-V job failures on Windows where operations briefly transitioning through suspended or shutting down states were incorrectly reported as failed.
- Fixed an issue where the WSL engine failed to start with a **Permission denied** error on machines where the cross-distro WSL mount was configured as `noexec`.
- Fixed an issue on Windows where end users could override the `NO_PROXY` exclusion list even when an admin had locked the proxy configuration.
- Fixed an issue on Windows where Docker Desktop would silently disappear on startup failure. An error dialog is now displayed instead.
- Fixed an issue on Windows where Docker Desktop showed a generic engine-start failure instead of routing to the WSL update recovery when an older wsl.exe did not support the --version flag.

## 4.79.0

{{< release-date date="2026-06-22" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.79.0" build_path="/230596/" >}}

### Updates

- [Docker Agent v1.79.0](https://github.com/docker/docker-agent/releases/tag/v1.79.0)
- `docker pass` v0.1.5
- Docker Desktop CLI v0.4.1
- Docker Offload v0.6.4 

### Bug fixes and enhancements

#### For all platforms

- Gordon improvements:
   - Added context-aware suggested questions to the Ask Gordon menu in the **Containers**, **Images**, **Volumes**, and **Builds** tabs, surfacing relevant diagnostics first when items are in a problematic state.
   - Added a **Give feedback** link to Gordon so you can report issues with a redacted conversation preview or share product feedback.
   - Fixed a React warning in Gordon's sidebar search input that appeared on the first keystroke when typing a search query.
- Fixed an issue where the Docker Engine settings editor displayed minified JSON instead of formatted JSON when first opened.
- Fixed spurious 500 errors for Docker API calls made right after the VM woke from idle shutdown.
- Fixed spurious 'Integrity issue detected' notifications caused by leftover symlinks from previously bundled binaries.
- Fixed a broken documentation link in the error screen shown when the current user is not a member of the `docker-users` group.
- Fixed a breaking change to the `/app/settings/grouped` API that caused integrations such as NVIDIA to stop working correctly.
- Fixed high CPU usage (~30%) on macOS Retina displays caused by SVG animations in the Gordon landing page.
- Fixed an issue where OAuth network errors caused Docker Desktop to incorrectly show users as signed out.
- Fixed an issue where signing in via OAuth would not display the user's username and email in the UI after login.
- QEMU has been updated to v10.2.3
- **Logs** view improvements
   - Added copy buttons. Copy all visible filtered logs at once or copy individual log entries on hover, respecting the current timestamp visibility setting.
   - Improved the toolbar with a reorganized layout, saved filter presets that now capture container selection and build log visibility, and the ability to persist container filter state.
   - Added the ability to clear logs.
   - Combined **copy** and **expand**/**collapse** buttons into a single pinned column that stays visible during horizontal scrolling, and fixed **copy** accidentally toggling the row detail pan.
- Fixed Registry Access Management policy downloads to avoid `permission denied` errors by fetching and caching policies in the user's own directory with tampering detection.

#### For Windows

- Fixed a bug where Docker Desktop on WSL failed to start with an 'is already mounted' error after a force-killed bootstrap left stale rootfs mounts behind.
- Fixed an issue on Windows where clicking "Quit Docker Desktop" had no effect when the backend had crashed or been killed.
- Fixed an issue on Windows where Docker Desktop processes could linger as orphans after an unexpected exit or crash.
- Fixed getting stuck on "Starting the Docker Engine…" after an in-place upgrade on Windows when the WSL virtual machine had not been shut down.
- Fixed the tray icon on Windows not matching the system taskbar theme, so the correct light or dark icon is now displayed.
- Fixed a silent failure on Windows where backend startup errors were only written to a log file. Users now see a visible error dialog box when Docker Desktop fails to start.

## 4.78.0

{{< release-date date="2026-06-15" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.78.0" build_path="/229452/" >}}

### Updates

- [Docker Agent v1.73.0](https://github.com/docker/docker-agent/releases/tag/v1.73.0)
- `docker pass` v0.1.4
- [Credential helpers v0.9.8](https://github.com/docker/docker-credential-helpers/releases/tag/v0.9.8)

### Bug fixes and enhancements

#### For all platforms 

- Fixed an out-of-memory crash that would cause Docker Desktop to become unresponsive or crash while streaming logs in the Docker Desktop Dashboard.
- Improved update reliability by retrying stalled and transient download failures and resuming from the partially downloaded file.
- Added live streaming output to Gordon tool calls so long-running commands like `docker compose up` display STDOUT/STDERR in real time instead of waiting until completion.
- Added color-coded labels to the **Logs** view so each container and build source is visually distinguished by a unique color in both the log grid and the container-filter dropdown.
- Improved the error message when the Docker Desktop VM fails to start. It now shows the underlying `VirtualizationFramework` / `libkrun` reason instead of the generic **Use of closed network connection**.
- Fixed a bug where Docker CLI error messages were shown as raw JSON instead of human-readable text while Docker Desktop was in Resource Saver mode.
- Fixed a crash that occurred in the **Logs** view when deselecting a container filter.
- Fixed an issue where the support page was replaced by the no-virtualization override screen when accessed from the troubleshooting popover.
- Fixed an issue where Docker Desktop failed to start on bare metal EC2 instances (e.g. `g4dn.metal`) with a **Nested virtualization not supported** error.
- Increased the retry delay to accommodate transient rename failures caused by antivirus software holding file locks.
- Gordon now shows clear network error messages with guidance to check VPN, proxy, or firewall settings when outbound HTTPS to Docker's services is blocked, instead of a generic agent error.
- Fixed the Gordon AI model picker incorrectly showing an internal model identifier instead of **Default** for sessions with no explicit model selection.

#### For Windows

- Fixed Docker Desktop getting stuck on **Starting the Docker Engine…** after an in-place upgrade.
- Fixed a bug where Docker Desktop was not restarted after a failed update was reverted to the previous version.
- Fixed delta updates failing to prepare.
- Fixed an issue on Hyper-V where Docker commands (e.g. `docker login`) would fail on the first attempt after the engine had been idle-shut-down or paused.
- Fixed an issue on Windows where Docker Desktop showed a generic engine-start failure instead of a clear, actionable error message when WSL is not installed.

## 4.77.0

{{< release-date date="2026-06-08" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.77.0" build_path="/228796/" >}}

### New

- You can now export log data from the **Logs** view.

### Updates

- Docker Offload v0.6.3
- [Docker Buildx v0.34.1](https://github.com/docker/buildx/releases/tag/v0.34.1)
- [Docker Agent v1.70.0](https://github.com/docker/docker-agent/releases/tag/v1.70.0)
- [Docker MCP gateway v0.42.2](https://github.com/docker/mcp-gateway/releases/tag/v0.42.2)
- `docker pass` v0.1.2 
- [containerd v2.2.4](https://github.com/containerd/containerd/releases/tag/v2.2.4)
- [DHI CLI (`dhictl`) v0.0.4](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.4)
- [Docker Engine v29.5.3](https://docs.docker.com/engine/release-notes/29/#2953)

### Bug fixes and enhancements

#### For all platforms 

- Increased the retry delay to accommodate transient rename failures caused by antivirus software holding file locks.
- Marketplace extensions are now installed and updated by pinned manifest digest, instead of by tag, protecting against tag mutation after publication.
- Added Buildx version information to the About window.
- Added a case-sensitivity toggle to the **Logs** search bar which lets you switch between case-insensitive (default) and case-sensitive log filtering.
- Fixed a bug where the mouse wheel scroll was not working in the **Logs** view grid.
- Fixed an issue where the backend incorrectly exited with error code 150 on clean shutdown via SIGINT or SIGTERM, causing false failure signals.
- Removed the bundled `hub-tool` binary from Docker Desktop.
- Added working **Authenticate** and **Cancel** buttons to the MCP OAuth authorization chat bubble in Gordon, letting you complete or decline OAuth sign-in flows from MCP servers.
- Added two new commands to `docker pass`:
   - Use `docker pass run` to inject secrets into host commands.
   - Use `docker pass plugins` for dynamic plugin management.
- Fixed a regression where `docker cp` into a container with Enhanced Container Isolation (ECI) enabled set file ownership to `nobody:nogroup`.

#### For Windows

- Fixed an issue on Windows where Docker Desktop would get stuck on **Starting the Docker Engine...** after a failed WSL distro registration left a VHDX on disk.
- Fixed a backend shutdown hang in Windows Containers mode that caused Docker Desktop to take a long time or fail to exit cleanly.

## 4.76.0

{{< release-date date="2026-06-01" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.76.0" build_path="/228118/" >}}

### New

- Docker Model Runner now supports registry mirrors.

### Updates

- [Docker Desktop Build v0.35.0](https://github.com/docker/desktop-build/releases/tag/v0.35.0)
- [Docker Agent v1.62.0](https://github.com/docker/docker-agent/releases/tag/v1.62.0)
- [NVIDIA Container Toolkit v1.19.1](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.19.1)
- [Docker Compose v5.1.4](https://github.com/docker/compose/releases/tag/v5.1.4)
- Docker Offload v0.5.93
- [Docker Scout CLI v1.21.0](https://github.com/docker/scout-cli/releases/tag/v1.21.0)
- `docker pass` v0.0.29

### Security

- Addressed [CVE-2026-8936](https://www.cve.org/CVERecord?id=CVE-2026-8936), a VM panic caused by unbounded recursion in the `grpcfuse` kernel module when a container created deeply nested directories on a bind-mounted host folder and triggered a `dentry` invalidation event.

### Bug fixes and enhancements

#### For all platforms

- The `docker sbom` command has been deprecated and will be removed in a future release. Use the [`docker scout sbom command`](/reference/cli/docker/scout/sbom/) instead.
- Fixed a race condition in Docker Engine when **Resource Saver** was active.
- Fixed a bug where anonymous Docker volumes were leaked each time a `kind` cluster was deleted, causing orphaned volumes to accumulate.
- Fixed column resizing in the **All Logs** grid so that **Timestamp** and **Object** columns no longer expand unexpectedly, and column widths are now preserved across navigation sessions.
- Fixed an issue where Docker Desktop failed to start when a VM disk resize operation encountered an error, even if the underlying filesystem was healthy.
- Fixed an issue that caused Docker Desktop to hang when quit.
- Fixed a bug where CPU and RAM resource totals could get stuck showing 0 in the Docker Desktop Dashboard after stopping or starting Docker Offload.
- Fixed a flicker in Gordon where the final answer text would briefly appear inside the working group before jumping to the response bubble.
- Fixed a daemon panic that could occur during concurrent sign-out and token refresh operations.
- Fixed a bug where the **Volumes** view showed incorrect mount targets for containers with multiple volumes.
- `docker pass` now has a `--force` flag on the `set` command. 
- `docker --help` now shows `docker pass`.
- Fixed stale API cache responses (synthetic 404s) for containers, images, networks, volumes, and plugins after restarting an idle-stopped engine via external API calls.
- Fixed a bug where the **Delete** button on the **Builds** view might not be visible immediately after selecting a build. Fixes [docker/desktop-feedback#329](https://github.com/docker/desktop-feedback/issues/329) and fixes [docker/desktop-feedback#330](https://github.com/docker/desktop-feedback/issues/330).
- Fixed time-namespaces being unavailable when Enhanced Container Isolation (ECI) is enabled.

#### For Windows

- Fixed a regression where the `--quiet` installer flag did not suppress the install-type dialog during silent installation.
- Fixed a bug on Windows where a stale PID file with a trailing newline prevented the lingering daemon from being killed, leaving Windows Containers mode unconfigurable.
- Fixed an issue on Windows where triggering an update while another installer instance was already running showed a generic error instead of a specific message.
- Fixed an issue on Windows where the installer and updater executables incorrectly triggered UAC elevation prompts due to Windows heuristic installer detection.
- Fixed double separator in the tray menu when running in Windows container mode.
- Fixed port-binding failures on Windows Hyper-V where `docker run -p 0:N` could allocate HNS-reserved ports, causing bind errors.
- Fixed garbled taskkill error messages in logs on non-English Windows systems (For example, Chinese Windows using GBK encoding).
- Fixed unbounded growth of the WSL2 ISO cache. Old `docker-desktop.iso` and `docker-wsl-cli.iso` entries are now removed when a new version is installed. Fixes [docker/desktop-feedback#419](https://github.com/docker/desktop-feedback/issues/419).

## 4.75.0

{{< release-date date="2026-05-26" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.75.0" build_path="/227598/" >}}

### Updates

- Docker Offload v0.5.92
- [Docker Engine v29.5.2](https://docs.docker.com/engine/release-notes/29/#2952)
- [Docker Buildx v0.34.0](https://github.com/docker/buildx/releases/tag/v0.34.0)

### Bug fixes and enhancements

#### For all platforms 

- Removed the Docker Scout view and disabled Scout-related OS notifications and notification popups.
- Added support for time namespacing in ECI protected containers.
- Fixed a bug where the `http_proxy` environment variable could prevent kind clusters from pulling local images.
- Fixed a `500 Internal Server Error` that could occur on the first Docker API call right after the VM wakes up from idle shutdown. 
- Fixed broken images in Docker Hub image descriptions caused by relative URLs being resolved to invalid `app://` scheme URLs.

#### For Mac

- Added a warning dialog that appears at startup when Docker Desktop is running from a staging directory due to a failed update. Also adds a link to download a fresh install.

#### For Windows 

- WSL integration with the default distribution has been disabled. To change this, visit **Settings**. 
- Fixed a bug where `docker compose up` failed with an `EOF` error on Windows with a Hyper-V backend, when accepting a file-sharing consent prompt.
- Fixed Windows installer bugs that could cause incorrect backend mode detection or unexpected directory creation during installation.

## 4.74.0

{{< release-date date="2026-05-19" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.74.0" build_path="/227015/" >}}

### New

- [Gordon](/ai/gordon) is now generally available. New usage plans are also available. Paid Gordon plans unlock higher usage limits.

### Updates

- Docker Offload v0.5.89
- [Docker Agent v1.57.0](https://github.com/docker/docker-agent/releases/tag/v1.57.0)
- [Credential helpers v0.9.7](https://github.com/docker/docker-credential-helpers/releases/tag/v0.9.7)
- `docker pass` v0.0.26

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where Docker Desktop's own Electron helper processes (GPU, renderer, utility) were incorrectly detected and killed as lingering processes on startup when launching from the Start menu, causing a crash loop.
- Fixed an issue where the **View build logs** toggle in Logs view display settings was reset after restarting Docker Desktop instead of persisting the user's preference.
- Docker Extensions is now disabled by default.

#### For Mac

- Fixed published ports being inaccessible when a container is also connected to a Swarm overlay network. Fixes [docker/for-mac#7854](https://github.com/docker/for-mac/issues/7854).
- Fixed dashboard TLS failures in some corporate environments.
- Improved GUI security via content hash validation.

#### For Linux

- Added support for Ubuntu 26.04.

## 4.73.1

{{< release-date date="2026-05-13" >}}

{{< desktop-install-v2 win=true version="4.73.1" build_path="/226574/" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed a bug where Docker Desktop's own Electron processes were incorrectly killed when launching from the Start menu. Fixes [docker/desktop-feedback#367](https://github.com/docker/desktop-feedback/issues/367).

## 4.73.0

{{< release-date date="2026-05-11" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.73.0" build_path="/226246/" >}}

### Updates

- [Docker Engine v29.4.3](https://docs.docker.com/engine/release-notes/29/#2943)
- [Docker Agent v1.54.0](https://github.com/docker/docker-agent/releases/tag/v1.54.0)

### Bug fixes and enhancements

#### For all platforms

- Fixed `Cmd+Q` (Mac) and `Ctrl+Q` (Windows/Linux) not fully quitting Docker Desktop. Fixes [docker/for-mac#7833](https://github.com/docker/for-mac/issues/7833).
- Fixed a bug where canceling `docker load` left a containerd ref lock held, causing subsequent loads of the same image to fail.
- Fixed an issue where Docker Desktop made unnecessary network requests to `mcp.docker.com` on sign-in when MCP Toolkit was disabled, causing unexpected proxy authentication prompts.
- Fixed an issue where the search input in Gordon's session sidebar would not close if it was left empty.
- Improved Docker Desktop handling of transient rename failures caused by antivirus software accessing those files simultaneously.

#### For Mac

- Fixed excessive memory usage on Apple Silicon Macs by improving the Linux VM's ability to return freed container memory back to the host OS.
- Fixed a bug where containers received connections with a corrupted source IP when another container had an active outbound connection to an IP in the same subnet range. Fixes [docker/for-mac#7824](https://github.com/docker/for-mac/issues/7824).

## 4.72.0

{{< release-date date="2026-05-06" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.72.0" build_path="/225998/" >}}

### New

- The **Logs** view is now generally available.
- New installations of Docker Desktop for Windows have a choice between per-user (Beta) or all-user installs.

### Updates

- [Docker Agent v1.50.0](https://github.com/docker/docker-agent/releases/tag/v1.50.0)
- [Docker DHI (`dhictl`) v0.0.3](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.3)
- [Docker Model Runner v1.1.37](https://github.com/docker/model-cli/releases/tag/v1.1.37)
- [credential helpers v0.9.6](https://github.com/docker/docker-credential-helpers/releases/tag/v0.9.6)

### Security

- The Extensions settings page now includes a security notice that extensions run with host-level privileges and are not audited by Docker.
- [Fixed CVE-2026-31431 ("copy.fail")](https://xint.io/blog/copy-fail-linux-distributions) by backporting an upstream Linux kernel patch that prevents an unprivileged container user from gaining root inside the container via a controlled write into the host VM page cache.

### Bug fixes and enhancements

#### For all platforms

- Improvements to Docker Offload idle notifications.
- Fixed the **Open Gordon in TUI**  button not working due to a missing `run` subcommand in Docker Agent command arguments.
- Fixed an issue where transient network errors or Docker Hub server errors during sign-in would unexpectedly sign users out instead of retrying automatically.
- Improved data refresh for the Containers, Images, and Volumes screens by fetching up-to-date data on demand when navigating to those screens, reducing background polling load.
- Fixed a kernel crash that could occur when changing filesharing technology after significant container file activity.
- Enable the OpenAI Responses API (`/responses`) endpoint in Docker Model Runner.
- Fixed a bug where users were unexpectedly signed out of Docker Desktop mid-flow when signing in via `docker login` using OAuth.

#### For Windows

- Fixed a bug on Windows where selecting the Docker Desktop taskbar icon multiple times could spawn multiple backend processes. Re-selecting the icon while Docker Desktop is running now brings the dashboard to focus.
- Fixed a race condition on Windows that caused a false-positive "processes still running" dialog to appear when Docker Desktop starts or exits normally.

### For Linux

- Support for RHEL 8 has been dropped.

## 4.71.0

{{< release-date date="2026-04-27" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.71.0" build_path="/225177/" >}}

> [!IMPORTANT]
>
> Support for RHEL 8 has ended. Installing Docker Desktop will require RHEL 9 or RHEL 10 in the next release.

### Updates

- [Docker Model Runner v1.1.36](https://github.com/docker/model-runner/releases/tag/v1.1.36)
- [containerd to v2.2.3](https://github.com/containerd/containerd/releases/tag/v2.2.3)
- [Runc v1.3.5](https://github.com/opencontainers/runc/releases/tag/v1.3.5)
- [Docker Compose v5.1.3](https://github.com/docker/compose/releases/tag/v5.1.3)
- [Docker Agent v1.44.0](https://github.com/docker/docker-agent/releases/tag/v1.44.0)
- [Docker Engine v29.4.1](../engine/release-notes/29.md#2941)

### Bug fixes and enhancements

#### For all platforms

- Docker Model Runner is now disabled by default and must be explicitly enabled in **Settings**. When enabled, TCP host-side support is automatically active.
- Fixed an issue where downloading a Docker Desktop update would fail without a clear error if the disk had insufficient free space.
- Fixed an issue where Docker Scout tag recommendations, when inspecting an image, failed when the base image digest or repository name was empty.
- Added a **Switch to local Docker context** button on the sign-in screen, allowing users in a cloud context to switch back to their local context without signing in.
- Added a dedicated **Stopped** status screen for the cloud engine so users see a clear stopped state instead of an error screen when transitioning away from Docker Offload.

#### For Mac

- Fixed an issue where error tracking would temporarily continue sending session data directly after a user disabled analytics. Fixes [docker/for-mac#7768](https://github.com/docker/for-mac/issues/7768).

#### For Windows

- Fixed a critical issue where Docker Desktop Dashboard failed to open with `ERR_FAILED` errors caused by process hardening policies conflicting with Chromium.
- Fixed a bug where Kubernetes could fail to start on WSL 2 when `HTTP_PROXY` environment variables are set in WSL 2 itself.
- Fixed a bug in Enhanced Container Isolation (ECI) that was causing loss of container `rootfs` persistence across Docker Desktop restarts, when using WSL.

### Security

- Addressed [CVE-2026-5843](https://www.cve.org/cverecord?id=CVE-2026-5843), container-to-host code execution in the Docker Model Runner MLX inference backend via MLX-LM `model_file` importlib loading.

## 4.70.0

{{< release-date date="2026-04-20" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.70.0" build_path="/224270/" >}}

### New

- Added a CLI hint that surfaces the **Logs** view when running `logs`, `compose logs`, `compose attach`, or `compose up` commands, giving you quick access to logs across all running containers. Available with the **Logs** (Beta) feature enabled.

### Updates

- [Docker Compose v5.1.2](https://github.com/docker/compose/releases/tag/v5.1.2)
- [Docker Engine v29.4.0](../engine/release-notes/29.md#2940)
- [Docker Agent v1.43.0](https://github.com/docker/docker-agent/releases/tag/v1.43.0)
- [Docker Model Runner v1.1.33](https://github.com/docker/model-runner/releases/tag/v1.1.33)
- [Docker Scout CLI v1.20.4](https://github.com/docker/scout-cli/releases/tag/v1.20.4)

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where `docker login` could fail silently in CI environments due to slow Docker Hub responses causing credential store update timeouts.
- Fixed an issue where disabling Beta features also disabled Docker Model Runner.
- Fixed `docker desktop start` causing the Docker AI agent API daemon to fail due to an inherited CLI plugin environment variable.

#### For Mac

- Fixed a crash loop where Docker Desktop repeatedly failed to start with exit status `42` after an update due to a corrupted `DockerAppLaunchPath` setting.
- Fixed an issue where a failed update could leave Docker Desktop in a broken state. The installer now automatically reverts to the previous version and shows a clear error message.
- Fixed a bug where stopping one container could disrupt active Unix socket forwards belonging to other running containers.

#### For Windows

- Fixed an issue where a failed update could leave Docker Desktop in a broken state. The installer now automatically reverts to the previous version and shows a clear error message.
- Fixed a bug where a failed switch to Windows containers could leave Docker Desktop in a broken state, requiring a restart.
- Fixed an issue where Docker Desktop failed to launch for users with `DEVHOME` set in their environment.
- Temporarily rolled back process hardening that caused Electron crashes on Windows. Fixes [docker/desktop-feedback#245](https://github.com/docker/desktop-feedback/issues/245).

## 4.69.0

{{< release-date date="2026-04-13" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.69.0" build_path="/224084/" >}}

### Updates

- [Docker Agent v1.42.0](https://github.com/docker/docker-agent/releases/tag/v1.42.0)
- [Docker Model v1.1.29](https://github.com/docker/model-runner/releases/tag/v1.1.29)
- [containerd v2.2.2](https://github.com/containerd/containerd/releases/tag/v2.2.2)
- [Docker Buildx v0.33.0](https://github.com/docker/buildx/releases/tag/v0.33.0)

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where `docker logout` from the CLI was ignored by Docker Desktop when OAuth tokens remained in the credential store, leaving the user unexpectedly signed in.
- Fixed an issue where Docker Desktop could unexpectedly sign users out when unrelated credential updates, `docker login`, or transient network errors triggered a sign-out.
- Fixed a data loss issue where backup data could be deleted during a failed restore operation, leaving users with no data.
- Fixed an issue where sign-in credentials (`login-info.json`) could be included in diagnostic bundles, improving privacy and security. Note that this file contains an encoded organisation(s) name, plan name, encoded username, and encoded email only. No passwords or credentials are included.
- Fixed the footer update label incorrectly showing **Downloading** during the prepare/unpack phase of an update. It now correctly displays **Preparing**.
- Fixed an issue where Docker Desktop would not start when the internal storage disk was full.

#### For Mac

- Fixed an issue where the in-app update button was not disabled when `Docker.app` was installed in a non-user-writable directory, preventing failed update attempts.
- Fixed update failure for users who installed Docker Desktop via Homebrew on Mac.

#### For Windows

- Fixed an unexpected WSL terminal popup appearing for Windows users using the Hyper-V backend during Docker Desktop installation or uninstallation.
- Fixed an issue on Windows where factory reset deleted CLI plugins from `~/.docker/cli-plugins`, causing `docker build` to fall back to the legacy builder.
- Fixed a bug where Kubernetes failed to start when WSL integration was enabled alongside another distro using cgroup v1 controllers.
- Fixed a race condition that caused Kubernetes to fail to start when a Registry Access Management policy change occurred during startup.
- Prevent Docker Desktop from fatally failing due to transient 'Access is denied' errors during file operations on Windows.

## 4.68.0

{{< release-date date="2026-04-07" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.68.0" build_path="/223695/" >}}

### New

- Gordon now has persistent local memory, allowing it to remember your preferences and context across sessions.

### Updates

- [Docker Agent v1.39.0](https://github.com/docker/docker-agent/releases/tag/v1.39.0)
- [Docker Model v1.1.28](https://github.com/docker/model-runner/releases/tag/v1.1.28)
- Docker Offload v0.5.81

### Bug fixes and enhancements

#### For all platforms

- Fixed a deadlock in Enhanced Container Isolation that caused containers to hang indefinitely during creation when ECI was enabled.
- Added a warning banner to alert when an MCP server is community-provided and has not been verified by Docker.
- Added a persistent **Show timestamps** toggle to the **Logs** view, allowing timestamps to be hidden in both table and visualiser views across sessions.
- Fixed an issue where Docker Desktop frontend processes were not properly terminated on quit.
- Fixed a deadlock when settings controlled by admins reload that could cause Docker Desktop to become unresponsive during sign in or sign out operations.
- Fixed a bug where Docker Desktop could fail to start due to uncorrectable filesystem errors on the disk image not being repaired.
- Fixed a bug that caused Enhanced Container Isolation (ECI) to inadvertently block startup of Kubernetes clusters.
- Fixed an issue where a failed volume size fetch could make the **Volumes** view inaccessible; container counts on volumes now correctly exclude bind mounts.
- Fixed race conditions in volume backup that could cause containers to be incorrectly restarted, export logs to be corrupted, or runtime panics when scheduling tasks.
- Fixed a crash in the API cache that occurred when containers with no names caused a panic disrupting container listing.
- Fixed a bug where starting a container could fail with `ENOENT` if a bind-mount parent directory was deleted while no container was using it.

#### For Mac

- Fixed a security vulnerability where tampered user-deployed config profiles could bypass organization sign-in enforcement.
- Fixed a bug where a failed `vmnetd` handshake could dispatch a bogus command on a broken connection, causing unexpected networking errors.
- Fixed a bug where the Docker Desktop Dashboard could be prematurely displayed when restoring to a fullscreen state on launch.
- Fixed nested bind mounts showing empty child mount content on VirtioFS when using Docker Compose with multiple services sharing a volume. Fixes [docker/desktop-feedback#264](https://github.com/docker/desktop-feedback/issues/264).

#### For Windows

- Fixed an issue where the installer extraction did not update the progress bar and could take around 5 minutes, depending on the machine. Extraction is now ~60% faster and includes proper progress updates.
- Fixed a race condition where container ports would sometimes not be published correctly after container start, affecting ephemeral ports, `--publish-all`, and gateway IP bindings.
- Fixed an issue where a failed WSL distro move could leave the distro unregistered.

### Security

- Addressed [CVE-2026-5817](https://www.cve.org/cverecord?id=CVE-2026-5817), container-to-host code execution in the Docker Model Runner vllm-metal inference backend via unsandboxed `trust_remote_code` tokenizer loading.

## 4.67.0

{{< release-date date="2026-03-30" >}}

### New

- Docker MCP Toolkit now has MCP profile template cards and an onboarding tour accessible via the **Profiles** tab.

### Updates

- [Docker Compose v5.1.1](https://github.com/docker/compose/releases/tag/v5.1.1)
- [Docker Agent v1.34.0](https://github.com/docker/docker-agent/releases/tag/v1.34.0)
- [Docker Scout CLI v1.20.3](https://github.com/docker/scout-cli/releases/tag/v1.20.3)
- [Docker Model v1.1.25](https://github.com/docker/model-runner/releases/tag/v1.1.25)

### Bug fixes and minor changes

#### For all platforms

- Docker Model Runner now supports Qwen3.5.
- With the new **Logs (Beta)** view, you can now filter container logs by Compose stack.
- Improved interaction with **Settings** while the Docker engine or Kubernetes is starting or stopping.
- Fixed a bug where random UDP port bindings reported port `0` instead of the actual assigned port.
- Fixed an issue with the Docker Desktop shortcut not reopening the Dashboard when Docker Desktop was already running.
- Fixed an issue where the **Add to existing profile** dialog showed profiles that already contained all selected MCP servers in the dropdown.

#### For Mac

- Fixed intermittent `exec format error` when starting amd64 containers on Apple Silicon Macs due to a race condition between Rosetta `binfmt` registration and `virtiofs` device availability.

#### For Windows

- Fixed Hyper-V being silently re-enabled on every EXE upgrade for WSL 2 users.
- Fixed an MSI installer bug where Docker Desktop processes could be left running after uninstall.
- Fixed an issue on Windows where installations or updates using `--installation-dir` would fail due to the installer archive being extracted into the custom installation directory.
- Improved Docker Desktop startup time on Windows by several seconds when using WSL 2.
- Fixed a bug on the **Models** > **Logs** screen which caused `docker-model` processes to accumulate on Windows each time the screen was visited.

### Security

- Addressed [CVE-2026-33990](https://www.cve.org/cverecord?id=CVE-2026-33990), SSRF in Docker Model Runner OCI Registry Client

## 4.66.1

{{< release-date date="2026-03-26" >}}

### Updates

- [Docker Engine v29.3.1](../engine/release-notes/29.md#2931)

## 4.66.0

{{< release-date date="2026-03-23" >}}

### Updates

- [Docker Engine v29.3.0](https://docs.docker.com/engine/release-notes/29/#2930)
- [NVIDIA Container Toolkit v1.19.0](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.19.0)

### Bug fixes and minor changes

#### For all platforms

- Gordon improvements:
   - Provides pre-filled prompts when deeplinking from command-line failure hints.
   - Prevents Docker Hub rate limiting by authenticating before making requests.
- Fixed a Kubernetes pod discovery hang when the kube context is broken or unreachable.
- Fixed a terminal crash caused by an undefined dimensions error during terminal resize.
- Fixed volume backup export error handling for file, image, and registry export operations.

#### For Windows

- Fixed high CPU usage in the Windows API proxy caused by unnecessary process enumeration.
- Fixed the Windows MSI installer failing to update Docker Desktop. Versions between 4.56 and 4.65 need to uninstall before reinstalling version 4.66 or later. Note that uninstalling removes all associated data.

## 4.65.0

{{< release-date date="2026-03-16" >}}

### New

- Added a new **Logs** view where you can explore logs from all sources in one unified view. (Beta)
- Gordon hints now appear when `docker build`, `docker run`, or `docker compose` commands fail, offering contextual suggestions.
- Community MCP servers now support OAuth authentication directly in the UI.
- Added the [`docker dhi` CLI plugin](https://github.com/docker-hardened-images/dhictl) for managing Docker Hardened Images.

### Updates

- [Docker Scout CLI v1.20.1](https://github.com/docker/scout-cli/releases/tag/v1.20.1)
- [Docker Agent v1.29.0](https://github.com/docker/docker-agent/releases/tag/v1.29.0)
- [Docker Buildx v0.32.1](https://github.com/docker/buildx/releases/tag/v0.32.1)

### Bug fixes and minor changes

#### For all platforms

- Kubernetes now defaults to kind for new clusters.
- Fixed update progress bar not resuming correctly.

#### For Windows 

- Improved startup time by skipping docker-users group check when using WSL2 backend.

### Known issues

- The Windows MSI installer cannot update an existing Docker Desktop installation when the current version is between 4.56 and 4.65. As a workaround, uninstall the existing version before reinstalling the latest version. Note that uninstalling removes all associated data.

## 4.64.0

{{< release-date date="2026-03-11" >}}

### Updates

- [Docker Compose v5.1.0](https://github.com/docker/compose/releases/tag/v5.1.0)
- [Docker Scout CLI v1.20.0](https://github.com/docker/scout-cli/releases/tag/v1.20.0)
- [Docker Agent v1.27.1](https://github.com/docker/docker-agent/releases/tag/v1.27.1)

### Bug fixes and minor changes

#### For all platforms

- Fixed a bug in MCP Toolkit where disabling all tools in a profile would enable all tools.
- Fixed the `docker ai` command stopping after a Docker Agent update.
- Fixed Gordon session title flickering when hover buttons appeared.
- Improved Gordon summary rendering and reduced narrative verbosity.
- Fixed a bug where `docker ai` CLI commands did not correctly shell out to Docker Agent.
- Fixed the **OAuth** tab in Docker MCP Toolkit not showing entries from all catalogs.
- Improved MCP Catalog search.
- Fixed the **Build logs** tab not retaining search terms and filters when switching tabs.
- Fixed Kind container startup to be more reliable.

#### For Mac

- Improved update error reporting with more descriptive diagnostics.
- Improved update reliability by preparing the updated `Docker.app` under `Application Support` instead of `/tmp`.

### Known issues

- The Windows MSI installer cannot update an existing Docker Desktop installation when the current version is between 4.56 and 4.65. As a workaround, uninstall the existing version before reinstalling the latest version. Note that uninstalling removes all associated data. 

## 4.63.0

{{< release-date date="2026-03-02" >}}

### New

- Added SLSA v1 provenance support in the **Builds** view. 

### Updates

- [Kubernetes v1.34.3](https://github.com/kubernetes/kubernetes/releases/tag/v1.34.3)
- Linux kernel `v6.12.72`

### Bug fixes and minor changes

#### For all platforms

- Enhanced the proxy settings UI and added a separate proxy for containers.
- Fixed an issue where community registry MCP catalogs failed to load when a server's config object contained `"required": null`.
- Fixed an issue where `mcp-gateway` would hang when fetching secrets from the Secrets Engine while the Docker Desktop VM was in Resource Saver mode. 
- Rebranded "Docker AI" references to "Gordon".

#### For Windows

- Improved startup time on Windows.

### Known issues

- The Windows MSI installer cannot update an existing Docker Desktop installation when the current version is between 4.56 and 4.65. As a workaround, uninstall the existing version before reinstalling the latest version. Note that uninstalling removes all associated data. 

## 4.62.0

{{< release-date date="2026-02-23" >}}

### New

- With Docker MCP Toolkit, you can now use [profiles](../ai/mcp-catalog-and-toolkit/profiles.md) to organize your MCP servers into named collections. You can also create custom catalogs — curated collections of servers for your team or organization.

### Updates

- Linux kernel `v6.12.69`

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where background update checks did not respect the **Automatically check for updates** setting when disabled. Fixes [docker/for-mac#3908](https://github.com/docker/for-mac/issues/3908).

#### For Mac

- Added support for vLLM Metal in Docker Model Runner.

#### For Linux 

- Fixed a networking crash on QEMU 10.2.0 and later.

### Security

- Addressed [CVE-2026-2664](https://www.cve.org/cverecord?id=CVE-2026-2664), out of bounds read in grpcfuse kernel module.
- Addressed [CVE-2026-28400](https://www.cve.org/cverecord?id=CVE-2026-28400), runtime flag injection in Docker Model Runner.

### Known issues

- The Windows MSI installer cannot update an existing Docker Desktop installation when the current version is between 4.56 and 4.65. As a workaround, uninstall the existing version before reinstalling the latest version. Note that uninstalling removes all associated data.

## 4.61.0

{{< release-date date="2026-02-18" >}}

### New

- You can now customize the left-hand navigation to show only the tabs that matter to you, and hide the ones that don’t.

### Updates

- Linux kernel `v6.12.68`
- [Docker Engine v29.2.1](https://docs.docker.com/engine/release-notes/29/#2921)
- Docker Sandbox `v0.12.0`

### Bug fixes and enhancements

#### For all platforms

- Docker Sandboxes:
   - Added automated image caching to prevent re-downloading images unnecessarily.
   - Added Shell mode for blank coding agent sandboxes.
   - Added support for OpenCode.
   - Added support for mounting multiple workspaces.
   - Added experimental Linux support (single user only, UID 1000).
   - Added support for running in WSL 2.
   - Sandboxes now start in the current working directory if no path is provided.

### Known issues

- The Windows MSI installer cannot update an existing Docker Desktop installation when the current version is between 4.56 and 4.65. As a workaround, uninstall the existing version before reinstalling the latest version. Note that uninstalling removes all associated data.

## 4.60.1

{{< release-date date="2026-02-10" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.60.1" build_path="/218372/" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed a rare issue that crashed the Docker Desktop Dashboard after sign-in.

## 4.60.0

{{< release-date date="2026-02-09" >}}

### New

- Added a new `docker desktop diagnose` command to gather diagnostics.

### Bug fixes and enhancements

#### For all platforms

- Fixed `ping6 host.docker.internal`.
- Enabled landlock LSM.
- Docker Sandboxes improvements:
   - Improved agent system prompt with network access documentation      
   - Fixed Gemini API key injection  
   - Sandboxes now block `console.anthropic.com/claude.ai` in proxy default rules
   - Fix CLI help text for `run <agent> --help`
   - Improved terminal size handling

### Known issues

- The Windows MSI installer cannot update an existing Docker Desktop installation when the current version is between 4.56 and 4.65. As a workaround, uninstall the existing version before reinstalling the latest version. Note that uninstalling removes all associated data. 

## 4.59.1

{{< release-date date="2026-02-03" >}}

### Bug fixes and enhancements

#### For Mac

- Fixed an issue where CPU usage could spike at regular intervals. Fixes [docker/for-mac#7839](https://github.com/docker/for-mac/issues/7839).

## 4.59.0

{{< release-date date="2026-02-02" >}}

### Updates

- Linux kernel `v6.12.67`
- [Docker Compose v5.0.2](https://github.com/docker/compose/releases/tag/v5.0.2)
- Docker Sandbox `v0.10.1`
- [Docker Buildx v0.31.1](https://github.com/docker/buildx/releases/tag/v0.31.1)

### Bug fixes and enhancements

#### For all platforms

- Added Neo4j as a known publisher to the Docker MCP Catalog.
- Fixed an issue where the **Models** tab would crash when displaying requests made via the Anthropic Messages API.

#### For Mac

- Fixed an issue where shared file permissions could be unintentionally modified when using DockerVMM. Fixes [docker/for-mac#7830](https://github.com/docker/for-mac/issues/7830).

#### For Windows

- Fixed an issue where container secrets injection could fail with `docker-pass`.
- Temporarily disabled VHDX compaction for the WSL data disk to improve stability.

### Security

- Fixed a security issue in enhanced container isolation where Docker socket mount permissions could be bypassed when using the `--use-api-socket` flag.

## 4.58.1

{{< release-date date="2026-01-29" >}}

{{< desktop-install-v2 mac=true version="4.58.1" build_path="/217134/" >}}

### Bug fixes and enhancements

#### For Mac

- Fixed an issue where CPU usage could spike at regular intervals. Fixes [docker/for-mac#7839](https://github.com/docker/for-mac/issues/7839).

## 4.58.0

{{< release-date date="2026-01-26" >}}

### New

- A new version of [Docker Sandboxes](../ai/sandboxes/index.md) is now available on Docker Desktop. It provides a secure, isolated, microVM-based environment for running coding agents.

### Updates

- Linux kernel `v6.12.65`
- [Credential helpers v0.9.5](https://github.com/docker/docker-credential-helpers/releases/tag/v0.9.5)
- [Docker Engine v29.1.5](https://docs.docker.com/engine/release-notes/29/#2915)

### Bug fixes and enhancements

#### For all platforms

- Docker Model Runner now exposes an [Anthropic-compatible API](../ai/model-runner/api-reference.md#anthropic-compatible-api).
- Docker Desktop now supports UTF-8 BOM for `admin-settings.json` and `registry.json`.
- Fixed an issue where admin settings incorrectly changed user proxy settings after a restart.

> [!IMPORTANT]
>
> Starting with Docker Desktop version 4.59, installing an update from the tray menu will proceed without opening the Docker Desktop Dashboard.

#### For Mac

- Fixed a bug where shared file permissions could be modified inadvertently while using DockerVMM on macOS. Fixes [docker/for-mac#7830](https://github.com/docker/for-mac/issues/7830).

#### For Windows

- Fixed an issue where the installer failed because of special ACLs set on `ProgramData`.


### Security

- Updated Kubernetes images to address CVEs.
   - Kind:
      - `docker/desktop-containerd-registry-mirror:v0.0.3`
      - `docker/desktop-cloud-provider-kind:v0.5.0`
   - Kubeadm:
      - `docker/desktop-vpnkit-controller:v4.0`
      - `docker/desktop-storage-provisioner:v3.0`
- The `kind` dependency image `envoyproxy/envoy` was upgraded from v1.32.6 to v1.36.4. If you mirror `kind` images, ensure your mirrors are updated.

## 4.57.0

{{< release-date date="2026-01-19" >}}

### Security

- Fixed [CVE-2025-14740](https://www.cve.org/cverecord?id=CVE-2025-14740) where the Docker Desktop for Windows installer contained multiple incorrect permission assignment vulnerabilities in the handling of the `C:\ProgramData\DockerDesktop` directory.

### New

- Docker Desktop now has a new issue tracker for all platforms at https://github.com/docker/desktop-feedback. Relevant, actively discussed issues from the previous platform-specific trackers will be migrated.

### Updates

- [Docker Compose v5.0.1](https://github.com/docker/compose/releases/tag/v5.0.1)

### Bug fixes and enhancements

#### For all platforms

- Improved alignment of the Ask Gordon streaming indicator so it stays in sync with content on large screens.
- Fixed a bug where `docker debug` failed on containers started with environment variables but no '='. For example, `docker run -e NONEXISTENT_ENV_VAR`.

## 4.56.0

{{< release-date date="2026-01-12" >}}

### New

- Docker Desktop now includes Docker Compose v5 which introduces a new official Go SDK. This SDK provides a comprehensive API that lets you integrate Compose functionality directly into your applications, allowing you to load, validate, and manage multi-container environments without relying on the Compose CLI. For more information, see the [Compose SDK docs](../compose/compose-sdk.md).

### Updates

- [containerd v2.2.1](https://github.com/containerd/containerd/releases/tag/v2.2.1)
- [Docker Compose v5.0.0](https://github.com/docker/compose/releases/tag/v5.0.0)
- [Docker Agent v1.18.6](https://github.com/docker/docker-agent/releases/tag/v1.18.6)

### Bug fixes and enhancements

#### For all platforms

- Fixed a panic in filesharing tests when containers don't have an IP address immediately after starting.
- Added support for custom DNS entries in the LinuxKit VM with the `ExtraDNSEntries` configuration field.

#### For Windows

- Fixed a bug on Windows where removing the state directory would fail because log files were still open.
- Fixed installations from the Microsoft Store wrongly advertizing a new update.
- Fixed a crash when running `/sbin/ldconfig` in `ubuntu:22.04` ARM64 containers by upgrading QEMU from 8.1.5 to 10.0.4. This resolves a known issue reported in [docker/for-win#15004](https://github.com/docker/for-win/issues/15004).

  > [!NOTE]
  >
  > When running under ARM64 emulation, some `amd64` Go binaries built with older Go versions may still segfault. To avoid this, rebuild affected binaries using Go 1.25.4 or later. For details, see [golang/go#69255](https://github.com/golang/go/issues/69255) and the corresponding [Go commit](https://github.com/golang/go/commit/bf95b767394eb5643265f44c7b98bdbb85b897ce).

#### For Linux

- Fixed Kubernetes `hostPath` volume mounts failing on Linux hosts. Fixes [docker/desktop-linux#12](https://github.com/docker/desktop-linux/issues/12).

## 4.55.0

{{< release-date date="2025-12-16" >}}

### Updates

- [Docker Engine v29.1.3](https://docs.docker.com/engine/release-notes/29/#2913)
- [Docker Agent v1.15.1](https://github.com/docker/docker-agent/releases/tag/v1.15.1)

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue that caused Docker Desktop to get stuck during startup.
- Improved the error message when the `daemon.json` is invalid.
- Fixed performance issues on every keystroke within a long Ask Gordon session.
- Fixed an issue that prevented Kubernetes in kubeadm mode from starting up when an organization has configured Registry Access Management to block Docker Hub.

> [!IMPORTANT]
>
> Wasm workloads will be deprecated and removed in a future Docker Desktop release.

## 4.54.0

{{< release-date date="2025-12-04" >}}

### New

- Added support for vLLM in Docker Model Runner on Windows with WSL2 and NVIDIA GPUs.

### Bug fixes and enhancements

#### For Mac

- Fixed a bug where `/dev/shm` did not have enough permission for containers to write into. Fixes [docker/for-mac#7804](https://github.com/docker/for-mac/issues/7804). 

### Upgrades

- [Docker Buildx v0.30.1](https://github.com/docker/buildx/releases/tag/v0.30.1)
- [Docker Engine v29.1.2](https://docs.docker.com/engine/release-notes/29/#2912)
- [Runc v1.3.4](https://github.com/opencontainers/runc/releases/tag/v1.3.4)
- [Docker Model Runner CLI v1.0.2](https://github.com/docker/model-runner/releases/tag/cmd%2Fcli%2Fv1.0.2)

### Security 

- Added a security patch to address [CVE-2025-13743](https://www.cve.org/cverecord?id=CVE-2025-13743) where Docker Desktop diagnostics bundles were found to include expired Hub PATs in log output due to error object serialization. 

## 4.53.0

{{< release-date date="2025-11-27" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where the Support Diagnostics tooling inadvertently captured expired Docker Hub authorization bearer tokens.

### Security 

- Added security patches to address CVEs [2025-52565](https://github.com/opencontainers/runc/security/advisories/GHSA-9493-h29p-rfm2), [2025-52881](https://github.com/opencontainers/runc/security/advisories/GHSA-cgrx-mc8f-2prm), and [2025-31133](https://github.com/opencontainers/runc/security/advisories/GHSA-qw9x-cqr3-wc7r) when using [Enhanced Container Isolation](https://docs.docker.com/enterprise/security/hardened-desktop/enhanced-container-isolation). 

## 4.52.0

{{< release-date date="2025-11-20" >}}

### New

- Added new port binding settings to Docker Desktop. This can also be controlled by administrators via Settings Management using the `admin-settings.json` file.
- Added a new Docker Model Runner command. With `docker model purge` you can remove all your models.

### Upgrades

- [Docker Engine v29.0.0](../engine/release-notes/29.md#2900)
- [Docker Model Runner v1.0.3](https://github.com/docker/model-runner/releases/tag/v1.0.3)
- [Docker Model Runner CLI v1.0.0](https://github.com/docker/model-runner/releases/tag/cmd%2Fcli%2Fv1.0.0)
- Docker MCP plugin `v0.28.0`

### Bug fixes and enhancements

#### For all platforms 

- Docker MCP Toolkit improvements:
   - Amazon Q client support
   - OAuth DCR (Dynamic Client Registration) with Docker Engine
   - Create MCP profiles using the CLI
- Docker Model Runner improvements:
   - You can now skip the `/engines` prefix for [Docker Model Runner's OpenAI API endpoint](../ai/model-runner/api-reference.md#rest-api-examples) `curl http://localhost:12434/v1/models`.
   - You can now skip the `ai/` prefix for the models [published on Docker Hub with](https://hub.docker.com/u/ai) `docker model pull`.
   - Downloads are now resumed when they get interrupted.

#### For Windows

- Fixed an issue with Kerberos/NTLM proxy sign in.

## 4.51.0

{{< release-date date="2025-11-13" >}}

### New

- You can now set up your Kubernetes resources from the **Kubernetes** view. This new view also provides a real-time display of your pods, services, and deployments. 

### Upgrades

- [Docker Engine v28.5.2](../engine/release-notes/28.md#2852)
- Linux kernel `v6.12.54`

### Bug fixes and enhancements

#### For all platforms 

- Kind now only pulls required dependency images if they are not available locally.

## 4.50.0

{{< release-date date="2025-11-06" >}}

### New

- [Dynamic MCP](../ai/mcp-catalog-and-toolkit/dynamic-mcp.md)(Experimental) is now available in Docker Desktop .
- Introduced a new Welcome Survey to improve onboarding. New users can now provide information to help tailor their Docker Desktop experience.

### Upgrades

- [Docker Compose v2.40.3](https://github.com/docker/compose/releases/tag/v2.40.3)
- [NVIDIA Container Toolkit v1.18.0](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.18.0)

### Bug fixes and enhancements

#### For all platforms 

- Docker Desktop now detects and attempts to avoid clashes between the "Docker subnet" and physical networks using RFC1918 addresses. For example if the host has a non-default route which overlaps with `192.168.65.0/24` then an alternative network will be chosen automatically. You can still override the choice as before via Docker Desktop settings and admin settings.
- Docker Desktop no longer treats Stargz Snapshotter failures as fatal. If a failure occurs, Docker Desktop continues to run without the Stargz Snapshotter.
- Ask Gordon no longer displays images with user provided URLs.
- Ask Gordon now asks for confirmation before running all built-in and all user added MCP tools.

## 4.49.0

{{< release-date date="2025-10-23" >}}

> [!IMPORTANT]
>
> Support for Windows 10 21H2 (19044) and 11 22H2 (22621) has ended. Installing Docker Desktop will require Windows 10 22H2 (19045) or Windows 11 23H2 (22631) in the next release.

### Security

- Fixed [CVE-2025-9164](https://www.cve.org/cverecord?id=CVE-2025-9164) where the Docker Desktop for Windows installer was vulnerable to DLL hijacking due to insecure DLL search order. The installer searches for required DLLs in the user's Downloads folder before checking system directories, allowing local privilege escalation through malicious DLL placement.

### New 

- [Docker Agent](../ai/docker-agent/index.md) is now available through Docker Desktop. 
- [Docker Debug](/reference/cli/docker/debug/) is now free for all users. 

### Upgrades

- [Docker Engine v28.5.1](../engine/release-notes/28.md#2851)
- [Docker Compose v2.40.2](https://github.com/docker/compose/releases/tag/v2.40.2)
- [NVIDIA Container Toolkit v1.17.9](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.9)
- Docker Debug `v0.0.45` 

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where Docker Desktop used an expired proxy password while waiting for the user to enter a new one.
- Fixed a 'chown' error shown on startup with Docker Debug.
- Fixed a bug that caused some forwarded UDP ports to hang. 

#### For Mac

- Fixed Kubernetes startup hanging when another Kubernetes context was active. Fixes https://github.com/docker/for-mac/issues/7771.
- If a Rosetta install is cancelled or fails, Rosetta will be disabled in Docker Desktop.
- Minimum OS version to install or update Docker Desktop on macOS is now macOS Sonoma (version 14) or later.

## 4.48.0

{{< release-date date="2025-10-09" >}}

> [!IMPORTANT]
>
> Support for macOS 13 has ended. Installing Docker Desktop will require macOS 14 in the next release.

### New

- You can now specify PAC files and Embedded PAC scripts with installer flags for [macOS](setup/install/mac-install.md#proxy-configuration) and [Windows](setup/install/windows-install.md#proxy-configuration). 
- Administrators can set proxy settings via [macOS configuration profiles](../enterprise/security/enforce-sign-in/methods.md#macos-configuration-profiles-method-recommended). 

### Upgrades

- [Docker Compose v2.40.0](https://github.com/docker/compose/releases/tag/v2.40.0)
- [Docker Buildx v0.29.1](https://github.com/docker/buildx/releases/tag/v0.29.1)
- [Docker Engine v28.5.1](https://docs.docker.com/engine/release-notes/28/#2851)
- Docker MCP plugin `v0.22.0`
- [Docker Model CLI v0.1.42](https://github.com/docker/model-cli/releases/tag/v0.1.42)

### Bug fixes and enhancements

#### For all platforms 

- Fixed an issue where kind cluster state is sometimes reset when Desktop restarts. Fixes [docker/for-mac#77445](https://github.com/docker/for-mac/issues/7745).
- Removed the obsolete `mcp` key to align with the latest VS Code MCP server changes.
- Update credential helpers to [v0.9.4](https://github.com/docker/docker-credential-helpers/releases/tag/v0.9.4).
- Fixed an issue where Docker Desktop used an expired proxy password while waiting for the user to enter a new one. 
- Fixed a bug which caused Docker Desktop to regularly create new processes with Docker CLI tools under certain conditions. Fixes [docker/for-win#14944](https://github.com/docker/for-win/issues/14944).
- Fixed a bug which caused models to not be configured for embeddings with Docker Model Runner via Compose. To specify that a model should be configured for embeddings, you must explicitly add the `--embeddings` runtime flag as described in [AI Models in Docker Compose](https://docs.docker.com/ai/compose/models-and-compose/#model-configuration-options). Fixes [docker/model-runner#166](https://github.com/docker/model-runner/issues/166).

#### For Windows

- Removed the `HKLM\SOFTWARE\Docker Inc.\Docker\1.0` registry key. Look for `docker.exe` in the path to find out where Docker Desktop is installed instead.
- Fixed startup in WSL 2 mode when IPv6 has been disabled.

## 4.47.0

{{< release-date date="2025-09-25" >}}

### Security

- Fixed [CVE-2025-10657](https://www.cve.org/CVERecord?id=CVE-2025-10657) where the Enhanced Container Isolation [Docker Socket command restrictions](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#command-restrictions) feature was not working properly in Docker Desktop 4.46.0 only (the configuration for it was being ignored).

### New

- Added dynamic MCP server discovery and support to Docker's MCP catalog.
- With Enhanced Container Isolation, administrators can now block `docker plugin` and `docker login` commands in containers with Docker socket mounts.
- Added a new Docker Model Runner command. With `docker model requests` you can fetch requests and responses.

### Upgrades

- [Docker Compose v2.39.4](https://github.com/docker/compose/releases/tag/v2.39.4)
- [Kubernetes v1.34.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.34.1)
  - [CNI plugins v1.7.1](https://github.com/containernetworking/plugins/releases/tag/v1.7.1)
  - [cri-tools v1.33.0](https://github.com/kubernetes-sigs/cri-tools/releases/tag/v1.33.0)
  - [cri-dockerd v0.3.20](https://github.com/Mirantis/cri-dockerd/releases/tag/v0.3.20)
- Docker Debug `v0.0.44`

### Bug fixes and enhancements

#### For all platforms

- You can now search for MCP servers more easily with filters, sorting, and improved search functionality.
- Docker Debug no longer hangs when debugging containers that have environment variables set to an empty value.
- Enhanced Docker Model Runner with rich response rendering in the CLI, conversational context in the Docker Desktop Dashboard, and resumable downloads.

#### For Mac

- Removed the `com.apple.security.cs.allow-dyld-environment-variables` entitlement which allow a signed, arbitrary dynamic library to be loaded with Docker Desktop via the `DYLD_INSERT_LIBRARIES` environment variable.
- Fixed a regression where config profile sign-in enforcement broke for some customer environments.
- Fixed a bug that sometimes caused the `docker model package` command to hang when writing to the local content store (without the `--push` flag).
- Fixed a bug where containers started with the restart policy `unless-stopped` were never restarted. Fixes [docker/for-mac#7744](https://github.com/docker/for-mac/issues/7744).

#### For Windows

- Fixed the Goose MCP client connection on Windows for the Docker MCP Toolkit.
- Addressed an issue with the "Skipping integration" of a WSL distro option, after a failed integration attempt.
- Fixed a bug that sometimes caused the `docker model package` command to hang when writing to the local content store (without the `--push` flag).

## 4.46.0

{{< release-date date="2025-09-11" >}}

### New

- Added a new Learning center walkthrough for Docker MCP Toolkit and other onboarding improvements.
- Administrators can now control [PAC configurations with Settings Management](../enterprise/security/hardened-desktop/settings-management/configure-json-file.md#proxy-settings).
- The update experience has been redesigned to make it easier to understand and manage updates for Docker Desktop and its components.

### Upgrades

- [Docker Buildx v0.28.0](https://github.com/docker/buildx/releases/tag/v0.28.0)
- [Docker Engine v28.4.0](https://docs.docker.com/engine/release-notes/28/#2840)

### Bug fixes and enhancements

#### For all platforms

- With the Docker CLI, you can now set the `GODEBUG` environment variable when the key-value pair (`"GODEBUG":"..."`) exists inside the Docker context metadata. This means certificates that have negative serial numbers in the CLI binaries are supported by default.
- Updated the Docker Subscription Service Agreement link to point to the latest version.

#### For Mac

- Improved the security of Docker Model Runner by enabling sandboxing of the `llama.cpp` inference processes.
- Fixed a bug which caused Docker Desktop to start slowly and appear frozen. Fixes [docker/for-mac#7671](https://github.com/docker/for-mac/issues/7671).

#### For Windows

- Improved the security of Docker Model Runner by enabling sandboxing of the `llama.cpp` inference processes.

#### For Linux

- Fixed a path issue in the RHEL post-uninstall sequence.

## 4.45.0

{{< release-date date="2025-08-28" >}}

### New

- [Docker Model Runner](../ai/model-runner/index.md) is now generally available.

### Upgrades

- [Docker Compose v2.39.2](https://github.com/docker/compose/releases/tag/v2.39.2)
- [Docker Buildx v0.27.0](https://github.com/docker/buildx/releases/tag/v0.27.0)
- [Docker Scout CLI v1.18.3](https://github.com/docker/scout-cli/releases/tag/v1.18.3)
- [Docker Engine v28.3.3](https://docs.docker.com/engine/release-notes/28/#2833)

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug that caused the `com.docker.diagnose` to crash when uploading a diagnostics bundle behind a proxy that requires authentication.
- The `kind` dependency image `envoyproxy/envoy` was upgraded from v1.32.0 to v1.32.6. If you mirror `kind` images, ensure your mirrors are updated.

#### For Mac

- Fixed a bug that caused Docker Desktop to crash after the laptop woke from sleep. Fixes [docker/for-mac#7741](https://github.com/docker/for-mac/issues/7741).
- Fixed an issue where the VM would sometimes fail with the error **The virtual machine stopped unexpectedly.**
- Fixed a bug that would break port mappings when a container was connected to or disconnected from a network after it was started. Fixes [docker/for-mac#7693](https://github.com/docker/for-mac/issues/7693).

#### For Windows

- Fixed a bug that prevented CLI plugins from being deployed to `~/.docker/cli-plugins` by default when users lacked the correct permissions.
- Fixed a bug where relocating the WSL data distribution would fail if the `docker-desktop` distribution was not present.
- Fixed a typo in the WSL install URL in the Docker Desktop Dashboard.
- Fixed an issue where certain WSL distros would fail to integrate. Fixes [docker/for-win#14686](https://github.com/docker/for-win/issues/14686)

## 4.44.3

{{< release-date date="2025-08-20" >}}

### Security

- Fixed [CVE-2025-9074](https://www.cve.org/CVERecord?id=CVE-2025-9074) where a malicious container running on Docker Desktop could access the Docker Engine and launch additional containers without requiring the Docker socket to be mounted. This could allow unauthorized access to user files on the host system. Enhanced Container Isolation (ECI) does not mitigate this vulnerability.

### Bug fixes and enhancements

- Fixed a bug which caused the Docker Offload dialog to block users from accessing the dashboard.

## 4.44.2

{{< release-date date="2025-08-15" >}}

### Bug fixes and enhancements

 - Adds [Docker Offload](../offload/index.md) to the **Beta features** settings tab and includes updates to support [Docker Offload Beta](https://www.docker.com/products/docker-offload/).

## 4.44.1

{{< release-date date="2025-08-13" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.44.1" build_path="/201842/" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue found in version 4.44.0 that caused startup to fail when `vpnkit` CIDR is locked without specifying a value in Desktop Settings Management.

#### For Windows

- Fixed an issue where volumes and containers were not visible after an upgrade from distributions using the legacy `version-pack-data` directory structure.
- Resolved a rare issue in WSL 2 where the Docker CLI failed with a **Proxy Authentication Required** error.
- Fixed a bug where CLI plugins were not deployed to `~/.docker/cli-plugins` if the user lacked execution permissions on that directory.

## 4.44.0

{{< release-date date="2025-08-07" >}}

### New

- WSL 2 stability improvements.
- You can now inspect requests and responses to help you diagnose model-related issues in Docker Model Runner.
- Added the ability to run multiple models and receive a warning on insufficient resources. This avoids Docker Desktop freezing when using big models.
- Added new MCP clients to the MCP Toolkit: Gemini CLI, Goose.
- Introduced `--gpu` (Windows only) and `--cors` flags for `docker desktop enable model-runner`.
- Added a new `docker desktop kubernetes` command to the Docker Desktop CLI.
- You can now search for specific configuration options within **Settings**.
- Apple Virtualization is now the default VMM for better performance and QEMU Virtualization is removed. See [blog post](https://www.docker.com/blog/docker-desktop-for-mac-qemu-virtualization-option-to-be-deprecated-in-90-days/).
- Performance and stability improvements to the DockerVMM.

### Upgrades

- [Docker Compose v2.39.1](https://github.com/docker/compose/releases/tag/v2.39.1)
- [Docker Buildx v0.26.1](https://github.com/docker/buildx/releases/tag/v0.26.1)
- [Docker Engine v28.3.2](https://docs.docker.com/engine/release-notes/28/#2832)
- [Docker Scout CLI v1.18.2](https://github.com/docker/scout-cli/releases/tag/v1.18.2)
- [Docker Model CLI v0.1.36](https://github.com/docker/model-cli/releases/tag/v0.1.36)
- [Docker Desktop CLI v0.2.0](features/desktop-cli.md)

### Security

We are aware of [CVE-2025-23266](https://nvd.nist.gov/vuln/detail/CVE-2025-23266), a critical vulnerability affecting the NVIDIA Container Toolkit in CDI mode up to version 1.17.7. Docker Desktop includes version 1.17.8, which is not impacted. However, older versions of Docker Desktop that bundled earlier toolkit versions may be affected if CDI mode was manually enabled. Upgrade to Docker Desktop 4.44 or later to ensure you're using the patched version.

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue pulling images with zstd differential layers when the containerd image store is enabled.
- Fixed a bug causing containers launching  with the `--restart` flag to not restart properly when using Enhanced Container Isolation.
- Improved interaction between [Kubernetes custom registry images](use-desktop/kubernetes.md#configuring-a-custom-image-registry-for-kubernetes-control-plane-images) and Enhanced Container Isolation (ECI), so the [ECI Docker Socket image list](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md) no longer needs to be manually updated when using a custom registry for Kubernetes control plane images.
- Fixed a bug where a Docker Desktop Kubernetes cluster in kind mode fails to start after restarting Docker Desktop if the user is required to be signed in but is currently signed out.
- Fixed a bug that prevented the mounting of MCP secrets into containers when [Enhanced Container Isolation](/enterprise/security/hardened-desktop/enhanced-container-isolation/) is enabled.
- Fixed a bug preventing the use of `--publish-all` when `--publish` was already specified.
- Fixed a bug causing the **Images** view to scroll infinitely. Fixes [docker/for-mac#7725](https://github.com/docker/for-mac/issues/7725).
- Fixed a bug which caused the **Volumes** tab to be blank while in Resource Saver mode.
- Updated terms of service text on first launch.
- More robustness in parsing newly released GGUF formats.

#### For Mac

- Fixed disk corruption on DockerVMM when reclaiming disk space.
- Fixed regression since 4.42.0 on DockerVMM by re-introducing performance boost on general usage.
- Removed QEMU hypervisor and switched to Apple Virtualization as the new default. See [blog post](https://www.docker.com/blog/docker-desktop-for-mac-qemu-virtualization-option-to-be-deprecated-in-90-days/).
- Fixed a bug preventing Traefik from autodetecting containers' ports. Fixes [docker/for-mac#7693](https://github.com/docker/for-mac/issues/7693).
- Fixed a bug that caused port mappings to break when a container was connected to or disconnected from a network after it was started. Fixes [docker/for-mac#7693](https://github.com/docker/for-mac/issues/7693#issuecomment-3131427879).
- Removed eBPF which blocked `io_uring`. To enable `io_uring` in a container, use `--security-opt seccomp=unconfined`. Fixes [docker/for-mac#7707](https://github.com/docker/for-mac/issues/7707).
- Docker Model Runner now supports GPT OSS models.

#### For Windows

- Re-added `docker-users` group to the named pipe security descriptors.
- Fixed an installer crash when the current user has no `SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall` registry key.
- Fixed a bug where Docker Desktop could leak a `com.docker.build` process and fail to start. Fixed [docker/for-win#14840](https://github.com/docker/for-win/issues/14840).
- Fixed a bug that was preventing Docker Desktop Kubernetes in kind mode from starting when using WSL with `cgroups v1` and Enhanced Container Isolation (ECI) is enabled.
- Fixed a typo in the WSL installation URL in the UI.
- Docker Model Runner now supports GPT OSS models

## 4.43.2

{{< release-date date="2025-07-15" >}}

### Upgrades

- [Docker Compose v2.38.2](https://github.com/docker/compose/releases/tag/v2.38.2)
- [Docker Engine v28.3.2](https://docs.docker.com/engine/release-notes/28/#2832)
- Docker Model CLI v0.1.33

## 4.43.1

{{< release-date date="2025-07-04" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue that caused Docker Desktop UI to break when Ask Gordon responses contained HTML tags.
- Fixed an issue that prevented extensions from communicating with their backends.

## 4.43.0

{{< release-date date="2025-07-03" >}}

{{< desktop-install-v2 all=true win_arm_release="Early Access" version="4.43.0" build_path="/198134/" >}}

### New

- [Compose Bridge](../compose/bridge/index.md) is now generally available.

### Upgrades

- [Docker Buildx v0.25.0](https://github.com/docker/buildx/releases/tag/v0.25.0)
- [Docker Compose v2.38.1](https://github.com/docker/compose/releases/tag/v2.38.1)
- [Docker Engine v28.3.0](https://docs.docker.com/engine/release-notes/28/#2830)
- [NVIDIA Container Toolkit v1.17.8](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.8)

### Security

- Fixed [CVE-2025-6587](https://www.cve.org/CVERecord?id=CVE-2025-6587) where sensitive system environment variables were included in Docker Desktop diagnostic logs, allowing for potential secret exposure.

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug causing `docker start` to drop the container's port mappings for a container already running.
- Fixed a bug that prevented container ports to be displayed on the GUI when a container was re-started.
- Fixed a bug that caused Docker API `500 Internal Server Error for API route and version` error application start.
- The settings **Apply & restart** button is now labeled **Apply**. The VM is no longer restarted when applying changed settings.
- Fixed a bug where the disk would be corrupted if Docker is shutdown during a `fsck`.
- Fixed a bug causing an incorrect `~/.kube/config` in WSL2 when using a `kind` Kubernetes cluster.
- Return an explicit error to a Docker API / `docker` CLI command if Docker Desktop has been manually paused.
- Fixed an issue where unknown keys in Admin and Cloud settings caused a failure.

#### For Mac

- Removed `eBPF` which blocked `io_uring`. To enable `io_uring` in a container, use `--security-opt seccomp=unconfined`. Fixes [docker/for-mac#7707](https://github.com/docker/for-mac/issues/7707).

#### For Windows

- Fixed an issue that caused the Docker Desktop installer to crash when the current user has no `SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall` registry key.
- Fixed a bug where Docker Desktop could leak a `com.docker.build` process and fail to start. Fixes [docker/for-win#14840](https://github.com/docker/for-win/issues/14840)

### Known issues

#### For all platforms

- `docker buildx bake` will not build images in Compose files with a top-level models attribute. Use `docker compose build` instead.
- Gordon responses containing HTML can cause Desktop UI to be permanently broken. As a workaround, you can delete `persisted-state.json` file to reset the UI. The file is located in the following directories:
  - Windows: `%APPDATA%\Docker Desktop\persisted-state.json`
  - Linux: `$XDG_CONFIG_HOME/Docker Desktop/persisted-state.json` or `~/.config/Docker Desktop/persisted-state.json`
  - Mac: `~/Library/Application Support/Docker Desktop/persisted-state.json`

#### For Windows

- Possible incompatibility between the "host networking" feature of Docker Desktop and the most recent WSL 2 Linux kernel. If you encounter such issues, downgrade WSL 2 to 2.5.7.

## 4.42.1

{{< release-date date="2025-06-18" >}}

### Upgrades

- [Docker Compose v2.37.1](https://github.com/docker/compose/releases/tag/v2.37.1)

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where Docker domains were not reachable when the proxy configuration is not valid.
- Fixed a possible deadlock when exposing ports.
- Fixed a race condition which can cause `docker run -p` ports to disappear.

#### For Mac

- Fixed a bug where a container’s port list appeared empty when inspected immediately after it was created, for example, when using a script. [docker/for-mac#7693](https://github.com/docker/for-mac/issues/7693)

#### For Windows

- Disabled the Resource Saver mode in WSL 2 to prevent `docker` CLI commands hanging in WSL 2 distros. [docker/for-win#14656](https://github.com/docker/for-win/issues/14656#issuecomment-2960285463)

## 4.42.0

{{< release-date date="2025-06-04" >}}

### New

- Expanded network compatibility with IPv6 support.
- The Docker MCP Toolkit is now natively integrated into Docker Desktop.
- Docker Model Runner is now available for Windows systems running on Qualcomm/ARM GPUs.
- Added a **Logs** tab to the Models view so you can see the inference engine output in real time.
- Gordon now integrates the MCP Toolkit, providing access to 100+ MCP servers.

### Upgrades

- [Docker Buildx v0.24.0](https://github.com/docker/buildx/releases/tag/v0.24.0)
- [Docker Engine v28.2.2](https://docs.docker.com/engine/release-notes/28/#2822)
- [Compose Bridge v0.0.20](https://github.com/docker/compose-bridge-binaries/releases/tag/v0.0.20)
- [Docker Compose v2.36.2](https://github.com/docker/compose/releases/tag/v2.36.2)
- [NVIDIA Container Toolkit v1.17.7](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.7)
- [Docker Scout CLI v1.18.0](https://github.com/docker/scout-cli/releases/tag/v1.18.0)

### Bug fixes and enhancements

#### For all platforms

- Docker Desktop now accepts certificates with a negative serial number.
- Re-enable `seccomp` for containers by default. Use `docker run --security-opt seccomp=unconfined` to disable seccomp for a container.
- Fixed a bug that caused Docker Desktop to hang when it ran out of memory.
- Block `io_uring` syscalls in containers.
- Added support for pulling models from Docker Hub directly, simplifying the process of accessing and using models.
- Docker Desktop now sets the disk usage limit to the size of the physical disk on fresh install and reset to defaults on Mac and Linux.
- The maximum disk size in the settings UI now aligns with the full capacity of the host file system.
- The **Models** view now has a **Docker Hub** tab that lists models under the `ai` namespace.
- Improved the sign-in enforcement message when more than 10 organizations are enforced.
- Changed the way ports are mapped by Docker Desktop to fully support IPv6 ports.
- Fixed a bug in the Dashboard container logs screen causing the scrollbar to disappear as the mouse approaches.
- [Enforced sign-in](../enterprise/security/enforce-sign-in/index.md) fixed for Teams subscription users.
- `llama.cpp` server now supports streaming and tool calling in Model Runner.
- Sign-in Enforcement capability is now available to all subscriptions.

#### For Mac

- Fixed a bug where the disk would always have a minimum usage limit of 64GB when using Docker VMM.
- Disabled the memory protection keys mechanism in the Docker Desktop Linux VM. This caused VS Code Dev Containers to not work properly. See [docker/for-mac#7667](https://github.com/docker/for-mac/issues/7667).
- Fixed persistent volume claims under Kubernetes. Fixes [docker/for-mac#7625](https://github.com/docker/for-mac/issues/7625).
- Fixed a bug where the VM failed to start using Apple virtualization.framework.
- Minimum version to install or update Docker Desktop on is now macOS Ventura 13.3.

#### For Windows

- Fixed a bug in Enhanced Container Isolation on Windows WSL, where files with hardlinks inside containers had `nobody:nogroup` ownership.
- Fixed a bug that caused Docker Desktop to crash. Related to [docker/for-win#14782](https://github.com/docker/for-win/issues/14782).
- Fixed a bug that caused `The network name cannot be found` error when starting with WSL 2. Fixes [docker/for-win#14714](https://github.com/docker/for-win/issues/14714).
- Fixed an issue where Docker Desktop would not remove entries in the hosts file when uninstalling.
- Fixed an issue when reading auto-start registry key for some system languages. Fixes [docker/for-win#14731](https://github.com/docker/for-win/issues/14731).
- Fixed a bug where Docker Desktop was adding unrecognised /etc/wsl.conf `crossDistro` option which was causing WSL 2 to log an error. See [microsoft/WSL#4577](https://github.com/microsoft/WSL/issues/4577)
- Fixed a bug where Docker Desktop failed to start on WSL 2.5.7 if another WSL distro is still using Linux cgroups v1. Fixes [docker/for-win#14801](https://github.com/docker/for-win/issues/14801)
- Windows Subsystem for Linux (WSL) version 2.1.5 is now the minimum version required for proper functioning of Docker Desktop application

### Known issues

#### For all platforms

- This release contains a regression with  `docker port`, resulting in "No host port found for host IP" errors when using testcontainers-node. See [testcontainers/testcontainers-node#818](https://github.com/testcontainers/testcontainers-node/issues/818#issuecomment-2941575369)

#### For Windows

- Running containers with Wasm will hang sporadically. See [docker/for-mac#7666](https://github.com/docker/for-mac/issues/7666).
- On some machines Resource Saver will cause other WSL 2 distros to freeze. The workaround is to disable Resource Saver. See [docker/for-win#14656](https://github.com/docker/for-win/issues/14656).

## 4.41.2

{{< release-date date="2025-05-06" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where the `Models` menu was displayed in the GUI even when Docker Model Runner was not supported or not enabled.

## 4.41.1

{{< release-date date="2025-04-30" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where Docker Desktop failed to start when a proxy configuration was specified in the `admin-settings.json` file.

#### For Windows

- Fixed possible conflict with 3rd party tools (for example, Ollama) by avoiding placing `llama.cpp` DLLs in a directory included in the system `PATH`.

## 4.41.0

{{< release-date date="2025-04-28" >}}

### New

- Docker Model Runner is now available on x86 Windows machines with NVIDIA GPUs.
- You can now [push models](/manuals/ai/model-runner.md#push-a-model-to-docker-hub) to Docker Hub with Docker Model Runner.
- Added support for Docker Model Runner's model management and chat interface in Docker Desktop for Mac and Windows (on hardware supporting Docker Model Runner). Users can now view, interact with, and manage local AI models through a new dedicated interface.
- [Docker Compose](../ai/compose/models-and-compose.md) and Testcontainers [Java](https://java.testcontainers.org/modules/docker_model_runner/) and [Go](https://golang.testcontainers.org/modules/dockermodelrunner/) now support Docker Model Runner.
- Introducing Docker Desktop in the [Microsoft App Store](https://apps.microsoft.com/detail/xp8cbj40xlbwkx?hl=en-GB&gl=GB).

### Upgrades

- [Docker Engine v28.1.1](https://docs.docker.com/engine/release-notes/28.1/#2811)
- [Docker Compose v2.35.1](https://github.com/docker/compose/releases/tag/v2.35.1)
- [Docker Buildx v0.23.0](https://github.com/docker/buildx/releases/tag/v0.23.0)
- [Docker Scout CLI v1.17.1](https://github.com/docker/scout-cli/releases/tag/v1.17.1)
- [Compose Bridge v0.0.19](https://github.com/docker/compose-bridge-binaries/releases/tag/v0.0.19)

### Security

- Fixed [CVE-2025-3224](https://www.cve.org/CVERecord?id=CVE-2025-3224) allowing an attacker with access to a user machine to perform an elevation of privilege when Docker Desktop updates.
- Fixed [CVE-2025-4095](https://www.cve.org/CVERecord?id=CVE-2025-4095) where Registry Access Management (RAM) policies were not enforced when using a MacOS configuration profile, allowing users to pull images from unapproved registries.
- Fixed [CVE-2025-3911](https://www.cve.org/CVERecord?id=CVE-2025-3911) allowing an attacker with read access to a user's machine to obtain sensitive information from Docker Desktop log files, including environment variables configured for running containers.

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug in DockerVMM that caused an excessive number of open file handles on the host.
- Fixed an issue where Docker Desktop failed to start if the `admin-settings.json` file didn't contain the optional `configurationFileVersion` configuration.
- Fixed a bug that was causing outgoing UDP connections to be eagerly closed.
- Enhanced log reading experience with advanced search capabilities and container-level filtering, enabling quicker debugging and troubleshooting.
- Improved error messages when downloading Registry Access Management configuration.
- If Docker can't bind an ICMPv4 socket, it now logs an error and continues rather than quits.
- Enabled the memory protection keys mechanism in the Docker Desktop Linux VM, allowing containers like Oracle database images to run correctly.
- Fixed a problem with containers accessing `/proc/sys/kernel/shm*` sysctls when [Enhanced Container Isolation](../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md) is enabled on Mac, Windows Hyper-V, or Linux.
- Added kernel module `nft_fib_inet`, required for running firewalld in a Linux container.
- MacOS QEMU Virtualization option is being deprecated on July 14, 2025.

#### For Mac

- Fixed a bug that caused high CPU usage. Fixes [docker/for-mac#7643](https://github.com/docker/for-mac/issues/7643).
- Fixed multi-arch build issue with Rosetta on M3 Macs.
- Fixed an issue where absence of `/Library/Application Support/com.docker.docker/` directory can cause failure to apply RAM policy restrictions.

#### For Windows

- The Windows `.exe` installer now includes improved handling of locked files. Fixes [docker/for-win#14299](https://github.com/docker/for-win/issues/14299) and [docker/for-win#14316](https://github.com/docker/for-win/issues/14316).
- Fixed `Docker Desktop.exe` not showing version information after installation. Fixes [docker/for-win#14703](https://github.com/docker/for-win/issues/14703).

### Known issues

#### For all platforms

- If you have enforced sign-in using `desktop.plist` (on macOS) or Registry key (on Windows) and also have a `registry.json`, sign-in will fail if the user belongs to an organization listed in `desktop.plist`/ registry key but not to any organizations specified in `registry.json`. To resolve this, remove the `registry.json` file.

#### For Windows

- If multiple organizations are specified in the `allowedOrgs` Windows registry key using space-separated format, sign-in will fail and user will be logged out. As a workaround, specify each organization on a separate line in the registry key value.

## 4.40.0

{{< release-date date="2025-03-31" >}}

### New

- You can now pull, run, and manage AI models from Docker Hub directly in Docker Desktop with [Docker Model Runner (Beta)](/manuals/ai/model-runner.md). Currently available for Docker Desktop for Mac with Apple Silicon.

### Upgrades

- [Docker Buildx v0.22.0](https://github.com/docker/buildx/releases/tag/v0.22.0)
- [Docker Compose v2.34.0](https://github.com/docker/compose/releases/tag/v2.34.0)
- [Docker Engine v28.0.4](https://docs.docker.com/engine/release-notes/28/#2804)
- [Docker Scout CLI v1.17.0](https://github.com/docker/scout-cli/releases/tag/v1.17.0)
- [compose-bridge v0.0.18](https://github.com/docker/compose-bridge-binaries/releases/tag/v0.0.18)
- [NVIDIA Container Toolkit v1.17.5](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.5)

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug that caused `docker-proxy` to stop forwarding UDP datagrams to containers.
- Fixed a bug that caused docker-proxy to close UDP connections to containers eagerly and resulting in the source address to change needlessly
- Fixed a race condition that prevented Docker Desktop Kubernetes from starting in some scenarios.
- Improved the way ECI collects image digest info from a repository in environments where proxies are configured.
- Users can now to specify a timeout when generating  a private Extension Marketplace using the new `--timeout` flag.
- Removed unused internal helper tool `com.docker.admin` for Mac and Linux.

#### For Mac

- Fixed an issue where stale directory cache in Docker VMM that prevented detecting moved or new files.
- Removed Continue/Restart pop up when Time Machine utility is restricted.
- Docker Desktop now allows Unix domain sockets to be shared with containers via `docker run -v /path/to/unix.sock:/unix.sock`. The full socket path must be specified in the bind-mount. See [for-mac/#483](https://github.com/docker/for-mac/issues/483).
- Fixed a bug that caused the `docker-credential-osxkeychain` and `docker-credential-desktop` to return malformed URIs when a token was stored for a server with a port specified.

#### For Windows

- The Windows MSI and `.exe` installers now disable Windows Containers by default when installing with the GUI.
- Improved port-mapping throughput on WSL2.

### Known issues

#### For Windows

- Switching to Windows Containers while the privileged helper error message is displayed could cause inconsistent state. As a workaround, quit Docker Desktop, change `UseWindowsContainers` to `false` in `settings-store.json` and restart Docker Desktop.
- After installation, `Docker Desktop.exe` does not contain the latest version information.

## 4.39.0

{{< release-date date="2025-03-05" >}}

### New

- The [Docker Desktop CLI](features/desktop-cli.md) is now generally available. You can now also print logs with the new `docker desktop logs` command.
- Docker Desktop now supports the `--platform` flag on [`docker load`](/reference/cli/docker/image/load/) and [`docker save`](/reference/cli/docker/image/save/). This helps you import and export a subset of multi-platform images.

### Upgrades

- [Docker Compose v2.33.1](https://github.com/docker/compose/releases/tag/v2.33.1)
- [Docker Buildx v0.21.1](https://github.com/docker/buildx/releases/tag/v0.21.1)
- [Kubernetes v1.32.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.32.2)
- [Docker Engine v28.0.1](https://docs.docker.com/engine/release-notes/28/#2801)
- [Docker Scout CLI v1.16.3](https://github.com/docker/scout-cli/releases/tag/v1.16.3)

### Security

- Fixed [CVE-2025-1696](https://www.cve.org/CVERecord?id=CVE-2025-1696) which could disclose proxy authentication credentials in plaintext in log files.

### Bug fixes and enhancements

#### For all platforms

- Ask Gordon now offers deeper context on Docker images, containers, and volumes, delivers faster support, and enables more user actions via Docker Desktop and the Docker CLI.
- Support multi-platform images via enabling users to pick a specific platform in `docker history`
- Fixed an issue that caused clients other than the CLI and Docker Desktop to see a delay of 3 seconds whenever a container with port-mappings exists. See [docker/for-mac#7575](https://github.com/docker/for-mac/issues/7575)
- Fixed a bug in the ECI Docker socket permissions which caused it to sometimes block Docker socket mounts on containers with allowed images, or images derived from allowed images.
- Fixed a bug that prevented Docker Desktop from entering Resource Saver mode again immediately after an engine restart.
- Fixed an issue that caused Kubernetes clusters to stop working due to expired PKI certificates.

#### For Mac

- Downgraded Linux kernel to `v6.10.14` to fix a bug in OpenJDK that causes Java containers to terminate due to cgroups controller misidentification. See [docker/for-mac#7573](https://github.com/docker/for-mac/issues/7573).
- Added `/usr/share/misc/usb.ids` in the root mount namespace to fix `usbip`.
- Fixed an issue where the display of the CPU limit was capped at 8 when using Docker VMM.
- Fixed an issue where startup would hang and the `com.docker.backend` process consumed 100% of the CPU. See [docker/for-mac#6951](https://github.com/docker/for-mac/issues/6951).
- Fixed a bug that caused all Java programs running on M4 Macbook Pro to emit a SIGILL error. See [docker/for-mac#7583](https://github.com/docker/for-mac/issues/7583).
- Blocked startup on macOS 15.4 beta 1 since starting VMs will cause the host to crash, see https://developer.apple.com/documentation/macos-release-notes/macos-15_4-release-notes#Virtual-Machines.
- Fixed an issue where the myIPAddress PAC file function retrieved the host IP from the wrong interface, causing incorrect proxy selection.

#### For Windows

- Fixed a bug that prevented `docker compose log` to stream when running apps in WSL.
- Fixed a bug where Paketo buildpacks failed with Enhanced Container Isolation when Docker Desktop uses WSL.
- Fixed a bug where the WSL 2 integration would fail if WSL Version 1 distributions are installed.
- Fixed a bug that caused some CLI plugins update to fail if WSL distributions were enabled.
- Fixed a bug where Docker Desktop sign-in would hang when using a PAC file for proxy configuration, causing a blurred UI and blocking access.

#### For Linux

- The **Software Updates** page in settings, now points to the latest available version available.

## 4.38.0

{{< release-date date="2025-01-30" >}}

### New

- Installing Docker Desktop via the PKG installer is now generally available.
- Enforcing sign-in via configuration profiles is now generally available.
- Docker Compose, Docker Scout, the Docker CLI, and Ask Gordon can now be updated independently of Docker Desktop and without a full restart (Beta).
- The new [`update` command](/reference/cli/docker/desktop/update/) has been added to the Docker Desktop CLI (Mac only).
- [Bake](../build/bake/index.md) is now generally available, with support for entitlements and composable attributes.
- You can now create [multi-node Kubernetes clusters](settings-and-maintenance/settings.md#kubernetes) in Docker Desktop.
- [Ask Gordon](../ai/gordon/index.md) is more widely available. It is still in Beta.

### Upgrades

- [containerd v1.7.24](https://github.com/containerd/containerd/releases/tag/v1.7.24)
- [Docker Buildx v0.20.1](https://github.com/docker/buildx/releases/tag/v0.20.1)
- [Docker Compose v2.32.4](https://github.com/docker/compose/releases/tag/v2.32.4)
- [Docker Engine v27.5.1](https://docs.docker.com/engine/release-notes/27/#2751)
- [Docker Scout CLI v1.16.1](https://github.com/docker/scout-cli/releases/tag/v1.16.1)
- [Runc v1.2.2](https://github.com/opencontainers/runc/releases/tag/v1.2.2)
- [NVIDIA Container Toolkit v1.17.4](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.4)
- [Kubernetes v1.31.4](https://github.com/kubernetes/kubernetes/releases/tag/v1.31.4)
- Docker Debug `v0.0.38`

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where access tokens generated by the `docker login` web flow could not be refreshed by Docker Desktop.
- Fixed a bug where container creation via the Docker API using `curl` failed when [Enhanced Container Isolation](../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md) was enabled.
- Fixed a bug where the RAM policy was not refreshed after the refresh period had elapsed.
- Fixed a bug in Enhanced Container Isolation when mounting the Docker socket into a container, and then creating Docker containers with bind-mounts from within that container.
- Fixed an issue that caused a discrepancy between the GUI and the CLI, the former forcing the `0.0.0.0` HostIP in port-mappings. This caused default binding IPs configured through Engine's `ip` flag, or through the bridge option `com.docker.network.bridge.host_binding_ipv4`, to not be used.
- Fixed a bug where the `pac` setting was ignored in `admin-settings.json`.
- Build UI:
  - Added a progress status when importing a build.
  - Fixed a bug where users were unable to import builds.
  - Fixed a bug where some builders using SSH endpoints were not skipped.

#### For Mac

- Fixed a bug in Docker VMM where bind-mounts from non-root volumes would weren't working as expected.
- Fixed an issue that caused startup failures on systems without IPv6. Fixes [docker/for-mac#14298](https://github.com/docker/for-win/issues/14298).
- Fixed a bug that caused Docker Desktop to hang. See [docker/for-mac#7493](https://github.com/docker/for-mac/issues/7493#issuecomment-2568594070).
- Fixed an issue where the uninstaller would fail if the settings file is missing.
- Fixed a bug where config profiles deployed via Workspace One were ignored.

#### For Windows

- The Docker Desktop installer will now present a UAC prompt when launched.
- Fixed an issue where Docker Desktop would fail to start for data disks created with old WSL versions that shared the same identifier as other WSL distros.
- Docker Desktop now restarts when WSL integration settings are changed. This ensures proper setup of WSL integration when using Enhanced Container Isolation.

#### For Linux

- Added support for gvisor networking. Users with an incompatible version of qemu (8.x) will stay on qemu networking, and others will be migrated automatically.

### Deprecation

#### For all platforms

- Deprecated `com.docker.diagnose check|check-dot|check-hypervisordetect-host-hypervisor`.

## 4.37.2

{{< release-date date="2025-01-09" >}}

### Bug fixes and enhancements

#### For Mac

- Prevents a bug that caused Docker Desktop to not update `com.docker.vmnetd` or `com.docker.socket` to newer versions.

### Known issues

#### For Mac

- If you’re seeing a security popup about malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.37.1

{{< release-date date="2024-12-17" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue that caused the AI Catalog in Docker Hub to be unavailable in Docker Desktop.
- Fixed an issue that caused Docker Desktop to panic with `index out of range [0] with length 0` when using [Enhanced Container Isolation](../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md).

### Known issues

#### For Mac

- If you’re seeing a security popup about a malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.37.0

{{< release-date date="2024-12-12" >}}

### New

- You can now perform key operations such as starting, stopping, restarting, and checking the status of Docker Desktop directly from the [command line](features/desktop-cli.md) (Beta).
- The AI Catalog in Docker Hub is available directly through Docker Desktop.

### Upgrades

- [Docker Buildx v0.19.2](https://github.com/docker/buildx/releases/tag/v0.19.2)
- [Docker Compose v2.31.0](https://github.com/docker/compose/releases/tag/v2.31.0)
- [Docker Engine v27.4.0](https://docs.docker.com/engine/release-notes/27/#2740)
- [Docker Scout CLI v1.15.1](https://github.com/docker/scout-cli/releases/tag/v1.15.1)
- [NVIDIA Container Toolkit v1.17.2](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.2)

### Bug fixes and enhancements

#### For all platforms

- The default disk usage limit for Docker Engine in new installations is now 1TB.
- Fixed an issue where containers could not establish loopback `AF_VSOCK` connections.
- Fixed a bug where resetting default settings would also reset the CLI context.
- Fixed a bug where the Docker Desktop Dashboard would get out of sync with the Docker daemon after restarting the engine while in Resource Saver mode (Windows with WSL2 backend only) or after switching engines (macOS).
- Fixed a bug where Resource Saver mode would fail to re-engage after restarting the engine while in Resource Saver mode.
- Build UI:
  - Fixed a bug where the source file could not be found for some builds.
  - Fixed a bug where error logs were not displayed in the **Source** tab.
  - Fixed a bug where users had to scroll to the bottom for error logs in **Source** tab.
  - Fixed a bug where timestamps would be broken in the **Logs** tab.

#### For Mac

- Fixed a bug that would create certain user directories with root permission when running the uninstaller binary twice with `sudo`.

#### For Windows

- Added support for Windows on ARM using WSL 2 version 2.3.24 and later to single distribution mode on WSL 2.
- Fixed an issue where Docker Desktop would fail to start. Fixes [docker/for-win#14453](https://github.com/docker/for-win/issues/14453)

### Known issues

#### For all platforms

- Kubernetes cluster may not start if **Registry Access Manager** is enabled. As a workaround, add `registry.k8s.io` and `<geo>-docker.pkg.dev` to **Registry Access Management** policies.

#### For Mac

- If you’re seeing a security popup about a malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

### Deprecation

#### For Mac

- QEMU (Legacy) as a VMM on Apple Silicon will be removed in a future version. It is recommended that you switch to the Apple Virtualization Framework for increased performance and stability. If you encounter an issue, [contact Docker Support](https://www.docker.com/support/) or [file a GitHub issue](https://github.com/docker/for-mac/issues).
- osxfs (Legacy) will be removed in a future version. It is recommended that you switch to VirtioFS for increased performance. If you encounter an issue, [contact Docker Support](https://www.docker.com/support/) or [file a GitHub issue](https://github.com/docker/for-mac/issues).

## 4.36.1

{{< release-date date="2025-01-09" >}}

### Bug fixes and enhancements

#### For Mac

- Prevents a bug that caused Docker Desktop to not update `com.docker.vmnetd` or `com.docker.socket` to newer versions.

### Known issues

#### For Mac

- If you’re seeing a security popup about malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.36.0

{{< release-date date="2024-11-18" >}}

### New

- Existing Docker Desktop installations using the WSL2 engine on Windows are now automatically migrated to a unified single-distribution architecture for enhanced consistency and performance.
- Administrators can now:
  - Enforce sign-in with macOS [configuration profiles](../enterprise/security/enforce-sign-in/methods.md#configuration-profiles-method-mac-only) (Early Access).
  - Enforce sign-in for more than one organization at a time (Early Access).
  - Deploy Docker Desktop for Mac in bulk with the [PKG installer](../enterprise/enterprise-deployment/pkg-install-and-configure.md) (Early Access).
  - Use Desktop Settings Management to manage and enforce defaults via admin.docker.com (Early Access).
- Enhance Container Isolation (ECI) has been improved to:
  - Allow admins to [turn off Docker socket mount restrictions](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#allowing-all-containers-to-mount-the-docker-socket).
  - Support wildcard tags when using the [`allowedDerivedImages` setting](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#docker-socket-mount-permissions-for-derived-images).

### Upgrades

- [Docker Buildx v0.18.0](https://github.com/docker/buildx/releases/tag/v0.18.0)
- [Docker Compose v2.30.3](https://github.com/docker/compose/releases/tag/v2.30.3)
- [Kubernetes v1.30.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.30.5)
- [NVIDIA Container Toolkit v1.17.0](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.17.0)
- [Docker Scout CLI v1.15.0](https://github.com/docker/scout-cli/releases/tag/v1.15.0)
- Docker Init v1.4.0
- Linux kernel `v6.10.13`

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where the `docker events` command would not terminate after streaming the events.
- Docker Init: Improved Dockerfile caching for PHP applications that don't use Docker Compose.
- Synchronized file shares now respects the `filesharingAllowedDirectories` setting in `admin-settings.json`.
- Fixed an issue where if Docker Desktop is configured to use a proxy, it fails to start due to an internal timeout while fetching authentication tokens.
- Added a recovery banner to retry an update if the download failed.
- Fixed an issue where if the `umask` is set to `577` it would cause `rpmbuild` failure. Fixes [docker/for-mac#6511](https://github.com/docker/for-mac/issues/6511).
- Fixed a bug that restricted containers using `--network=host` to 18 open host ports.
- Fixed bind mount ownership for non-root containers. Fixes [docker/for-mac#6243](https://github.com/docker/for-mac/issues/6243).
- Docker Desktop will not unpause automatically after a manual pause. The system will stay paused until you manually resume the Docker engine. This fixes a bug where other software would accidentally trigger a resume by running a CLI command in the background. Fixes [for-mac/#6908](https://github.com/docker/for-mac/issues/6908)
- Build UI:
  - The **Source** tab now supports multiple source files.
  - Links for image dependencies in the **Info** tab now support other well-known registries such as GitHub, Google, and GitLab.
  - Disabled the **Delete** button if only cloud builds are selected.
  - Fixed an issue where users were unable to delete builds.
  - Fixed malformed Jaeger traces that were missing events and links.
  - Fixed missing export attributes when building with the cloud driver.

#### For Mac

- Fixed a bug in Docker VMM that prevented MySQL and other databases containers to start. Fixes reports from [docker/for-mac#7464](https://github.com/docker/for-mac/issues/7464).
- The minimum memory requirement is now automatically adjusted for Docker VMM, improving the user experience and addressing reports from [docker/for-mac#7464](https://github.com/docker/for-mac/issues/7464), [docker/for-mac#7482](https://github.com/docker/for-mac/issues/7482).
- Fixed a bug where the advanced option **Allowed privileged port mapping** was not working as expected. Fixes [docker/for-mac#7460](https://github.com/docker/for-mac/issues/7460).
- Docker Desktop can now automatically configure shell completion scripts for zsh, bash and fish inside the install wizard and settings screen.
- Fixed a bug where the in-app update would fail if Docker Desktop was installed by a non-admin user or if the current user was previously an administrator. Fixes [for-mac/#7403](https://github.com/docker/for-mac/issues/7403) and [for-mac/#6920](https://github.com/docker/for-mac/issues/6920)

#### For Windows

- Fixed a bug preventing UDP port 53 to be bound.
- Fixed a bug where Windows daemon options were overwritten at startup.

## 4.35.2

{{< release-date date="2025-01-09" >}}


### Bug fixes and enhancements

#### For Mac

- Prevents a bug that caused Docker Desktop to not update `com.docker.vmnetd` or `com.docker.socket` to newer versions.

### Known issues

#### For Mac

- If you’re seeing a security popup about malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.35.1

{{< release-date date="2024-10-30" >}}

#### For all platforms

- Fixed a bug where Docker Desktop would incorrectly bind to port `8888`. Fixes [docker/for-win#14389](https://github.com/docker/for-win/issues/14389) and [docker/for-mac#7468](https://github.com/docker/for-mac/issues/7468)

## 4.35.0

{{< release-date date="2024-10-24" >}}

### New

- Support for [Docker Desktop on Red Hat Enterprise Linux](setup/install/linux/rhel.md) is now generally available.
- Volume Backup and Share is now generally available and can be found in the **Volumes** view.
- Terminal support within Docker Desktop using system shells is now generally available.
- Beta release of Docker VMM - the more performant alternative to Apple Virtualization Framework on macOS (requires Apple Silicon and macOS 12.5 or later).

### Upgrades

- [containerd v1.7.21](https://github.com/containerd/containerd/releases/tag/v1.7.21)
- [Docker Buildx v0.17.1](https://github.com/docker/buildx/releases/tag/v0.17.1)
- [Docker Compose v2.29.7](https://github.com/docker/compose/releases/tag/v2.29.7)
- [Docker Engine v27.3.1](https://docs.docker.com/engine/release-notes/27/#2731)
- [Docker Scout CLI v1.14.0](https://github.com/docker/scout-cli/releases/tag/v1.14.0)
- Docker Debug `v0.0.37`
- Linux kernel `v6.10.9`

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where proxy settings in `daemon.json` would override proxies set in Docker Desktop settings.
- Fixed a bug where some Docker subnet ranges were not able to be used.
- Removed [docker-index](https://github.com/docker/index-cli-plugin) as it is now deprecated, you can use `docker scout cves fs://<path to binary>` instead.
- Fixed a bug where images couldn't be sorted or filtered by tag. Fixes [docker/for-win#14297](https://github.com/docker/for-win/issues/14297).
- Fixed a bug where the `docker` CLI did not work as expected when the `registry.json` file was malformed.
- Fixed a bug where the **Push to Docker Hub** action in the **Images** view would result in an `invalid tag format` error. Fixes [docker/for-win#14258](https://github.com/docker/for-win/issues/14258).
- Fixed an issue where Docker Desktop startup failed when ICMPv6 setup was not successful.
- Added drivers that allow USB/IP to work.
- Fixed a bug in Enhanced Container Isolation (ECI) [Docker socket mount permissions for derived images](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md) where it was incorrectly denying Docker socket mounts for some images when Docker Desktop uses the containerd image store.
- Enable `NFT_NUMGEN`, `NFT_FIB_IPV4` and `NFT_FIB_IPV6` kernel modules.
- Build UI:
  - Highlight build check warnings in the **Completed builds** list.
  - Improve visualization for the build time charts.
  - Image tags added to **Build results** section under the **Info** tab.
- Improved efficiency of host-side disk utilization for fresh installations on Mac and Linux.
- Fixed a bug that prevented the Sign in enforcement popup to be triggered when token expires.
- Fixed a bug where containers would not be displayed in the GUI immediately after signing in when using [enforced sign-in](../enterprise/security/enforce-sign-in/index.md).
- `settings.json` has been renamed to `settings-store.json`
- The host networking feature no longer requires users to be signed-in in order to use it.

#### For Mac

- Fixed a bug where auto-start containers could be misconfigured after changing filesharing type in settings.
- Fixed a bug that would cause `~/.docker/cli-plugins` to not be populated on start-up.
- Fixed a bug that prevented php composer or postgres to start as non root user. Fixes [docker/for-mac#7415](https://github.com/docker/for-mac/issues/7415).
- Fixed a bug that could cause file changed on the host to appear truncated. Fixes [docker/for-mac#7438](https://github.com/docker/for-mac/issues/7438).

#### For Windows

- New installations of Docker Desktop for Windows now require a Windows version of 19045 or later.
- Fixed an issue that caused a start failure if IPv6 is disabled either in the kernel config or via the kernel command-line in WSL. Fixes [docker/for-win#14240](https://github.com/docker/for-win/issues/14240)
- Fixed the **Clean / Purge data** button on Windows. Fixes [docker/for-win#12650](https://github.com/docker/for-win/issues/14308).
- Disk usage statistics is now displayed in the Dashboard footer installations.
- Improved recovery for WSL distribution issues.

#### For Linux

- Ubuntu 24.04 is now supported on Docker Desktop.

### Known issues

#### For Mac

- Since version 4.34.0, the toggle "Allow privileged port mapping" in the Advanced settings does not work. For more information, see [docker/for-mac#7460](https://github.com/docker/for-mac/issues/7460).

#### For Windows

- Users with versions 4.14.0 and earlier could encounter issues using the in-app update. To update to the latest version, download and install the latest Docker Desktop from this page.

## 4.34.4

{{< release-date date="2025-01-09" >}}

### Bug fixes and enhancements

#### For Mac

- Prevents a bug that caused Docker Desktop to not update `com.docker.vmnetd` or `com.docker.socket` to newer versions.

### Known issues

#### For Mac

- If you’re seeing a security popup about malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.34.3

{{< release-date date="2024-10-09" >}}

{{< desktop-install-v2 all=true win_arm_release="Beta" version="4.34.3" build_path="/170107/" >}}

### Upgrades

- [NVIDIA Container Toolkit v1.16.2](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.16.2)

### Security

- Fixed [CVE-2024-9348](https://www.cve.org/cverecord?id=CVE-2024-9348) which allows RCE via image build details source information
- Fixed NVIDIA Container Toolkit [CVE-2024-0132](https://nvidia.custhelp.com/app/answers/detail/a_id/5582)
- Fixed NVIDIA Container Toolkit [CVE-2024-0133](https://nvidia.custhelp.com/app/answers/detail/a_id/5582)

## 4.34.2

{{< release-date date="2024-09-12" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where `docker compose up` would become unresponsive while in Resource Saver mode.

### Security

- Fixed [CVE-2024-8695](https://www.cve.org/cverecord?id=CVE-2024-8695) which allows RCE via crafted extension description/changelog which could be abused by a malicious extension.
- Fixed [CVE-2024-8696](https://www.cve.org/cverecord?id=CVE-2024-8696) which allows RCE via crafted extension publisher-url/additional-urls which could be abused by a malicious extension.

## 4.34.1

{{< release-date date="2024-09-05" >}}

{{< desktop-install-v2 win=true win_arm_release="Beta" version="4.34.1" build_path="/166053/" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed a bug where Docker Desktop failed to start (often on first boot) incorrectly believing another instance of the application is running. ([docker/for-win#14294](https://github.com/docker/for-win/issues/14294) and [docker/for-win#14034](https://github.com/docker/for-win/issues/14034)).

## 4.34.0

{{< release-date date="2024-08-29" >}}

### New

- [Host networking](../engine/network/drivers/host.md#docker-desktop) support on Docker Desktop is now generally available.
- If you authenticate via the CLI, you can now authenticate through a browser-based flow, removing the need for manual PAT generation.
- Windows now supports automatic reclamation of disk space in Docker Desktop for WSL2 installations [using a managed virtual hard disk](features/wsl/best-practices.md).
- Deploying Docker Desktop via the [MSI installer](../enterprise/enterprise-deployment/msi-install-and-configure.md) is now generally available.
- Two new methods to [enforce sign-in](../enterprise/security/enforce-sign-in/index.md) (windows registry key and `.plist` file) are now generally available.
- Fresh installations of Docker Desktop now use the containerd image store by default.
- [Compose Bridge](../compose/bridge/index.md) (Experimental) is now available from the Compose file viewer. Easily convert and deploy your Compose project to a Kubernetes cluster.

### Upgrades

- [Docker Engine v27.2.0](https://docs.docker.com/engine/release-notes/27.2/#2720)
- [Docker Compose v2.29.2](https://github.com/docker/compose/releases/tag/v2.29.2)
- [containerd v1.7.20](https://github.com/containerd/containerd/releases/tag/v1.7.20)
- [Docker Scout CLI v1.13.0](https://github.com/docker/scout-cli/releases/tag/v1.13.0)
- [Docker Buildx v0.16.2](https://github.com/docker/buildx/releases/tag/v0.16.2)
- Linux kernel `v6.10.1`

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug that caused the CLI to become idle when a container was started with AutoRemove (`--rm`) but whose port bindings would be rejected by Docker Desktop at start-up.
- Fixed a bug where diagnostics collection would fail sporadically on the **Support** screen.
- Fixed a bug where folders wouldn't expand in a container's **File** tab. Fixes [docker/for-win#14204](https://github.com/docker/for-win/issues/14204).
- In-app updates now respect the proxy settings.
- Extended the ECI Docker socket mount permissions feature to optionally child images derived from allowed images. This allows ECI to work with buildpacks (e.g., Paketo) that create ephemeral local images that use Docker socket mounts.
- Fixed a bug that caused the **Containers** view to flash when using certain proxy settings. Fixes [docker/for-win#13972](https://github.com/docker/for-win/issues/13972).
- Improved the output of `docker image list` to show multi-platform-related image information.

#### For Mac

- Fixed a bug where a `Partial repair error` would occasionally appear when triggering the Configuration integrity check feature.
- Configuration integrity check feature now shows information on why the Docker socket is mis-configured.
- Fixed an issue where the Configuration integrity check feature would report the system path instead of the user path if Docker Desktop is installed as `User`.
- Fixed a bug where applications trying to read extended attributes from bind mounted volumes could experience failures. Fixes [docker/for-mac#7377](https://github.com/docker/for-mac/issues/7377).

#### For Windows

- Fixed a bug where Docker Desktop would reset docker's `credsStore` to `desktop` when the user's intention is to keep it empty. Fixes [docker/for-win#9843](https://github.com/docker/for-win/issues/9843).
- Fixed a bug that would cause Docker Desktop to not start in the WSL2 engine  [docker/for-win#14034](https://github.com/docker/for-win/issues/14034).
- Fixed a bug that caused WSL distribution to terminate abruptly. Fixes [docker/for-win/14230](https://github.com/docker/for-win/issues/14230).
- Fixed an issue that caused WSL to update in each startup. Fixes [docker/for-win/13868](https://github.com/docker/for-win/issues/13868), [docker/for-win/13806](https://github.com/docker/for-win/issues/13806).

### Known issues

- Compose Bridge does not work automatically when you enable it within the **Experimental** settings tab.  It takes a few minutes before you are notified that you must 'repair' Docker Desktop which then installs the `compose-bridge` binary.
- The **Convert and Deploy** button in the Compose file viewer  might be disabled even when Kubernetes is running and Compose Bridge is enabled. The workaround for this is to disable Compose Bridge in the **Experimental** settings tab, apply the change with **Apply & restart**, then re-enable and select **Apply & restart** again.
- There is a known issue when authenticating against a registry in the Docker CLI (`docker login [registry address]`) where, if the provided registry address includes a repository/image name (such as `docker login index.docker.io/docker/welcome-to-docker`), the repository part (`docker/welcome-to-docker`) is not normalized and results in credentials being stored incorrectly, which causes subsequent pulls from the registry (`docker pull index.docker.io/docker/welcome-to-docker`) to not be authenticated. To prevent this, don't include any extraneous suffix in the registry address when running `docker login`.
  > [!NOTE]
  > Using `docker login` with an address that includes URL path segments is not a documented use case and is considered unsupported. The recommended usage is to specify only a registry hostname, and optionally a port, as the address for `docker login`.
- When running `docker compose up` and Docker Desktop is in the Resource Saver mode, the command is unresponsive. As a workaround, manually exit the Resource Saving mode and Docker Compose becomes responsive again.
- When [Enhanced Container Isolation (ECI)](../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md) is enabled, Docker Desktop may not enter Resource Saver mode. This will be fixed in a future Docker Desktop release.
- The new [ECI Docker socket mount permissions for derived images](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#docker-socket-mount-permissions-for-derived-images) feature does not yet work when Docker Desktop is configured with the  **Use containerd for pulling and storing images**. This will be fixed in the next Docker Desktop release.

## 4.33.2

{{< release-date date="2025-01-09" >}}

### Bug fixes and enhancements

#### For Mac

- Prevents a bug that caused Docker Desktop to not update `com.docker.vmnetd` or `com.docker.socket` to newer versions.

### Known issues

#### For Mac

- If you’re seeing a security popup about malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.33.1

{{< release-date date="2024-07-31" >}}

### Bug fixes and enhancements

#### For Windows

- Added support for WSL2 2.3.11 and above, which includes loadable kernel modules. Fixes [docker/for-win#14222](https://github.com/docker/for-win/issues/14222)

## 4.33.0

{{< release-date date="2024-07-25" >}}

{{< desktop-install-v2 all=true win_arm_release="Beta" version="4.33.0" build_path="/160616/" >}}

### New

- [Docker Debug](/reference/cli/docker/debug/) is now generally available.
- BuildKit now evaluates Dockerfile rules to inform you of potential issues.
- **Resource Allocation** settings can now be accessed directly from the resource usage data displayed in the Dashboard footer.
- New and improved experience for [troubleshooting](troubleshoot-and-support/troubleshoot/index.md).

### Upgrades

- [Docker Compose v2.29.1](https://github.com/docker/compose/releases/tag/v2.29.1)
- [Docker Engine v27.1.1](https://docs.docker.com/engine/release-notes/27.1/#2711)
- [containerd v1.7.19](https://github.com/containerd/containerd/releases/tag/v1.7.19)
- [NVIDIA Container Toolkit v1.16.0](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.16.0)
- [Docker Scout CLI v1.11.0](https://github.com/docker/scout-cli/releases/tag/v1.11.0)
- [Kubernetes v1.30.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.30.2)
- Linux kernel `v6.10`

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue that caused containers started with `--net=host` and listening on an IPv6 address to be accessible from the host.
- Improved the UX for enabling the containerd image store in the **Settings** tab.
- Fixed an issue that caused a deadlock seen while using the `grpcfuse` filesharing option under heavy load.
- Fixed a bug where Mac-specific admin settings were impacting other platforms.
- IPv6 address blocks can now be specified in Docker Engine's `default-address-pools`.
- Fixed an issue with the validation of the Docker Engine's `bip`, `fixed-cidr` and `fixed-cidr-v6`. Fixes  [docker/for-mac#7104](https://github.com/docker/for-mac/issues/7104).
- Docker Engine's `default-network-opts` parameter is now properly validated.
- VirtioFS performance improvements include increasing directory cache timeout, handling change notifications from the host, removing extra FUSE operations for security.capability attributes, optimizing host event detection, and providing an API to clean caches after container termination.
- Docker Desktop now notifies when there is a port conflict in a host networking container.
- Compose Bridge command line option is now available via Experimental features. When enabled, run `compose-bridge` to convert your Compose configuration to Kubernetes resources.
- Builds view:
  - Added [build checks](../build/checks.md) to the build details' **Source** tab.
  - Added build tags to the build details' **Info** tab under the **Source details** section.
  - Newly imported builds are now highlighted.
  - Improved performance of error message handling.
  - Fixed a connection issue to the builder which prevented build records from displaying.
  - Fixed the navigation when opening builds through the CLI.

#### For Mac

- The Configuration integrity check feature now provides more context around what has changed with your Docker Desktop configuration. For more information, see the [FAQs](troubleshoot-and-support/faqs/macfaqs.md).
- The Configuration integrity check feature shows an error when it fails to repair Docker Desktop.
- Fixed a bug where the IPv6 TCP was set to `host.docker.internal`. Fixes [docker/for-mac#7332](https://github.com/docker/for-mac/issues/7332).
- Fixed an issue where the `docker-compose` symlink pointed to an empty location. Fixes [docker/for-mac#7345](https://github.com/docker/for-mac/issues/7345).

#### For Linux

- Fixed an issue where some `wincred` values were persisted after uninstall. Reported by Javier Yong [@Javiery3889](https://github.com/Javiery3889).
- Fixed an issue where the notification **Another application changed your Desktop configurations** is incorrectly triggered.

### Security

#### For all platforms

- Includes a fix for AuthZ Plugin Bypass Regression in Docker Engine. For more information, see [CVE-2024-41110](https://www.cve.org/cverecord?id=CVE-2024-41110).

#### For Windows

- Fixed an issue where some `wincred` values were persisted after uninstall. Reported by Javier Yong [@Javiery3889](https://github.com/Javiery3889).

### Known Issues

#### For Windows

- Docker Desktop fails to start with WSL pre-releases `v2.3.11.0` and `v2.3.12.0`, which is included in Windows 11 Insider. To fix this ensure WSL `v2.2.4.0` is installed.
For more information, see [microsoft/WSL#11794](https://github.com/microsoft/WSL/issues/11794). This affects Docker Desktop 4.33.0 and earlier.

## 4.32.1

{{< release-date date="2025-01-09" >}}

{{< desktop-install-v2 mac=true version="4.32.1" build_path="/179691/" >}}

### Bug fixes and enhancements

#### For Mac

- Prevents a bug that caused Docker Desktop to not update `com.docker.vmnetd` or `com.docker.socket` to newer versions.

### Known issues

#### For Mac

- If you’re seeing a security popup about malware on `com.docker.vmnetd` or `com.docker.socket`, follow the steps documented in [docker/for-mac#7527](https://github.com/docker/for-mac/issues/7527).

## 4.32.0

{{< release-date date="2024-07-04" >}}


### New

- Docker Engine and CLI updated to version 27.0.
- Docker Desktop now supports moving data to a different drive on macOS and Windows with WSL2 backend. See [docker/for-win#13384](https://github.com/docker/for-win/issues/13384).
- You can now [schedule backups for volume exports](use-desktop/volumes.md) in the **Volumes** tab (Beta).
- Access a terminal shell directly from Docker Desktop (Beta).

### Upgrades

- [Docker Buildx v0.15.1](https://github.com/docker/buildx/releases/tag/v0.15.1)
- [Docker Compose v2.28.1](https://github.com/docker/compose/releases/tag/v2.28.1)
- [Docker Scout CLI v1.10.0](https://github.com/docker/scout-cli/releases/tag/v1.10.0)
- [Docker Engine v27.0.3](https://docs.docker.com/engine/release-notes/27/#2703)
- Docker Init v1.3.0

### Bug fixes and enhancements

#### For all platforms

- Improved instructions for `watch` in the Compose File Viewer
- Added support for Golang projects that don't have dependencies in Docker Init. Addresses [docker/roadmap#611](https://github.com/docker/roadmap/issues/611)
- [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md) now lets admins set the default value to `ProxyEnableKerberosNTLM`.
- Removed a temporary compatibility fix for older versions of Visual Studio Code.
- Builds view:
  - Changed icon for imported build record to a "files" icon.
  - Improved the error message when trying to connect to an already connected Docker Build Cloud builder.
  - Fixed an issue where build records would disappear unexpectedly.
  - Fixed an issue that prevented users from being able to re-open an [imported build](use-desktop/builds.md#import-builds).
  - Fixed an issue where build details were not displayed when a build's state had changed from running to completed.
  - Fixed malformed build source link in build details.
  - Fixed missing build stats for named contexts.
  - Fixed image index/manifest not being displayed anymore in build results.
  - Fixed an issue where build traces exported from the UI would appear as a single, flattened list when imported to Jaeger
  - Fixed truncated digest/sha in build details.
  - Fixed final status animation of active builds.

#### For Windows

- Fixed an issue on the WSL 2 engine where Docker Desktop would not detect the existence of the `docker-desktop-data` distribution if it had been manually moved by the user.
- The Windows on ARM installer and the [privileged service](setup/install/windows-permission-requirements.md#privileged-helper) are now built for ARM64.

#### For Mac

- Re-added `CONFIG_DM_CRYPT` kernel module.
- Re-added `CONFIG_PSI` kernel module.
- Re-added `CONFIG_GTP` kernel module.
- Re-added `CONFIG_NFT_BRIDGE_META` kernel module.
- Fixed a regression where the **Another application changed your Desktop configuration** warning message appeared whenever `/var/run/docker.socket` was pointing to an unexpected path.
- Changed the Configuration Check menu entry and banner to a notification.
- Improved the performance of read and write operations on bind mounts.
- Fixed fatal errors with some `AMD64` Java images. Fixes [docker/for-mac/7286](https://github.com/docker/for-mac/issues/7286) and [docker/for-mac/7006](https://github.com/docker/for-mac/issues/7006).
- Fixed an issue that caused Docker Desktop to remove `Docker.app` when installing from `/Applications`.
- Fixed an issue that caused bind mounts to fail. Fixes [docker/for-mac#7274](https://github.com/docker/for-mac/issues/7274).

### Known issues

#### For all platforms

- The **Manage Synchronized File Shares with Compose** setting is automatically enabled for all users who opt into **Access experimental features**. This converts all bind mounts into synchronized file shares. To disable this behavior, deselect **Access experimental features**. Then, manually delete any file shares by going to the **File sharing** tab within **Resources**, navigating to the **Synchronized file shares** section, selecting the file shares you want to remove, and selecting **Delete**.

#### For Mac

- When running `docker-compose` after an update, it will return `command not found`. As a workaround, you can create the following symlink: `sudo ln -sf /Applications/Docker.app/Contents/Resources/cli-plugins/docker-compose /usr/local/bin/docker-compose`

## 4.31.1

### Bug fixes and enhancements

#### For Windows

- Fixed a bug where containers, images and volumes created before the update were potentially invisible for users. Fixes [docker/for-win#14118](https://github.com/docker/for-win/issues/14118).

## 4.31.0

### New

- [Air-Gapped Containers](../enterprise/security/hardened-desktop/air-gapped-containers.md) is now generally available.
- Docker Compose File Viewer shows your Compose YAML with syntax highlighting and contextual links to relevant docs (Beta, progressive rollout).
- New Sidebar user experience.

### Upgrades

- [Docker Engine and CLI v26.1.4](https://github.com/moby/moby/releases/tag/v26.1.4).
- [Docker Scout CLI v1.9.1](https://github.com/docker/scout-cli/releases/tag/v1.9.1)
- [Docker Compose v2.27.1](https://github.com/docker/compose/releases/tag/v2.27.1)
- [Docker Buildx v0.14.1](https://github.com/docker/buildx/releases/tag/v0.14.1)
- [Containerd v1.6.33](https://github.com/containerd/containerd/releases/tag/v1.6.33)
- [Credential Helpers v0.8.2](https://github.com/docker/docker-credential-helpers/releases/tag/v0.8.2)
- [NVIDIA Container Toolkit v1.15.0](https://github.com/NVIDIA/nvidia-container-toolkit/releases/tag/v1.15.0)
- [Go 1.22.4](https://github.com/golang/go/releases/tag/go1.22.4)
- Linux kernel `v6.6.31`

### Bug fixes and enhancements

#### For all platforms

- Newer releases are now displayed in the **Software updates** settings tab when an update has already been downloaded.
- Added `proxyEnableKerberosNTLM` config to `settings.json` to enable fallback to basic proxy authentication if Kerberos/NTLM environment is not properly set up.
- Fixed a bug where Docker Debug was not working properly with Enhanced Container Isolation enabled.
- Fixed a bug where UDP responses were not truncated properly.
- Fixed a bug where the **Update** screen was hidden when using [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md).
- Fixed a bug where proxy settings defined in `admin-settings.json` were not applied correctly on startup.
- Fixed a bug where the **Manage Synchronized file shares with Compose** toggle did not correctly reflect the value with the feature.
- Fixed a bug where a bind mounted file modified on host is not updated after the container restarts, when gRPC FUSE file sharing is used on macOS and on Windows with Hyper-V. Fixes [docker/for-mac#7274](https://github.com/docker/for-mac/issues/7274), [docker/for-win#14060](https://github.com/docker/for-win/issues/14060).
- Builds view:
  - New [Import builds](use-desktop/builds.md#import-builds) feature that lets you import build records for builds by other people, or [builds in a CI environment](../build/ci/github-actions/build-summary.md).
  - Fixed missing OpenTelemetry traces in build results for failed builds.
  - Fixed `default-load` appearing as invalid driver-opt for the container driver.
  - Fixed deep link to build details.

#### For Windows

- Changed the `--allowed-org` installer flag to write a policy registry key instead of to the `registry.json`.

#### For Mac

- Moved the setting **Automatically check configuration** from **Advanced** settings to **General** settings.
- Improved VirtioFS caching by implementing longer attributes timeout and invalidation.

#### For Linux

- Added Linux headers to the VM, to ease the compilation of custom kernel modules.

### Security

#### For all platforms

- Fixed a security bug in Enhanced Container Isolation (ECI) mode where a user could create Docker volumes sourced from restricted directories inside the Docker Desktop VM and mount them into containers, thereby giving the container access to such restricted VM directories.
- By default, only extensions listed in the marketplace can be installed in Docker Desktop. This can be changed in Docker Desktop's settings. Extension developers will need to change this option in order to test their extensions.

### For Windows

- Fixed [CVE-2024-5652](https://www.cve.org/cverecord?id=CVE-2024-5652) in which a user in the `docker-users` group can cause a Windows Denial-of-Service through the `exec-path` Docker daemon config option in Windows containers mode. This vulnerability was discovered by Hashim Jawad ([@ihack4falafel](https://github.com/ihack4falafel)) working with Trend Micro Zero Day Initiative.

### Deprecation

#### For all platforms

- The CLI binary that used to be shipped as `com.docker.cli` is now shipped simply as `docker`. This release leaves the CLI binary as `com.docker.cli`, but it will be removed next release.

#### For Windows

- Removed support for legacy version packs from the WSL2 engine.

### Known Issues

#### For Windows

- When upgrading to Docker Desktop 4.31.0, existing containers, images and volumes become invisible for users that created those containers and images using Docker Desktop 4.8.0 or lower, on Windows hosts with WSL only. The data is not lost, it just becomes invisible to Docker Desktop 4.31.0. If impacted, downgrade to version 4.30 or earlier. For more information see: [docker/for-win#14118](https://github.com/docker/for-win/issues/14118).

#### For Linux

- Ubuntu 24.04 LTS is not yet supported, Docker Desktop will fail to start. Due to a change in how the latest Ubuntu release restricts the unprivileged namespaces, `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0` needs to be ran at least once. Refer to the [Ubuntu Blog](https://ubuntu.com/blog/).

## 4.30.0

{{< release-date date="2024-05-06" >}}

### New

#### For all platforms

- Docker Desktop now supports [SOCKS5 proxies](/manuals/desktop/features/networking.md#socks5-proxy-support). Requires a Business subscription.
- Added a new setting to manage the onboarding survey in [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md).

#### For Windows

- Added support for [Kerberos and NTLM proxy authentication](settings-and-maintenance/settings.md#proxy-authentication) on Windows. Requires a Business subscription.

### Upgrades

- [Docker Compose v2.27.0](https://github.com/docker/compose/releases/tag/v2.27.0)
- [Docker Engine v26.1.1](https://docs.docker.com/engine/release-notes/26.1/#2611)
- [Wasm](features/wasm.md) runtimes:
  - Updated `runwasi` shims to `v0.4.0`
  - Updated `deislabs` shims to `v0.11.1`
  - Updated `spin` shim to `v0.13.1`
- [Docker Scout CLI v1.8.0](https://github.com/docker/scout-cli/releases/tag/v1.8.0)
- Docker Debug `v0.0.29`
- Linux kernel `v6.6.26`
- [Go 1.22.2](https://github.com/golang/go/releases/tag/go1.22.2)

### Bug fixes and enhancements

#### For all platforms

- Improved Enhanced Container Isolation (ECI) security when running `docker build` commands in rootless containers.
- Fixed a bug where `docker events` exited with `Unexpected EOF` when Docker Desktop entered/exited Resource Saver mode.
- Fixed a bug where `docker stats --no-stream` hung when Docker Desktop was in Resource Saver mode.
- Fixed a bug in the self-diagnose CLI that incorrectly showed the VM had not started. Fixes [docker/for-mac#7241](https://github.com/docker/for-mac/issues/7241).
- Fixed a bug where high-throughput port forward transfers could stall. Fixes [docker/for-mac#7207](https://github.com/docker/for-mac/issues/7207).
- Fixed CLI-plugin symlinks not being removed when CLI apps were removed.
- Fixed a bug in the shared ports drawer to show the right message for local engines.
- Dev Environments is being sunset and has moved to the **Beta** tab in **Features in development**.
- Builds view:
  - Better bulk delete for build records.
  - Added action to open the relevant web page for container images and Git sources in build dependencies.
  - Added action to download Provenance and OpenTelemetry traces in Jaeger or OTLP format.
  - Fixed source details for remote build invocations.
  - Fixed a bug where multi-platform builds would show up as separate records when using a cloud builder.

#### For Mac

- Fixed a bug where a segmentation fault was triggered with Virtualization Framework, on post-2019 Macs. See [docker/for-mac#6824](https://github.com/docker/for-mac/issues/6824).
- Enabled `CONFIG_SECURITY=y` kernel config, for example for [Tetragon](https://tetragon.io/). Fixes [docker/for-mac#7250](https://github.com/docker/for-mac/issues/7250).
- Re-added support for `SQUASHFS` compression. Fixes [docker/for-mac#7260](https://github.com/docker/for-mac/issues/7260).
- Fixed a bug that caused a new version of Docker Desktop to be marked as damaged.
- Increased network MTU when using qemu on Apple Silicon.
- Fixed a bug preventing Docker Desktop to start if Rosetta was not installed. Fixes [docker/for-mac#7243](https://github.com/docker/for-mac/issues/7243).

#### For Windows

- Added a simplified provisioning mode for WSL2 that avoids the need for the ancillary `docker-desktop-data` WSL distribution (experimental).
- Fixed bash completions for the Docker CLI in a WSL environment.
- Fixed a regression in Docker Desktop 4.28 that caused host files bind-mounted into containers to not show up properly inside the container, when using Docker-in-Docker (via mounts of `/var/run/docker.sock`) on WSL.
- Fixed a bug that would cause the following error `merging settings: integratedWslDistros type mismatch`.

### Known issues

#### For all platforms

- If you have enabled a feature in Docker Desktop that requires you to be signed in, such as **Host networking** you must remain signed in to use Docker Desktop. To continue using Docker Desktop or to modify these settings, ensure you are signed in.
- To enable or disable **Manage Synchronized file shares with Compose**, **Access experimental features** and **Manage Synchronized file shares with Compose** have to be checked or unchecked at the same time.
- The Docker CLI will sometimes hang when running a container with the autoremove option (`--rm`) if the container fails to start (e.g.: `docker run --rm alpine invalidcommand`). In this case, the CLI process may need to be manually killed.

#### For Windows

- When starting Docker Desktop as a non-admin user, the following error connect `ENOENT \\.\pipe\errorReporter` might be triggered if the user is not a member of the **docker-users** group.
This can be resolved by adding the user to the **docker-users** group. Before starting Docker Desktop, make sure to sign out and then sign back in and unregister `docker-desktop` distribution if that was created, using `wsl --unregister docker-desktop`.

#### For Linux

- Ubuntu 24.04 LTS is not yet supported, Docker Desktop will fail to start. Due to a change in how the latest Ubuntu release restricts the unprivileged namespaces, `sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0` needs to be ran at least once. Refer to the [Ubuntu Blog](https://ubuntu.com/blog/ubuntu-23-10-restricted-unprivileged-user-namespaces) for more details.

## 4.29.0

{{< release-date date="2024-04-08" >}}

### New

- You can now enforce Rosetta usage via [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md).
- [Docker socket mount restrictions](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md) with ECI is now generally available.
- Docker Engine and CLI updated to [Moby 26.0](https://github.com/moby/moby/releases/tag/v26.0.0). This includes Buildkit 0.13, sub volumes mounts, networking updates, and improvements to the containerd multi-platform image store UX.
- New and improved Docker Desktop error screens: swift troubleshooting, easy diagnostics uploads, and actionable remediation.
- Compose supports [Synchronized file shares (experimental)](features/synchronized-file-sharing.md).
- New [interactive Compose CLI (experimental)](../compose/how-tos/environment-variables/envvars.md#compose_menu).
- Beta release of:
  - Air-Gapped Containers with [Settings Management](../enterprise/security/hardened-desktop/air-gapped-containers.md).
  - [Host networking](../engine/network/drivers/host.md#docker-desktop) in Docker Desktop.
  - [Docker Debug](use-desktop/container.md#integrated-terminal) for running containers.
  - [Volumes Backup & Share extension](use-desktop/volumes.md) functionality available in the **Volumes** tab.

### Upgrades

- [Docker Compose v2.26.1](https://github.com/docker/compose/releases/tag/v2.26.1)
- [Docker Scout CLI v1.6.3](https://github.com/docker/scout-cli/releases/tag/v1.6.3)
- [Docker Engine v26.0.0](https://docs.docker.com/engine/release-notes/26.0/#2600)
- [Buildx v0.13.1](https://github.com/docker/buildx/releases/tag/v0.13.1)
- [Kubernetes v1.29.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.29.2)
- [cri-dockerd v0.3.11](https://github.com/Mirantis/cri-dockerd/releases/tag/v0.3.11)
- Docker Debug v0.0.27

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue with dropdown menu opening beyond the application window.
- Docker Init:
  - Updated the formatting of CLI output to improve legibility.
  - Fixed an issue with `.dockerignore` to avoid ignoring application files that start with "compose".
  - Improved how Java applications are started based on Spring Boot version. Fixes [docker/for-mac#7171](https://github.com/docker/for-mac/issues/7171).
  - Removed non-official Docker image used for Rust cross-compilation.
- The maximum number of files per [Synchronized file share](features/synchronized-file-sharing.md) now exceeds 2 million.
- Fixed an issue that caused the warning: "_The value provided to Autocomplete is invalid._" when selecting the **Export to local image** field.
- **Run Cloud** can now be accessed from the Docker Desktop Dashboard.
- Opting out from sending analytics will now also disable collecting data for bug reports.
- You can now share and unshare a port to the Cloud Engine in the **Containers** view.
- Shared cloud can now be accessed from the footer in the right-hand side of the **Dashboard**.
- Added beta support for host networking on macOS, Windows and Docker Desktop for Linux  [docker#238](https://github.com/docker/roadmap/issues/238).
- Added a timestamp to new unread notifications.
- Fixed typo in the virtualization support error message. Fixes [docker/desktop-linux#197](https://github.com/docker/desktop-linux/issues/197).
- Docker Desktop now allows connections to `host.docker.internal` to be blocked by a rule in a PAC file.
- Fixed the placement of the secondary menu in the **Images** and **Containers** lists.
- Fixed a race condition that occurred when starting Docker Desktop with QEMU.
- Improved the error message when an image pull is blocked by Registry Access Management policy.
- Re-add `CONFIG_BONDING=y` in the kernel config.

#### For Mac

- Fixed Kubernetes not starting successfully. Fixes [docker/for-mac#7136](https://github.com/docker/for-mac/issues/7136) and [docker/for-mac#7031](https://github.com/docker/for-mac/issues/7031).
- Fixed a bug when the browser was not able to send back authentication information to Docker Desktop. Fixes [docker/for-mac/issues#7160](https://github.com/docker/for-mac/issues/7160).

#### For Windows

- Fixed a bug where `docker run -v` would fail after switching between WSL 2 and Hyper-V.
- Fixed a bug where Docker Desktop was not stopping its WSL distributions (`docker-desktop` and `docker-desktop-data`) when it was shutdown. Fixes [docker/for-win/issues/13443](https://github.com/docker/for-win/issues/13443) and [docker/for-win/issues/13938](https://github.com/docker/for-win/issues/13938).

#### For Linux

- Fixed an issue that caused the list of available experimental features in the UI to become out-of-sync with the backend data.

#### Security

- Disabled Electron `runAsNode` fuse to improve security hardening. For more info, see [Electron's documentation.](https://www.electronjs.org/blog/statement-run-as-node-cves).
- Fixed [CVE-2024-6222](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-6222) which allows an attacker who has gained access to the Docker Desktop VM through a container breakout to further escape to the host by passing extensions and dashboard related IPC messages. Reported by Billy Jheng Bing-Jhong, Đỗ Minh Tuấn, Muhammad Alifa Ramdhan working with Trend Micro Zero Day Initiative.

### Known issues

#### For Mac

- Docker Desktop on Apple Silicon doesn't start if Rosetta is not installed. This will be fixed in future releases. See [docker/for-mac#7243](https://github.com/docker/for-mac/issues/7243).

## 4.28.0

{{< release-date date="2024-02-26" >}}

### New

- [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md) now allows admins to set the default file-sharing implementation and specify which paths developer can add file shares to.
- Added support for `socks5://` HTTP and HTTPS proxy URLs when the [`SOCKS` proxy support beta feature](/manuals/desktop/features/networking.md) is enabled.
- Users can now filter volumes to see which ones are in use in the **Volumes** tab.

### Upgrades

- [Compose v2.24.6](https://github.com/docker/compose/releases/tag/v2.24.6)
- [Docker Engine v25.0.3](https://docs.docker.com/engine/release-notes/25.0/#2503)
- [Docker Scout CLI v1.5.0](https://github.com/docker/scout-cli/releases/tag/v1.5.0)
- [Qemu 8.1.5](https://wiki.qemu.org/ChangeLog/8.1)
- [Wasm](features/wasm.md) runtimes:
  - Updated runwasi shims to `v0.4.0`, including:
    - wasmtime `v17.0`, with initial support for WASI preview 2
    - wasmedge `v0.13.5`
    - wasmer `v4.1.2`
  - Updated deislabs shims to `v0.11.1`, including:
    - lunatic `v0.13.2`
    - slight `v0.5.1`
    - spin `v2.2.0`
    - wws `v1.7.0`

### Bug fixes and enhancements

#### For all platforms

- Fixed `postgis` with `Qemu`. Fixes [docker/for-mac#7172](https://github.com/docker/for-mac/issues/7172).
- Re added `CONFIG_BLK_DEV_DM` kernel config for `kpartx`. Fixes [docker/for-mac#7197](https://github.com/docker/for-mac/issues/7197).
- Allow `SOCKS` proxies to be set via a proxy autoconfig `pac file`.
- Re added `CONFIG_AUDIT` kernel config.
- Fixed a bug with the Rust build on `virtiofs`. See [rust-lang/docker-rust#161](https://github.com/rust-lang/docker-rust/issues/161).
- Fixed an issue that caused the `missing registry authentication` error when pulling Kubernetes images.
- Fixed an issue that caused Docker Compose commands to hang.
- Fixed a bug in `docker build` that caused Docker Desktop to crash. Fixes [docker/for-win#13885](https://github.com/docker/for-win/issues/13885), [docker/for-win#13896](https://github.com/docker/for-win/issues/13896), [docker/for-win#13899](https://github.com/docker/for-win/issues/13899), [docker/for-mac#7164](https://github.com/docker/for-mac/issues/7164), [docker/for-mac#7169](https://github.com/docker/for-mac/issues/7169)
- Docker Init:
  - Improved how Java applications are started based on Spring Boot version. Fixes [docker/for-mac#7171](https://github.com/docker/for-mac/issues/7171).
  - Removed non-official Docker image used for Rust cross-compilation
- Builds view:
  - Active and completed builds can be found in dedicated tabs.
  - Build details now displays build duration and cache steps.
  - OpenTelemetry traces are now displayed in the build results.
  - Fixed an issue where context builders events were not always triggered.
  - Restyle the empty state view to make the dashboard clearer.

#### For Mac

- Fix `httpd` issue with Rosetta. [docker/for-mac#7182](https://github.com/docker/for-mac/issues/7182)
- Fixed a bug that caused a crash on the `virtualization.framework`. Fixes [docker/for-mac#7024](https://github.com/docker/for-mac/issues/7024)

#### For Windows

- Fixed an issue with DNS timeouts on Windows.
- Added support for Enhanced Container Isolation Docker socket mount permission on WSL user distributions.
- Fixed an issue that caused the `failed to get console mode` error when redirecting output from the CLI.
- Fixed an issue with the engine socket permissions when mounted inside containers. Fixes [docker/for-win#13898](https://github.com/docker/for-win/issues/13898)

### Known Issues

#### For Windows

- In dark mode, the **Disk image location** in **Resources**>**Advanced** settings is not visible. As a workaround, change to light mode.

## 4.27.2

{{< release-date date="2024-02-08" >}}

### Upgrades

- [Compose v2.24.5](https://github.com/docker/compose/releases/tag/v2.24.5)
- [Docker Scout CLI v1.4.1](https://github.com/docker/scout-cli/releases/tag/v1.4.1)
- Docker Debug v0.0.24

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where the diagnostics ID would not print correctly when uploading diagnostics from the terminal.
- Fixed a bug where the default settings values were being reset to default on startup, when using Settings Management.
- Fixed a bug with the dashboard being shown at startup even though the **Open Docker Dashboard when Docker Desktop starts** option was disabled. Fixes [docker/for-win#13887](https://github.com/docker/for-win/issues/13887).
- Fixed a bug in the build backend service that caused Docker Desktop to crash. Fixes [docker/for-win#13885](https://github.com/docker/for-win/issues/13885), [docker/for-win#13896](https://github.com/docker/for-win/issues/13896), [docker/for-win#13899](https://github.com/docker/for-win/issues/13899), [docker/for-mac#7164](https://github.com/docker/for-mac/issues/7164), [docker/for-mac#7169](https://github.com/docker/for-mac/issues/7169).
- Fixed the Docker Engine socket permissions when mounted inside containers. Fixes [docker/for-win#13898](https://github.com/docker/for-win/issues/13898).
- Docker Scout:
  - Updated dependencies to address Leaky Vessels series of CVEs ([CVE-2024-21626](https://github.com/advisories/GHSA-xr7r-f8xq-vfvv), [CVE-2024-24557](https://github.com/advisories/GHSA-xw73-rw38-6vjc))
  - Added initial VEX document to document false positive [CVE-2020-8911](https://github.com/advisories/GHSA-f5pg-7wfw-84q9) and [CVE-2020-8912](https://github.com/advisories/GHSA-7f33-f4f5-xwgw)
  - Added support for cosign SBOM attestations
  - Added support for VEX in-toto attestations
- Docker Debug:
  - Fixed a bug when pulling the image behind resource accesses management
  - Fixed connection issues

#### For Mac

- Re-added kernel modules needed by `Istio`. Fixes [docker/for-mac#7148](https://github.com/docker/for-mac/issues/7148).
- Node now uses all the cores available under Rosetta.
- Fixed an issue with `php-fpm`. Fixes [docker/for-mac#7037](https://github.com/docker/for-mac/issues/7037).

## 4.27.1

{{< release-date date="2024-02-01" >}}

### Upgrades

- [Docker Engine v25.0.2](https://docs.docker.com/engine/release-notes/25.0/#2502) which contains a fix for [CVE-2024-24557](https://scout.docker.com/vulnerabilities/id/CVE-2024-24557), [CVE-2024-23650](https://scout.docker.com/vulnerabilities/id/CVE-2024-23650), [CVE-2024-23651](https://scout.docker.com/vulnerabilities/id/CVE-2024-23651), [CVE-2024-23652](https://scout.docker.com/vulnerabilities/id/CVE-2024-23652) and [CVE-2024-23653](https://scout.docker.com/vulnerabilities/id/CVE-2024-23653)
- [Containerd v1.6.28](https://github.com/containerd/containerd/releases/tag/v1.6.28)
- [Runc v1.1.12](https://github.com/opencontainers/runc/releases/tag/v1.1.12) which contains a fix for [CVE-2024-21626](https://scout.docker.com/vulnerabilities/id/CVE-2024-21626)

### Bug fixes and enhancements

#### For Mac

- Fixed a bug that caused Docker Desktop to hang when applying an update.

## 4.27.0

{{< release-date date="2024-01-25" >}}

### New

- Docker init now supports Java and is generally available to all users.
- [Synchronized File Shares](features/synchronized-file-sharing.md) provides fast and flexible host-to-VM file sharing within Docker Desktop. Utilizing the technology behind [Docker’s acquisition of Mutagen](https://www.docker.com/blog/mutagen-acquisition/), this feature provides an alternative to virtual bind mounts that uses synchronized filesystem caches, improving performance for developers working with large codebases.
- Organization admins can now [configure Docker socket mount permissions](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md) when ECI is enabled.
- [Containerd Image Store](features/containerd.md) support is now generally available to all users.
- Get a debug shell into any container or image with the new [`docker debug` command](/reference/cli/docker/debug/) (Beta).
- Organization admins, with a Docker Business subscription, can now configure a custom list of extensions with [Private Extensions Marketplace](../extensions/private-marketplace.md) enabled (Beta)

### Upgrades

- [Amazon ECR Credential Helper v0.7.1](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.7.1)
- [Buildx v0.12.1](https://github.com/docker/buildx/releases/tag/v0.12.1)
- [Containerd v1.6.27](https://github.com/containerd/containerd/releases/tag/v1.6.27)
- [Compose v2.24.3](https://github.com/docker/compose/releases/tag/v2.24.3)
- [Docker Credential Helpers v0.8.1](https://github.com/docker/docker-credential-helpers/releases/tag/v0.8.1)
- [Runc v1.1.11](https://github.com/opencontainers/runc/releases/tag/v1.1.11)
- [Docker Engine v25.0.0](https://docs.docker.com/engine/release-notes/25.0/)
- [Kubernetes v1.29.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.29.1)
- [Docker Scout v1.3.0](https://github.com/docker/scout-cli/releases/tag/v1.3.0)

### Bug fixes and enhancements

#### For all platforms

- The `docker scan` command has been removed. To continue learning about the vulnerabilities of your images, and many other features, use the [`docker scout` command](/reference/cli/docker/scout/).
- Fixed a bug where automatic updates would not download when the **Always download updates** checkbox was selected.
- Fixed typo in the dashboard tooltip. Fixes [docker/for-mac#7132](https://github.com/docker/for-mac/issues/7132)
- Improved signal handling behavior (e.g. when pressing Ctrl-C in the terminal while running a `docker` command).
- Re-added kernel modules required by `minikube start --cni=cilium`.
- Fixed a bug that caused the installation screen to appear again when admin controls are enabled after sign in.
- Fixed a bug where Docker would not start if a shared folder is no longer present.
- Fixed the number of available CPUs displayed in the **Containers** section of the Dashboard.
- Re-added kernel modules for `btrfs`, `xfs`, `vfat`, `exfat`, `ntfs3`, `f2fs`, `squashfs`, `udf`, `9p` and `autofs`.
- Container usage charts have been moved to a vertical **Resource usage** side panel to allow for more space in the containers list. Accessing the usage charts remains the same via the **Show charts** button.
- Fixed a bug where selecting **Close Application** at sign-in was leaving behind a hung backend process.
- Fixed a bug which caused Docker Desktop to become unresponsive when analytics is disabled through Settings Management.
- Docker init:
  - Added support for containerizing a Java server
  - Various fixes on Windows
- Builder settings:
  - You can now refresh storage data for your builder at any point in time.
  - You can now delete the build history for a builder.
- Builds view:
  - An error message is now shown when a build record cannot be removed.
  - Fixed an issue where a cloud builder could not be created in rootless mode on macOS.
  - Inline cache and Git source are now properly handled in the **Build timing** section of the **Info** tab.
  - The Builder used and the author invoking the build is now displayed in past builds on the **History** tab.
  - Several improvements made to better link past builds on the **History** tab.
  - Several improvements to make the build name more accurate.
  - Fixed stuck builds in the **Active builds** list when a builder cannot be reached.
  - Fixed an issue preventing the build record from being deleted in some circumstances.
  - Fixed an issue where build names could be empty.
  - Fixed a general issue with the Builds view when Resource saver mode is enabled.

#### For Mac

- Enabled `Huge Pages` and fixed PHP segmentation fault with Rosetta. Fixes [docker/for-mac#7117](https://github.com/docker/for-mac/issues/7117).
- Fixed `xvfb` under Rosetta. Fixes [docker/for-mac#7122](https://github.com/docker/for-mac/issues/7122)
- Fixed `ERR_WORKER_INVALID_EXEC_ARGV` error under Rosetta. [docker/for-mac#6998](https://github.com/docker/for-mac/issues/6998).
- Fixed a bug where Docker Desktop could deadlock if `admin-settings.json` was syntactically invalid.

#### For Windows

- Fixed a bug that prevented UTF-16 strings from being encoded to UTF-8 for some locales. Fixes [docker/for-win#13868](https://github.com/docker/for-win/issues/13868).
- Fixed a bug where the credentials store configuration would reset on app restart with the WSL integration. Fixes [docker/for-win#13529](https://github.com/docker/for-win/issues/13529).
- Fixed an issue that prevented the correct WSL engine errors from propagating to the user.
- Fixed an issue that would cause Docker Desktop to hang when quitting from Windows Containers mode.

### Security

#### For Windows

- Mitigated several DLL side-loading vulnerabilities in the Docker Desktop installer on Windows, reported by Suman Kumar Chakraborty ([@Hijack-Everything](https://github.com/Hijack-Everything))

### Known issues

#### For all platforms

- When using Setting Management, the settings that are not set in the `admin-settings.json` will be reset to default when Docker Desktop starts.

#### For Mac

- Updating to 4.27.0 from the **Software updates** sometimes hangs. As a workaround, use the 4.27.0 installer from this page.

## 4.26.1

{{< release-date date="2023-12-14" >}}

### Bug fixes and enhancements

#### For all platforms

- Updated feedback links inside Docker Desktop to ensure they continue to work correctly

#### For Windows

- Switch the CLI binaries to a version compatible with older versions of glibc, such as used in Ubuntu 20.04 fixes [docker/for-win#13824](https://github.com/docker/for-win/issues/13824)

## 4.26.0

{{< release-date date="2023-12-04" >}}

### New

- Administrators can now control access to beta and experimental features in the **Features in development** tab with [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md).
- Introduced four new version update states in the footer.
- `docker init` (Beta) now supports PHP with Apache + Composer.
- The [**Builds** view](use-desktop/builds.md) is now GA. You can now inspect builds, troubleshoot errors, and optimize build speed.

### Upgrades

- [Compose v2.23.3](https://github.com/docker/compose/releases/tag/v2.23.3)
- [Docker Scout CLI v1.2.0](https://github.com/docker/scout-cli/releases/tag/v1.2.0).
- [Buildx v0.12.0](https://github.com/docker/buildx/releases/tag/v0.12.0)
- [Wasm](features/wasm.md) runtimes:
  - wasmtime, wasmedge and wasmer `v0.3.1`.
  - lunatic, slight, spin, and wws `v0.10.0`.
  - Wasmtime is now based on wasmtime `v14.0` and supports wasi preview-2 components
  - Wasmedge is now based on WasmEdge `v0.13.5`
  - Spin is now based on Spin `v2.0.1`
  - wws is now based on wws `v1.7.0`
- [Docker Engine v24.0.7](https://docs.docker.com/engine/release-notes/24.0/#2407)
- [Containerd v1.6.25](https://github.com/containerd/containerd/releases/tag/v1.6.25)
- [runc v1.1.10](https://github.com/opencontainers/runc/releases/tag/v1.1.10)

### Bug fixes and enhancements

#### For all platforms

- You can now provide feedback from the commandline by using `docker feedback`.
- Improved the text and position of the startup options in the **General** settings tab.
- Redesigned the dashboard's header bar, added links to other Docker resources, improved display of account information.
- Fixed a bug  where enabling the containerd image store and Wasm simultaneously would not enable Wasm.
- containerd integration:
  - Fixed `docker push/pull` authentication not being sent to non-DockerHub registries in cases where `ServerAddress` is not provided.
  - Fixed `docker history` reporting wrong IDs and tags.
  - Fixed `docker tag` not preserving internal metadata.
  - Fixed `docker commit` when the daemon configured with `--userns-remap`.
  - Fixed `docker image list` to show real image creation date.
  - Added support for `-a` flag to `docker pull` (pull all remote repository tags).
  - Added support for `--group-add` flag to `docker run` (append extra groups).
  - Adjusted some errors reported by `docker push/pull`.
- Docker Init:
  - Improved cross-compilation in Dockerfiles for Golang and Rust.
  - Improved caching in Dockerfile for ASP.NET Core.
- Docker Desktop now gives more detailed information about pending updates in the dashboard footer.
- Fixed a bug in Enhanced Container Isolation mode where `docker run --init` was failing.
- Fixed a bug where a notification prompting the user to download a new version of Docker Desktop remained visible after the user started downloading the new version.
- Added a notification that indicates when Docker Desktop is installing a new version.
- Fixed a bug where the cursor changed to a pointer when the user hovered over a notification that has no call to action.

#### For Mac

- Fixed an issue where Rosetta would not work with PHP. Fixes [docker/for-mac#6773](https://github.com/docker/for-mac/issues/6773)  and [docker/for-mac#7037](https://github.com/docker/for-mac/issues/7037).
- Fixed several issues related to Rosetta not working. Fixed [[docker/for-mac#6973](https://github.com/docker/for-mac/issues/6973), [[docker/for-mac#7009](https://github.com/docker/for-mac/issues/7009), [[docker/for-mac#7068](https://github.com/docker/for-mac/issues/7068) and [[docker/for-mac#7075](https://github.com/docker/for-mac/issues/7075)
- Improved the performance of NodeJS under Rosetta.
- Fixed the **Unable to open /proc/self/exe** Rosetta errors.
- Fixed a bug were the setting **Start Docker Desktop when you sign in** would not work. Fixes [docker/for-mac#7052](https://github.com/docker/for-mac/issues/7052).
- You can now enable the use of Kernel networking path for UDP through the UI. Fixes [docker/for-mac#7008](https://github.com/docker/for-mac/issues/7008).
- Fixed a regression where the `uninstall` CLI tool was missing.
- Addressed an issue which caused Docker Desktop to become unresponsive when analytics were disabled with Settings Management.

#### For Windows

- Added support for WSL mirrored mode networking (requires WSL `v2.0.4` and up).
- Added missing signatures on DLL and VBS files.

### Known issues

#### For Windows

- Docker CLI doesn’t work when using WSL 2 integration on an older Linux distribution (for example, Ubuntu 20.04) which uses a `glibc` version older than `2.32`. This will be fixed in future releases. See [docker/for-win#13824](https://github.com/docker/for-win/issues/13824).

## 4.25.2

{{< release-date date="2023-11-21" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where a blank UI would appear after submitting a response in the **Welcome Survey**.

#### For Windows

- Fixed a bug where Docker Desktop on WSL 2 would shut down dockerd unexpectedly when idle. Fixes [docker/for-win#13789](https://github.com/docker/for-win/issues/13789)

## 4.25.1

{{< release-date date="2023-11-13" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed a regression in 4.25 where Docker would not start if the swap file was corrupt. Corrupt swap files will be re-created on next boot.
- Fixed a bug when swap is disabled. Fixes [docker/for-mac#7045](https://github.com/docker/for-mac/issues/7045), [docker/for-mac#7044](https://github.com/docker/for-mac/issues/7044) and [docker/for-win#13779](https://github.com/docker/for-win/issues/13779).
- The `sysctl vm.max_map_count` is now set to 262144. See [docker/for-mac#7047](https://github.com/docker/for-mac/issues/7047)

#### For Windows

- Fixed an issue where **Switch to Windows Containers** would not appear on the tray menu for some users. See [docker/for-win#13761](https://github.com/docker/for-win/issues/13761).
- Fixed a bug where the WSL integration would not work for users using a shell other than `sh`. See [docker/for-win#13764](https://github.com/docker/for-win/issues/13764).
- Re-added `DockerCli.exe`.

## 4.25.0

{{< release-date date="2023-10-26" >}}

### New

- Rosetta is now Generally Available for all users on macOS 13 or later. It provides faster emulation of Intel-based images on Apple Silicon. To use Rosetta, see [Settings](settings-and-maintenance/settings.md). Rosetta is enabled by default on macOS 14.1 and later.
- Docker Desktop now detects if a WSL version is out of date. If an out dated version of WSL is detected, you can allow Docker Desktop to automatically update the installation or you can manually update WSL outside of Docker Desktop.
- New installations of Docker Desktop for Windows now require a Windows version of 19044 or later.
- Administrators now have the ability to control Docker Scout image analysis in [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md).

### Upgrades

- [Compose v2.23.0](https://github.com/docker/compose/releases/tag/v2.23.0)
- [Docker Scout CLI v1.0.9](https://github.com/docker/scout-cli/releases/tag/v1.0.9).
- [Kubernetes v1.28.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.28.2)
  - [cri-dockerd v0.3.4](https://github.com/Mirantis/cri-dockerd/releases/tag/v0.3.4)
  - [CNI plugins v1.3.0](https://github.com/containernetworking/plugins/releases/tag/v1.3.0)
  - [cri-tools v1.28.0](https://github.com/kubernetes-sigs/cri-tools/releases/tag/v1.28.0)

### Bug fixes and enhancements

#### For all platforms

- Fixed a spacing problem in the `Accept License` pop-up.
- Fixed a bug where the **Notifications drawer** changed size when navigating between **Notifications list** and **Notification details** view.
- containerd integration:
  - `docker push` now supports `Layer already exists` and `Mounted from` progress statuses.
  - `docker save` is now able to export images from all tags of the repository.
  - Hide push upload progress of manifests, configs and indexes (small json blobs) to match the original push behavior.
  - Fixed `docker diff` containing extra differences.
  - Fixed `docker history` not showing intermediate image IDs for images built with the classic builder.
  - Fixed `docker load` not being able to load images from compressed tar archives.
  - Fixed registry mirrors not working.
  - Fixed `docker diff` not working correctly when called multiple times concurrently for the same container.
  - Fixed `docker push` not reusing layers when pushing layers to different repositories on the same registry.
- Docker Init:
  - Fixed outdated links to Docker documentation included in generated files
  - Add support for ASP.NET Core 8 (in addition to 6 and 7)
- Fixed a bug that caused a failure when installing Wasm shims.
- Fixed a bug where Docker Desktop exits the [Resource Saver mode](https://docs.docker.com/desktop/use-desktop/resource-saver/) every 15 minutes, or, if the timer is set above 15 minutes, the resource saver mode never kicks in.
- Promoted the **Enable background SBOM indexing** option to **General settings**.

#### For Mac

- Minimum OS version to install or update Docker Desktop on macOS is now macOS Monterey (version 12) or later.
- Enhanced error messaging when an update cannot be completed if the user doesn't match the owner of `Docker.app`. Fixes [docker/for-mac#7000](https://github.com/docker/for-mac/issues/7000).
- Fixed a bug where **Re-apply configuration** might not work when `/var/run/docker.sock` is mis-configured.
- Docker Desktop doesn't overwrite `ECRCredentialHelper` if already present in `/usr/local/bin`.

#### For Windows

- Fixed an issue where **Switch to Windows Containers** would show in the tray menu on Windows Home Editions. Fixes [docker/for-win#13715](https://github.com/docker/for-win/issues/13715)

#### For Linux

- Fixed a bug in `docker login`. Fixes  [docker/docker-credential-helpers#299](https://github.com/docker/docker-credential-helpers/issues/299)

### Known Issues

#### For Mac

- Upgrading to MacOS 14 can cause Docker Desktop to also update to a latest version even if the auto update option is disabled.
- Uninstalling Docker Desktop from the command line is not available. As a workaround, you can [uninstall Docker Desktop from the Dashboard](https://docs.docker.com/desktop/uninstall/).

#### For Windows

- **Switch to Windows containers** option in the tray menu may not show up on Windows. As a workaround, edit the [`settings.json` file](settings-and-maintenance/settings.md) and set `"displaySwitchWinLinContainers": true`.

#### For all platforms

- Docker operations, such as pulling images or logging in, fail with 'connection refused' or 'timeout' errors if the Swap file size is set to 0MB. As a workaround, configure the swap file size to a non-zero value in the **Resources** tab in **Settings**.

## 4.24.2

{{< release-date date="2023-10-12" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where Docker Desktop would send multiple requests to `notify.bugsnag.com`. Fixes [docker/for-win#13722](https://github.com/docker/for-win/issues/13722).
- Fixed a performance regression for PyTorch.

## 4.24.1

{{< release-date date="2023-10-04" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed a bug on Docker Desktop for Windows where the Docker Desktop Dashboard wouldn't display container logs correctly. Fixes [docker/for-win#13714](https://github.com/docker/for-win/issues/13714).

## 4.24.0

{{< release-date date="2023-09-28" >}}

### New

- The new Notification center is now available to all users so you can be notified of new releases, installation progress updates, and more. Select the bell icon in the bottom-right corner of the Docker Desktop Dashboard to access the notification center.
- Compose Watch is now available to all users. For more information, see [Use Compose Watch](../compose/how-tos/file-watch.md).
- Resource Saver is now available to all users and is enabled by default. To configure this feature, navigate to the **Resources** tab in **Settings**. For more information see [Docker Desktop's Resource Saver mode](use-desktop/resource-saver.md).
- You can now view and manage the Docker Engine state, with pause, stop, and resume, directly from the Docker Desktop Dashboard.

### Upgrades

- [Compose v2.22.0](https://github.com/docker/compose/releases/tag/v2.22.0)
- [Go 1.21.1](https://github.com/golang/go/releases/tag/go1.21.1)
- [Wasm](features/wasm.md) runtimes:
  - wasmtime, wasmedge `v0.2.0`.
  - lunatic, slight, spin, and wws`v0.9.1`.
  - Added wasmer wasm shims.


### Bug fixes and enhancements

#### For all platforms

- Docker Init:
  - Fixed an issue formatting Dockerfile file paths for ASP.NET projects on Windows.
  - Improved performance on language detection for large directories with lots of files.
- Added a timeout to polling for resource usage stats used by the **Containers** view. Fixes [docker/for-mac#6962](https://github.com/docker/for-mac/issues/6962).
- containerd integration:
  - Implemented push/pull/save image events.
  - Implemented pulling legacy schema1 images.
  - Implemented `docker push --all-tags`.
  - Implemented counting containers using a specific image (visible for example in `docker system df -v`).
  - Validated pulled image names are not reserved.
  - Handle `userns-remap` daemon setting.
  - Fixed legacy builder build errors when multiple COPY/ADD instructions are used.
  - Fixed `docker load` causing pool corruption which could some subsequent image related operations.
  - Fixed not being able to reference images via truncated digest with a `sha256:` prefix.
  - Fixed `docker images` (without `--all`) showing intermediate layers (created by the legacy classic builder).
  - Fixed `docker diff` containing extra differences.
  - Changed `docker pull` output to match the output with containerd integration disabled.
- Fixed a grammatical error in Kubernetes status message. See [docker/for-mac#6971](https://github.com/docker/for-mac/issues/6971).
- Docker containers now use all host CPU cores by default.
- Improved inter-process security in dashboard UI.

#### For Mac

- Fixed a kernel panic on Apple Silicon Macs with macOS version earlier than 12.5. Fixes [docker/for-mac#6975](https://github.com/docker/for-mac/issues/6975).
- Fixed a bug where Docker Desktop failed to start if invalid directories were included in `filesharingDirectories`. Fixes [docker/for-mac#6980](https://github.com/docker/for-mac/issues/6980).
- Fixed a bug where installer is creating root-owned directories. Fixes [docker/for-mac#6984](https://github.com/docker/for-mac/issues/6984).
- Fixed a bug where installer is failing on setting up the docker socket when missing `/Library/LaunchDaemons`. Fixes [docker/for-mac#6967](https://github.com/docker/for-mac/issues/6967).
- Fixed a permission denied error when binding a privileged port to a non-localhost IP on macOS. Fixes [docker/for-mac#697](https://github.com/docker/for-mac/issues/6977).
- Fixed a resource leak introduced in 4.23. Related to [docker/for-mac#6953](https://github.com/docker/for-mac/issues/6953).

#### For Windows

- Fixed a bug where a "Docker Desktop service not running" popup appeared when service is already running. See [docker/for-win#13679](https://github.com/docker/for-win/issues/13679).
- Fixed a bug that caused Docker Desktop fail to start on Windows hosts. Fixes [docker/for-win#13662](https://github.com/docker/for-win/issues/13662).
- Modified the Docker Desktop resource saver feature to skip reducing kernel memory on WSL when no containers are running, as this was causing timeouts in some cases. Instead, users are encouraged to enable "autoMemoryReclaim" on WSL directly via the .wslconfig file (available since WSL 1.3.10).

### Known issues

#### For Mac

- Creating a container with the port 53 fails with the error address `already in use`. As a workaround, deactivate network acceleration by adding `"kernelForUDP": false`, in the `settings.json` file located at `~/Library/Group Containers/group.com.docker/settings.json`.

## 4.23.0

{{< release-date date="2023-09-11" >}}

### Upgrades

- [Compose v2.21.0](https://github.com/docker/compose/releases/tag/v2.21.0)
- [Docker Engine v24.0.6](https://docs.docker.com/engine/release-notes/24.0/#2406)
- [Docker Scout CLI v0.24.1](https://github.com/docker/scout-cli/releases/tag/v0.24.1).
- [Wasm](features/wasm.md) runtimes:
  - wasmtime, wasmedge revision `d0a1a1cd`.
  - slight and spin wasm `v0.9.0`.

### New

- Added support for new Wasm runtimes: wws and lunatic.
- [`docker init`](/reference/cli/docker/init/) now supports ASP.NET
- Increased performance of exposed ports on macOS, for example with `docker run -p`.

### Removed

- Removed Compose V1 from Docker Desktop as it has stopped receiving updates.  Compose V2 has replaced it and is now integrated into all current Docker Desktop versions.

### Bug fixes and enhancements

#### For all platforms

- With [Docker Scout](../scout/index.md), you can now:
  - Manage temporary and cached files with `docker scout cache`.
  - Manage environments with `docker scout environment`.
  - Configure the default organization with `docker scout config`.
  - List packages of an image with their vulnerabilities with `docker scout cves --format only-packages`.
  - Enroll an organization with Docker scout with `docker scout enroll`.
  - Stop, analyze, and compare local file systems with `docker scout cves --type fs`.
- Fixed a bug where `docker stats` would hang when Docker Desktop was in Resource Saver mode.
- Fixed a bug where turning off experimental features via **Settings** in the Docker Desktop Dashboard would not fully turn off Resource Saver mode.
- Fixed a bug where the **Containers list** action button was clipped.
- containerd image store:
  - Fixed `failed to read config content` error when interacting with some images.
  - Fixed building Dockerfiles with `FROM scratch` instruction when using the legacy classic builder (`DOCKER_BUILDKIT=0`).
  - Fixed `mismatched image rootfs errors` when building images with legacy classic builder (`DOCKER_BUILDKIT=0`).
  - Fixed `ONBUILD` and `MAINTAINER` Dockerfile instruction
  - Fixed healthchecks.

#### For Mac

- All users on macOS 12.5 or greater now have VirtioFS turned on by default. You can revert this in **Settings** in the **General** tab.
- Improved single-stream TCP throughput.
- Reinstated the health check for macOS that notifies you if there has been a change on your system which might cause problems running Docker binaries.

#### For Linux

- Fixed a bug where the GUI is killed when opening the Docker Desktop app twice. See [docker/desktop-linux#148](https://github.com/docker/desktop-linux/issues/148).

#### For Windows

- Fixed a bug where non-admin users would get prompted for credentials when switching to Windows Containers or after disabling WSL and switching to the Hyper-V engine.
  This issue would occur after an OS restart, or on a cold start of Docker Desktop.

### Security

#### For all platforms

- Fixed [CVE-2023-5165](https://www.cve.org/cverecord?id=CVE-2023-5165) which allows Enhanced Container Isolation bypass via debug shell. The affected functionality is available for Docker Business customers only and assumes an environment where users are not granted local root or Administrator privileges.
- Fixed [CVE-2023-5166](https://www.cve.org/cverecord?id=CVE-2023-5166) which allows Access Token theft via a crafted extension icon URL.

### Known Issues

- Binding a privileged port on Docker Desktop does not work on macOS. As a workaround you can expose the port on all interfaces (using `0.0.0.0`) or using localhost (using `127.0.0.1`).

## 4.22.1

{{< release-date date="2023-08-24" >}}

### Bug fixes and enhancements

#### For all platforms

- Mitigated several issues impacting Docker Desktop startup and Resource Saver mode. [docker/for-mac#6933](https://github.com/docker/for-mac/issues/6933)

#### For Windows

- Fixed `Clean / Purge data` troubleshoot option on Windows. [docker/for-win#13630](https://github.com/docker/for-win/issues/13630)

## 4.22.0

{{< release-date date="2023-08-03" >}}

### Upgrades

- [Buildx v0.11.2](https://github.com/docker/buildx/releases/tag/v0.11.2)
- [Compose v2.20.2](https://github.com/docker/compose/releases/tag/v2.20.2)
- [Docker Engine v24.0.5](https://docs.docker.com/engine/release-notes/24.0/#2405)

> [!NOTE]
>
> In this release, the bundled Docker Compose and Buildx binaries show a different version string. This relates to our efforts to test new features without causing backwards compatibility issues.
>
> For example, `docker buildx version` outputs `buildx v0.11.2-desktop.1`.

### New

- [Resource Usage](use-desktop/container.md) has moved from experimental to GA.
- You can now split large Compose projects into multiple sub-projects with [`include`](../compose/how-tos/multiple-compose-files/include.md).

### Bug fixes and enhancements

#### For all platforms

- [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md) now lets you turn off Docker Extensions for your organisation.
- Fixed a bug where turning on Kubernetes from the UI failed when the system was paused.
- Fixed a bug where turning on Wasm from the UI failed when the system was paused.
- Bind mounts are now shown when you [inspect a container](use-desktop/container.md).
- You can now download Wasm runtimes when the containerd image store is enabled.
- With [Quick Search](use-desktop/index.md#quick-search), you can now:
  - Find any container or Compose app residing on your local system. In
    addition, you can access environment variables and perform essential actions
    such as starting, stopping, or deleting containers.
  - Find public Docker Hub images, local images, or images from remote
    repositories.
  - Discover more about specific extensions and install them.
  - Navigate through your volumes and gain insights about the associated
    containers.
  - Search and access Docker's documentation.

#### For Mac

- Fixed a bug that prevented Docker Desktop from starting. [docker/for-mac#6890](https://github.com/docker/for-mac/issues/6890)
- Resource Saver is now available on Mac. It optimises Docker Desktop's usage of your system resources when no containers are running. To access this feature, make sure you have [turned on access to experimental features](settings-and-maintenance/settings.md) in settings.

#### For Windows

- Fixed a bug where the self-diagnose tool showed a false-positive failure when vpnkit is expected to be not running. Fixes [docker/for-win#13479](https://github.com/docker/for-win/issues/13479).
- Fixed a bug where an invalid regular expression in the search bar caused an error. Fixes [docker/for-win#13592](https://github.com/docker/for-win/issues/13592).
- Resource Saver is now available on Windows Hyper-V. It optimises Docker Desktop's usage of your system resources when no containers are running. To access this feature, make sure you have [turned on access to experimental features](settings-and-maintenance/settings.md) in settings.

## 4.21.1

{{< release-date date="2023-07-03" >}}

#### For all platforms

- Fixed connection leak for Docker contexts using SSH ([docker/for-mac#6834](https://github.com/docker/for-mac/issues/6834) and [docker/for-win#13564](https://github.com/docker/for-win/issues/13564))

#### For Mac

- Removed configuration health check for further investigation and addressing specific setups.

## 4.21.0

{{< release-date date="2023-06-29" >}}

### New

- Added support for new Wasm runtimes: slight, spin, and wasmtime. Users can download Wasm runtimes on demand when the containerd image store is enabled.
- Added Rust server support to Docker init.
- Beta release of the [**Builds** view](use-desktop/builds.md) that lets you inspect builds and manage builders. This can be found in the **Features in Development** tab in **Settings**.

### Upgrades

- [Buildx v0.11.0](https://github.com/docker/buildx/releases/tag/v0.11.0)
- [Compose v2.19.0](https://github.com/docker/compose/releases/tag/v2.19.0)
- [Kubernetes v1.27.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.27.2)
- [cri-tools v1.27.0](https://github.com/kubernetes-sigs/cri-tools/releases/tag/v1.27.0)
- [cri-dockerd v0.3.2](https://github.com/Mirantis/cri-dockerd/releases/tag/v0.3.2)
- [coredns v1.10.1](https://github.com/coredns/coredns/releases/tag/v1.10.1)
- [cni v1.2.0](https://github.com/containernetworking/plugins/releases/tag/v1.2.0)
- [etcd v3.5.7](https://github.com/etcd-io/etcd/releases/tag/v3.5.7)

### Bug fixes and enhancements

#### For all platforms

- Docker Desktop now automatically pauses the Docker Engine when it is not in use and wakes up again on demand.
- VirtioFS is now the default file sharing implementation for new installations of Docker Desktop on macOS 12.5 and higher.
- Improved product usage reporting using OpenTelemetry (experimental).
- Fixed Docker socket permissions. Fixes [docker/for-win#13447](https://github.com/docker/for-win/issues/13447) and [docker/for-mac#6823](https://github.com/docker/for-mac/issues/6823).
- Fixed an issue which caused Docker Desktop to hang when quitting the application whilst paused.
- Fixed a bug which caused the **Logs** and **Terminal** tab content in the **Container** view to be covered by a fixed toolbar [docker/for-mac#6814](https://github.com/docker/for-mac/issues/6814).
- Fixed a bug which caused input labels to overlap with input values on the container run dialog. Fixes [docker/for-win#13304](https://github.com/docker/for-win/issues/13304).
- Fixed a bug which meant users couldn't select the Docker Extension menu. Fixes [docker/for-mac#6840](https://github.com/docker/for-mac/issues/6840) and [docker/for-mac#6855](https://github.com/docker/for-mac/issues/6855)

#### For Mac

- Added a health check for macOS that notifies users if there has been a change on their system which might cause problems running Docker binaries.

#### For Windows

- Fixed a bug on WSL 2 where if Desktop is paused, killed, and then restarted, the startup hangs unless WSL is shut down first with `wsl --shutdown`.
- Fixed the WSL engine in cases where wsl.exe is not on the PATH [docker/for-win#13547](https://github.com/docker/for-win/issues/13547).
- Fixed the WSL engine's ability to detect cases where one of the Docker Desktop distributions' drive is missing [docker/for-win#13554](https://github.com/docker/for-win/issues/13554).
- A slow or unresponsive WSL integration no longer prevents Docker Desktop from starting. Fixes [docker/for-win#13549](https://github.com/docker/for-win/issues/13549).
- Fixed a bug that caused Docker Desktop to crash on startup [docker/for-win#6890](https://github.com/docker/for-mac/issues/6890).
- Added the following installer flags:
  - `--hyper-v-default-data-root` which specifies the default location for Hyper-V VM disk.
  - `--windows-containers-default-data-root` which specifies the default data root for Windows Containers.
  - `--wsl-default-data-root` which specifies the default location for WSL distribution disks.

## 4.20.1

{{< release-date date="2023-06-05" >}}

### Bug fixes and enhancements

#### For all platforms

- containerd image store: Fixed a bug that caused `docker load` to fail when loading an image that contains attestations.
- containerd image store: Fixed the default image exporter during build.

#### For Windows

- Fixed a bug that made it difficult to parse the WSL version on the host in non-western locales. Fixes [docker/for-win#13518](https://github.com/docker/for-win/issues/13518) and [docker/for-win#13524](https://github.com/docker/for-win/issues/13524).

## 4.20.0

{{< release-date date="2023-05-30" >}}

### Upgrades

- [Buildx v0.10.5](https://github.com/docker/buildx/releases/tag/v0.10.5)
- [Compose v2.18.1](https://github.com/docker/compose/releases/tag/v2.18.1)
- [Docker Engine v24.0.2](https://docs.docker.com/engine/release-notes/24.0/#2402)
- [Containerd v1.6.21](https://github.com/containerd/containerd/releases/tag/v1.6.21)
- [runc v1.1.7](https://github.com/opencontainers/runc/releases/tag/v1.1.5)

### Bug fixes and enhancements

#### For all platforms

- [Docker Scout CLI](https://docs.docker.com/scout/#docker-scout-cli) now finds the most recently built image if it is not provided as an argument.
- Improved the [Docker Scout CLI](https://docs.docker.com/scout/#docker-scout-cli) `compare` command.
- Added a warning about the [retirement of Docker Compose ECS/ACS integrations in November 2023](https://docs.docker.com/go/compose-ecs-eol/). Can be suppressed with `COMPOSE_CLOUD_EOL_SILENT=1`.
- Fixed an HTTP proxy bug where an HTTP 1.0 client could receive an HTTP 1.1 response.
- Enabled Docker Desktop's Enhanced Container Isolation (ECI) feature on WSL-2. This is available with a Docker Business subscription.
- Fixed a bug on the **Containers** table where previously hidden columns were displayed again after a fresh installation of Docker Desktop.

#### For Mac

- You can now reclaim disk space more quickly when files are deleted in containers. Related to [docker/for-mac#371](https://github.com/docker/for-mac/issues/371).
- Fixed a bug that prevented containers accessing 169.254.0.0/16 IPs. Fixes [docker/for-mac#6825](https://github.com/docker/for-mac/issues/6825).
- Fixed a bug in `com.docker.diagnose check` where it would complain about a missing vpnkit even when vpnkit is not expected to be running. Related to [docker/for-mac#6825](https://github.com/docker/for-mac/issues/6825).

#### For Windows

- Fixed a bug that meant WSL data could not be moved to a different disk. Fixes [docker/for-win#13269](https://github.com/docker/for-win/issues/13269).
- Fixed a bug where Docker Desktop was not stopping its WSL distributions (docker-desktop and docker-desktop-data) when it was shutdown, consuming host memory unnecessarily.
- Added a new setting that allows the Windows Docker daemon to use Docker Desktop's internal proxy when running Windows containers. See [Windows proxy settings](settings-and-maintenance/settings.md#proxies).

#### For Linux

- Fixed an issue with the Docker Compose V1/V2 compatibility setting.

## 4.19.0

{{< release-date date="2023-04-27" >}}

### New

- Docker Engine and CLI updated to [Moby 23.0](https://github.com/moby/moby/releases/tag/v23.0.0).
- The **Learning Center** now supports in-product walkthroughs.
- Docker init (Beta) now supports Node.js and Python.
- Faster networking between VM and host on macOS.
- You can now inspect and analyze remote images from Docker Desktop without pulling them.
- Usability and performance improvements to the **Artifactory images** view.

### Removed

- Removed `docker scan` command. To continue learning about the vulnerabilities of your images, and many other features, use the new `docker scout` command. Run `docker scout --help`, or [read the docs to learn more](/reference/cli/docker/scout/).

### Upgrades

- [Docker Engine v23.0.5](https://docs.docker.com/engine/release-notes/23.0/#2305)
- [Compose 2.17.3](https://github.com/docker/compose/releases/tag/v2.17.3)
- [Containerd v1.6.20](https://github.com/containerd/containerd/releases/tag/v1.6.20)
- [Kubernetes v1.25.9](https://github.com/kubernetes/kubernetes/releases/tag/v1.25.9)
- [runc v1.1.5](https://github.com/opencontainers/runc/releases/tag/v1.1.5)
- [Go v1.20.3](https://github.com/golang/go/releases/tag/go1.20.3)

### Bug fixes and enhancements

#### For all platforms

- Improved `docker scout compare` command to compare two images, now also aliased under `docker scout diff`.
- Added more details to dashboard errors when a `docker-compose` action fails ([docker/for-win#13378](https://github.com/docker/for-win/issues/13378)).
- Added support for setting HTTP proxy configuration during installation. This can be done via the `--proxy-http-mode`, `--overrider-proxy-http`, `--override-proxy-https` and `--override-proxy-exclude` installer flags in the case of installation from the CLI on [Mac](setup/install/mac-install.md#install-from-the-command-line) and [Windows](setup/install/windows-install.md#install-from-the-command-line), or alternatively by setting the values in the `install-settings.json` file.
- Docker Desktop now stops overriding .docker/config.json `credsStore` keys on application start. Note that if you use a custom credential helper then the CLI `docker login` and `docker logout` does not affect whether the UI is signed in to Docker or not. In general, it is better to sign into Docker via the UI since the UI supports multi-factor authentication.
- Added a warning about the forthcoming removal of Compose V1 from Docker Desktop. Can be suppressed with `COMPOSE_V1_EOL_SILENT=1`.
- In the Compose config, boolean fields in YAML should be either `true` or `false`. Deprecated YAML 1.1 values such as “on” or “no” now produce a warning.
- Improved UI for image table, allowing rows to use more available space.
- Fixed various bugs in port-forwarding.
- Fixed a HTTP proxy bug where an HTTP request without a Server Name Indication record would be rejected with an error.

#### For Windows

- Reverted to fully patching etc/hosts on Windows (includes `host.docker.internal` and `gateway.docker.internal` again). For WSL, this behavior is controlled by a new setting in the **General** tab. Fixes [docker/for-win#13388](https://github.com/docker/for-win/issues/13388) and [docker/for-win#13398](https://github.com/docker/for-win/issues/13398).
- Fixed a spurious `courgette.log` file appearing on the Desktop when updating Docker Desktop. Fixes [docker/for-win#12468](https://github.com/docker/for-win/issues/12468).
- Fixed the "zoom in" shortcut (ctrl+=). Fixes [docker/for-win#13392](https://github.com/docker/for-win/issues/13392).
- Fixed a bug where the tray menu would not correctly update after second container type switch. Fixes [docker/for-win#13379](https://github.com/docker/for-win/issues/13379).

#### For Mac

- Increased the performance of VM networking when using the Virtualization framework on macOS Ventura and above. Docker Desktop for Mac now uses gVisor instead of VPNKit. To continue using VPNKit, add `"networkType":"vpnkit"` to your `settings.json` file located at `~/Library/Group Containers/group.com.docker/settings.json`.
- Fixed a bug where an error window is displayed on uninstall.
- Fixed a bug where the setting `deprecatedCgroupv1` was ignored. Fixes [docker/for-mac#6801](https://github.com/docker/for-mac/issues/6801).
- Fixed cases where `docker pull` would return `EOF`.

#### For Linux

- Fixed a bug where the VM networking crashes after 24h. Fixes [docker/desktop-linux#131](https://github.com/docker/desktop-linux/issues/131).

### Security

#### For all platforms

- Fixed a security issue allowing users to bypass Image Access Management (IAM) restrictions configured by their organisation by avoiding `registry.json` enforced login via deleting the `credsStore` key from their Docker CLI configuration file. Only affects Docker Business customers.
- Fixed [CVE-2023-24532](https://github.com/advisories/GHSA-x2w5-7wp4-5qff).
- Fixed [CVE-2023-25809](https://github.com/advisories/GHSA-m8cg-xc2p-r3fc).
- Fixed [CVE-2023-27561](https://github.com/advisories/GHSA-vpvm-3wq2-2wvm).
- Fixed [CVE-2023-28642](https://github.com/advisories/GHSA-g2j6-57v7-gm8c).
- Fixed [CVE-2023-28840](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28840).
- Fixed [CVE-2023-28841](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28841).
- Fixed [CVE-2023-28842](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28842).

## 4.18.0

{{< release-date date="2023-04-03" >}}

### New

- Initial beta release of `docker init` as per [the roadmap](https://github.com/docker/roadmap/issues/453).
- Added a new **Learning Center** tab to help users get started with Docker.
- Added an experimental file-watch command to Docker Compose that automatically updates your running Compose services as you edit and save your code.

### Upgrades

- [Buildx v0.10.4](https://github.com/docker/buildx/releases/tag/v0.10.4)
- [Compose 2.17.2](https://github.com/docker/compose/releases/tag/v2.17.2)
- [Containerd v1.6.18](https://github.com/containerd/containerd/releases/tag/v1.6.18), which includes fixes for [CVE-2023-25153](https://github.com/advisories/GHSA-259w-8hf6-59c2) and [CVE-2023-25173](https://github.com/advisories/GHSA-hmfx-3pcx-653p).
- [Docker Engine v20.10.24](https://docs.docker.com/engine/release-notes/20.10/#201024), which contains fixes for [CVE-2023-28841](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28841),
  [CVE-2023-28840](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28840), and
  [CVE-2023-28842](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28842).

### Bug fixes and enhancements

#### For all platforms

- [Docker Scout CLI](../scout/index.md#docker-scout-cli) can now compare two images and display packages and vulnerabilities differences. This command is in [Early Access](../release-lifecycle.md) and might change in the future.
- [Docker Scout CLI](../scout/index.md#docker-scout-cli) now displays base image update and remediation recommendations using `docker scout recommendations`. It also displays a short overview of an image using `docker scout quickview` commands.
- You can now search for extensions direct from the Marketplace, as well as using **Global Search**.
- Fixed a bug where `docker buildx` container builders would lose access to the network after 24hrs.
- Reduced how often users are prompted for feedback on Docker Desktop.
- Removed minimum VM swap size.
- Added support for subdomain match, CIDR match, `.` and `_.` in HTTP proxy exclude lists.
- Fixed a bug in the transparent TLS proxy when the Server Name Indication field is not set.
- Fixed a grammatical error in Docker Desktop engine status message.

### For Windows

- Fixed a bug where `docker run --gpus=all` hangs. Fixes [docker/for-win#13324](https://github.com/docker/for-win/issues/13324).
- Fixed a bug where Registry Access Management policy updates were not downloaded.
- Docker Desktop now allows Windows containers to work when BitLocker is enabled on `C:`.
- Docker Desktop with the WSL backend no longer requires the `com.docker.service` privileged service to run permanently. For more information see [Permission requirements for Windows](setup/install/windows-permission-requirements.md).

### For Mac

- Fixed a performance issue where attributes stored on the host would not be cached for VirtioFS users.
- The first time Docker Desktop for Mac is launched, the user is presented with an installation window to confirm or adjust the configuration that requires privileged access. For more information see [Permission requirements for Mac](https://docs.docker.com/desktop/mac/permission-requirements/).
- Added the **Advanced** tab in **Settings**, where users can adjust the settings which require privileged access.

### For Linux

- Fixed a bug where the VM networking crashes after 24h. [docker/for-linux#131](https://github.com/docker/desktop-linux/issues/131)

### Security

#### For all platforms

- Fixed [CVE-2023-1802](https://www.cve.org/cverecord?id=CVE-2023-1802) where a security issue with the Artifactory Integration would cause it to fall back to sending registry credentials over plain HTTP if HTTPS check failed. Only users who have `Access experimental features` enabled are affected. Fixes [docker/for-win#13344](https://github.com/docker/for-win/issues/13344).

#### For Mac

- Removed the `com.apple.security.cs.allow-dyld-environment-variables` and `com.apple.security.cs.disable-library-validation` entitlements which allow an arbitrary dynamic library to be loaded with Docker Desktop via the `DYLD_INSERT_LIBRARIES` environment variable.

### Known Issues

- Uninstalling Docker Desktop on Mac from the **Troubleshoot** page might trigger an unexpected fatal error popup.

## 4.17.1

{{< release-date date="2023-03-20" >}}

### Bug fixes and enhancements

#### For Windows

- Docker Desktop now allows Windows containers to work when BitLocker is enabled on C:
- Fixed a bug where `docker buildx` container builders would lose access to the network after 24hrs.
- Fixed a bug where Registry Access Management policy updates were not downloaded.
- Improved debug information to better characterise failures under WSL 2.

### Known Issues

- Running containers with `--gpus` on Windows with the WSL 2 backend does not work. This will be fixed in future releases. See [docker/for-win/13324](https://github.com/docker/for-win/issues/13324).

## 4.17.0

{{< release-date date="2023-02-27" >}}

### New

- Docker Desktop now ships with Docker Scout. Pull and view analysis for images from Docker Hub and Artifactory repositories, get base image updates and recommended tags and digests, and filter your images on vulnerability information. To learn more, see [Docker Scout](../scout/index.md).
- `docker scan` has been replaced by `docker scout`. See [Docker Scout CLI](../scout/index.md#docker-scout-cli), for more information.
- You can now discover extensions that have been autonomously published in the Extensions Marketplace. For more information on self-published extensions, see [Marketplace Extensions](../extensions/marketplace.md).
- **Container File Explorer** is available as an experimental feature. Debug the filesystem within your containers straight from the GUI.
- You can now search for volumes in **Global Search**.

### Upgrades

- [Containerd v1.6.18](https://github.com/containerd/containerd/releases/tag/v1.6.18), which includes fixes for [CVE-2023-25153](https://github.com/advisories/GHSA-259w-8hf6-59c2) and [CVE-2023-25173](https://github.com/advisories/GHSA-hmfx-3pcx-653p).
- [Docker Engine v20.10.23](https://docs.docker.com/engine/release-notes/20.10/#201023).
- [Go 1.19.5](https://github.com/golang/go/releases/tag/go1.19.5)

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where diagnostic gathering could hang waiting for a subprocess to exit.
- Prevented the transparent HTTP proxy from mangling requests too much. Fixes Tailscale extension login, see [tailscale/docker-extension#49](https://github.com/tailscale/docker-extension/issues/49).
- Fixed a bug in the transparent TLS proxy where the Server Name Indication field is not set.
- Added support for subdomain match, CIDR match, `.` and `*.` in HTTP proxy exclude lists.
- Ensured HTTP proxy settings are respected when uploading diagnostics.
- Fixed fatal error when fetching credentials from the credential helper.
- Fixed fatal error related to concurrent logging.
- Improved the UI for Extension actions in the Marketplace.
- Added new filters in the Extensions Marketplace. You can now filter extensions by category and reviewed status.
- Added a way to report a malicious extension to Docker.
- Updated Dev Environments to v0.2.2 with initial set up reliability & security fixes.
- Added a whalecome survey for new users only.
- The confirmation dialogs on the troubleshooting page are now consistent in style with other similar dialogs.
- Fixed fatal error caused by resetting the Kubernetes cluster before it has started.
- Implemented `docker import` for the containerd integration.
- Fixed image tagging with an existing tag with the containerd integration.
- Implemented the dangling filter on images for the containerd integration.
- Fixed `docker ps` failing with containers whose images are no longer present with the containerd integration.

#### For Mac

- Fixed download of Registry Access Management policy on systems where the privileged helper tool `com.docker.vmnetd` is not installed.
- Fixed a bug where `com.docker.vmnetd` could not be installed if `/Library/PrivilegedHelperTools` does not exist.
- Fixed a bug where the "system" proxy would not handle "autoproxy" / "pac file" configurations.
- Fixed a bug where vmnetd installation fails to read `Info.Plist` on case-sensitive file systems. The actual filename is `Info.plist`. Fixes [docker/for-mac#6677](https://github.com/docker/for-mac/issues/6677).
- Fixed a bug where user is prompted to create the docker socket symlink on every startup. Fixes [docker/for-mac#6634](https://github.com/docker/for-mac/issues/6634).
- Fixed a bug that caused the **Start Docker Desktop when you log in** setting not to work. Fixes [docker/for-mac#6723](https://github.com/docker/for-mac/issues/6723).
- Fixed UDP connection tracking and `host.docker.internal`. Fixes [docker/for-mac#6699](https://github.com/docker/for-mac/issues/6699).
- Improved kubectl symlink logic to respect existing binaries in `/usr/local/bin`. Fixes [docker/for-mac#6328](https://github.com/docker/for-mac/issues/6328).
- Docker Desktop now automatically installs Rosetta when you opt-in to use it but have not already installed it.

### For Windows

- Added statical linking of WSL integration tools against `musl` so there is no need to install `alpine-pkg-glibc` in user distributions.
- Added support for running under cgroupv2 on WSL 2. This is activated by adding `kernelCommandLine = systemd.unified_cgroup_hierarchy=1 cgroup_no_v1=all` to your `%USERPROFILE%\.wslconfig` file in the `[wsl2]` section.
- Fixed an issue that caused Docker Desktop to get stuck in the "starting" phase when in WSL 2 mode (introduced in 4.16).
- Fixed Docker Desktop failing to start the WSL 2 backend when file system compression or encryption is enabled on `%LOCALAPPDATA%`.
- Fixed Docker Desktop failing to report a missing or outdated (incapable of running WSL version 2 distributions) WSL installation when starting.
- Fixed a bug where opening in Visual Studio Code fails if the target path has a space.
- Fixed a bug that causes `~/.docker/context` corruption and the error message "unexpected end of JSON input". You can also remove `~/.docker/context` to work around this problem.
- Ensured the credential helper used in WSL 2 is properly signed. Related to [docker/for-win#10247](https://github.com/docker/for-win/issues/10247).
- Fixed an issue that caused WSL integration agents to be terminated erroneously. Related to [docker/for-win#13202](https://github.com/docker/for-win/issues/13202).
- Fixed corrupt contexts on start. Fixes [docker/for-win#13180](https://github.com/docker/for-win/issues/13180) and [docker/for-win#12561](https://github.com/docker/for-win/issues/12561).

### For Linux

- Added Docker Buildx plugin for Docker Desktop for Linux.
- Changed compression algorithm to `xz` for RPM and Arch Linux distribution.
- Fixed a bug that caused leftover files to be left in the root directory of the Debian package. Fixes [docker/for-linux#123](https://github.com/docker/desktop-linux/issues/123).

### Security

#### For all platforms

- Fixed [CVE-2023-0628](https://www.cve.org/cverecord?id=CVE-2023-0628), which allows an attacker to execute an arbitrary command inside a Dev Environments container during initialization by tricking a user to open a crafted malicious `docker-desktop://` URL.
- Fixed [CVE-2023-0629](https://www.cve.org/cverecord?id=CVE-2023-0629), which allows an unprivileged user to bypass Enhanced Container Isolation (ECI) restrictions by setting the Docker host to `docker.raw.sock`, or `npipe:////.pipe/docker_engine_linux` on Windows, via the `-H` (`--host`) CLI flag or the `DOCKER_HOST` environment variable and launch containers without the additional hardening features provided by ECI. This does not affect already running containers, nor containers launched through the usual approach (without Docker's raw socket).

## 4.16.3

{{< release-date date="2023-01-30" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed Docker Desktop failing to start the WSL 2 backend when file system compression or encryption is enabled on `%LOCALAPPDATA%`. Fixes [docker/for-win#13184](https://github.com/docker/for-win/issues/13184).
- Fixed Docker Desktop failing to report a missing or outdated WSL installation when starting. Fixes [docker/for-win#13184](https://github.com/docker/for-win/issues/13184).

## 4.16.2

{{< release-date date="2023-01-19" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where `docker build` and `docker tag` commands produced an `image already exists` error if the containerd integration feature is enabled.
- Fixed a regression introduced with Docker Desktop 4.16 breaking networking from containers with target platform linux/386 on amd64 systems. Fixes [docker/for-mac/6689](https://github.com/docker/for-mac/issues/6689).

#### For Mac

- Fixed the capitalization of `Info.plist` which caused `vmnetd` to break on case-sensitive file systems. Fixes [docker/for-mac/6677](https://github.com/docker/for-mac/issues/6677).

#### For Windows

- Fixed a regression introduced with Docker Desktop 4.16 causing it to get stuck in the "starting" phase when in WSL2 mode. Fixes [docker/for-win/13165](https://github.com/docker/for-win/issues/13165)

## 4.16.1

{{< release-date date="2023-01-13" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed `sudo` inside a container failing with a security related error for some images. Fixes [docker/for-mac/6675](https://github.com/docker/for-mac/issues/6675) and [docker/for-win/13161](https://github.com/docker/for-win/issues/13161).

## 4.16.0

{{< release-date date="2023-01-12" >}}

### New

- Extensions have moved from Beta to GA.
- Quick Search has moved from experimental to GA.
- Extensions are now included in Quick Search.
- Analyzing large images is now up to 4x faster.
- New local images view has moved from experimental to GA.
- New Beta feature for MacOS 13, Rosetta for Linux, has been added for faster emulation of Intel-based images on Apple Silicon.

### Upgrades

- [Compose v2.15.1](https://github.com/docker/compose/releases/tag/v2.15.1)
- [Containerd v1.6.14](https://github.com/containerd/containerd/releases/tag/v1.6.14)
- [Docker Engine v20.10.22](https://docs.docker.com/engine/release-notes/20.10/#201022)
- [Buildx v0.10.0](https://github.com/docker/buildx/releases/tag/v0.10.0)
- [Docker Scan v0.23.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.23.0)
- [Go 1.19.4](https://github.com/golang/go/releases/tag/go1.19.4)

### Bug fixes and enhancements

#### For all platforms

- Fixed `docker build --quiet` not outputting the image identifier with the `containerd` integration.
- Fixed image inspect not showing image labels with the `containerd` integration.
- Increased the contrast between running and stopped container icons to make it easier for colorblind people to scan the containers list.
- Fixed a bug where the user is prompted for new HTTP proxy credentials repeatedly until Docker Desktop is restarted.
- Added a diagnostics command `com.docker.diagnose login` to check HTTP proxy configuration.
- Fixed actions on compose stack not working properly. Fixes [docker/for-mac#6566](https://github.com/docker/for-mac/issues/6566).
- Fixed the Docker Desktop Dashboard trying at startup to get disk usage information and display an error banner before the engine was running.
- Added an informational banner with instructions on how to opt-out of experimental feature access next to all experimental features.
- Docker Desktop now supports downloading Kubernetes images via an HTTP proxy.
- Fixed tooltips to not block action buttons. Fixes [docker/for-mac#6516](https://github.com/docker/for-mac/issues/6516).
- Fixed the blank "An error occurred" container list on the **Container** view.

#### For Mac

- Minimum OS version to install or update Docker Desktop on macOS is now macOS Big Sur (version 11) or later.
- Fixed the Docker engine not starting when Enhanced Container Isolation is enabled if the legacy `osxfs` implementation is used for file sharing.
- Fixed files created on VirtioFS having the executable bit set. Fixes [docker/for-mac#6614](https://github.com/docker/for-mac/issues/6614).
- Added back a way to uninstall Docker Desktop from the command line. Fixes [docker/for-mac#6598](https://github.com/docker/for-mac/issues/6598).
- Fixed hardcoded `/usr/bin/kill`. Fixes [docker/for-mac#6589](https://github.com/docker/for-mac/issues/6589).
- Fixed truncation (for example with the `truncate` command) of very large files (> 38GB) shared on VirtioFS with an incorrect size.
- Changed the disk image size in **Settings** to use the decimal system (base 10) to coincide with how Finder displays disk capacity.
- Fixed Docker crash under network load. Fixes [docker/for-mac#6530](https://github.com/docker/for-mac/issues/6530).
- Fixed an issue causing Docker to prompt the user to install the `/var/run/docker.sock` symlink after every reboot.
- Ensured the Login Item which installs the `/var/run/docker.sock` symlink is signed.
- Fixed bug where `$HOME/.docker` was removed on factory reset.

### For Windows

- Fixed `docker build` hanging while printing "load metadata for". Fixes [docker/for-win#10247](https://github.com/docker/for-win/issues/10247).
- Fixed typo in diagnose.exe output Fixes [docker/for-win#13107](https://github.com/docker/for-win/issues/13107).
- Added support for running under cgroupv2 on WSL 2. This is activated by adding `kernelCommandLine = systemd.unified_cgroup_hierarchy=1 cgroup_no_v1=all` to your `%USERPROFILE%\.wslconfig` file in the `[wsl2]` section.

### Known Issues

- Calling `sudo` inside a container fails with a security related error for some images. See [docker/for-mac/6675](https://github.com/docker/for-mac/issues/6675) and [docker/for-win/13161](https://github.com/docker/for-win/issues/13161).

## 4.15.0

{{< release-date date="2022-12-01" >}}

### New

- Substantial performance improvements for macOS users with the option of enabling the new VirtioFS file sharing technology. Available for macOS 12.5 and above.
- Docker Desktop for Mac no longer needs to install the privileged helper process `com.docker.vmnetd` on install or on the first run. For more information see [Permission requirements for Mac](https://docs.docker.com/desktop/mac/permission-requirements/).
- Added [WebAssembly capabilities](features/wasm.md). Use with the [containerd integration](features/containerd.md).
- Improved the descriptions for beta and experimental settings to clearly explain the differences and how people can access them.
- Available disk space of VM now displays in the footer of Docker Desktop Dashboard for Mac and Linux.
- A disk space warning now displays in the footer if available space is below 3GB.
- Changes to Docker Desktop's interface as we become more ADA accessible and visually unified.
- Added a **Build** tab inside **Extensions** which contains all the necessary resources to build an extension.
- Added the ability to share extensions more easily, either with `docker extension share` CLI or with the share button in the extensions **Manage** tab.
- Extensions in the Marketplace now display the number of installs. You can also sort extensions by the number of installs.
- Dev Environments allow cloning a Git repository to a local bind mount, so you can use any local editor or IDE.
- More Dev Environments improvements: custom names, better private repo support, improved port handling.

### Upgrades

- [Compose v2.13.0](https://github.com/docker/compose/releases/tag/v2.13.0)
- [Containerd v1.6.10](https://github.com/containerd/containerd/releases/tag/v1.6.10)
- [Docker Hub Tool v0.4.5](https://github.com/docker/hub-tool/releases/tag/v0.4.5)
- [Docker Scan v0.22.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.22.0)

### Bug fixes and enhancements

#### For all platforms

- Containers are now restored on restart with the containerd integration.
- Fixed listing multi-platform images with the containerd integration.
- Better handling of dangling images with the containerd integration.
- Implement "reference" filter for images with the containerd integration.
- Added support for selecting upstream HTTP/HTTPS proxies automatically via `proxy.pac` in containers, `docker pull` etc.
- Fixed regressions when parsing image references on pull. Fixes [docker/for-win#13053](https://github.com/docker/for-win/issues/13053), [docker/for-mac#6560](https://github.com/docker/for-mac/issues/6560), and [docker/for-mac#6540](https://github.com/docker/for-mac/issues/6540).

#### For Mac

- Improved the performance of `docker pull`.

#### For Windows

- Fixed an issue where the system HTTP proxies were not used when Docker starts and the developer logs in.
- When Docker Desktop is using "system" proxies and if the Windows settings change, Docker Desktop now uses the new Windows settings without a restart.

#### For Linux

- Fixed hot-reload issue on Linux. Fixes [docker/desktop-linux#30](https://github.com/docker/desktop-linux/issues/30).
- Disabled tray icon animations on Linux which fixes crashes for some users.

## 4.14.1

{{< release-date date="2022-11-17" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed container DNS lookups when using Registry Access Management.

#### For Mac

- Fixed an issue preventing the **Analyze Image** button on the **Images** tab from working.
- Fixed a bug causing symlinks to not be created for the user if `/usr/local/lib` doesn't already exist. Fixes [docker/for-mac#6569](https://github.com/docker/for-mac/issues/6569)

## 4.14.0

{{< release-date date="2022-11-10" >}}

### New

- Set Virtualization framework as the default hypervisor for macOS >= 12.5.
- Migrate previous install to Virtualization framework hypervisor for macOS >= 12.5.
- The Enhanced Container Isolation feature, available to Docker Business users, can now be enabled from the General Settings.

### Updates

- [Docker Engine v20.10.21](../engine/release-notes/20.10.md#201021),
  which contains mitigations against a Git vulnerability, tracked in [CVE-2022-39253](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253),
  and updates the handling of `image:tag@digest` image references.
- [Docker Compose v2.12.2](https://github.com/docker/compose/releases/tag/v2.12.2)
- [Containerd v1.6.9](https://github.com/containerd/containerd/releases/tag/v1.6.9)
- [Go 1.19.3](https://github.com/golang/go/releases/tag/go1.19.3)

### Bug fixes and enhancements

#### For all platforms

- Docker Desktop now requires an internal network subnet of size /24. If you were previously using a /28, it is automatically expanded to /24. If you experience networking issues, check to see if you have a clash between the Docker subnet and your infrastructure. Fixes [docker/for-win#13025](https://github.com/docker/for-win/issues/13025).
- Fixed an issue that prevents users from creating Dev Environments when the Git URL has upper-case characters.
- Fix the `vpnkit.exe is not running` error reported in diagnostics.
- Reverted qemu to 6.2.0 to fix errors like `PR_SET_CHILD_SUBREAPER is unavailable` when running emulated amd64 code.
- Enabled [contextIsolation](https://www.electronjs.org/docs/latest/tutorial/context-isolation) and [sandbox](https://www.electronjs.org/docs/latest/tutorial/sandbox) mode inside Extensions. Now Extensions run in a separate context and this limits the harm that malicious code can cause by limiting access to most system resources.
- Included `unpigz` to allow parallel decompression of pulled images.
- Fixed issues related to performing actions on selected containers. [Fixes https://github.com/docker/for-win/issues/13005](https://github.com/docker/for-win/issues/13005)
- Added functionality that allows you to display timestamps for your container or project view.
- Fixed a possible segfault when interrupting `docker pull` with Control+C.
- Increased the default DHCP lease time to avoid the VM's network glitching and dropping connections every two hours.
- Removed the infinite spinner on the containers list. [Fixes https://github.com/docker/for-mac/issues/6486](https://github.com/docker/for-mac/issues/6486)
- Fixed bug which showed incorrect values on used space in **Settings**.
- Fixed a bug that caused Kubernetes not to start with the containerd integration.
- Fixed a bug that caused `kind` not to start with the containerd integration.
- Fixed a bug that caused Dev Environments to not work with the containerd integration.
- Implemented `docker diff` in the containerd integration.
- Implemented `docker run —-platform` in the containerd integration.
- Fixed a bug that caused insecure registries not to work with the containerd integration.

#### For Mac

- Fixed a startup failure for users of Virtualization framework.
- Re-added the `/var/run/docker.sock` on Mac by default, to increase compatibility with tooling like `tilt` and `docker-py.`
- Fixed an issue that prevented the creation of Dev Environments on new Mac installs (error "Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?").

#### For Windows

- Re-added `DockerCli.exe -SharedDrives`. Fixes [docker/for-win#5625](https://github.com/docker/for-win#5625).
- Docker Desktop now allows Docker to function on machines where PowerShell is disabled.
- Fixed an issue where Compose v2 was not always enabled by default on Windows.
- Docker Desktop now deletes the `C:\Program Files\Docker` folder at uninstall.

### Known Issues

- For some users on Mac OS there is a known issue with the installer that prevents the installation of a new helper tool needed for the experimental vulnerability and package discovery feature in Docker Desktop. To fix this, a symlink is needed that can be created with the following command: `sudo ln -s /Applications/Docker.app/Contents/Resources/bin/docker-index /usr/local/bin/docker-index`

## 4.13.1

{{< release-date date="2022-10-31" >}}

### Updates

- [Docker Compose v2.12.1](https://github.com/docker/compose/releases/tag/v2.12.1)

### Bug fixes and enhancements

#### For all platforms

- Fixed a possible segfault when interrupting `docker pull` with `Control+C` or `CMD+C`.
- Increased the default DHCP lease time to avoid the VM's network glitching and dropping connections every two hours.
- Reverted `Qemu` to `6.2.0` to fix errors like `PR_SET_CHILD_SUBREAPER is unavailable` when running emulated amd64 code.

#### For Mac

- Added back the `/var/run/docker.sock` symlink on Mac by default, to increase compatibility with tooling like `tilt` and `docker-py`. Fixes [docker/for-mac#6529](https://github.com/docker/for-mac/issues/6529).
- Fixed an issue preventing the creation of Dev Environments on new Mac installs and causing `error "Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?")`

#### For Windows

- Docker Desktop now functions on machines where PowerShell is disabled.

## 4.13.0

{{< release-date date="2022-10-19" >}}

### New

- Two new security features have been introduced for Docker Business users, Settings Management and Enhanced Container Isolation. Read more about Docker Desktop’s new [Hardened Docker Desktop security model](../enterprise/security/hardened-desktop/index.md).
- Added the new Dev Environments CLI `docker dev`, so you can create, list, and run Dev Envs via command line. Now it's easier to integrate Dev Envs into custom scripts.
- Docker Desktop can now be installed to any drive and folder using the `--installation-dir`. Partially addresses [docker/roadmap#94](https://github.com/docker/roadmap/issues/94).

### Updates

- [Docker Scan v0.21.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.21.0)
- [Go 1.19.2](https://github.com/golang/go/releases/tag/go1.19.2) to address [CVE-2022-2879](https://www.cve.org/CVERecord?id=CVE-2022-2879), [CVE-2022-2880](https://www.cve.org/CVERecord?id=CVE-2022-2880) and [CVE-2022-41715](https://www.cve.org/CVERecord?id=CVE-2022-41715)
- Updated Docker Engine and Docker CLI to [v20.10.20](../engine/release-notes/20.10.md#201020),
  which contain mitigations against a Git vulnerability, tracked in [CVE-2022-39253](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253),
  and updated handling of `image:tag@digest` image references, as well as a fix for [CVE-2022-36109](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-36109).
- [Docker Credential Helpers v0.7.0](https://github.com/docker/docker-credential-helpers/releases/tag/v0.7.0)
- [Docker Compose v2.12.0](https://github.com/docker/compose/releases/tag/v2.12.0)
- [Kubernetes v1.25.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.25.2)
- [Qemu 7.0.0](https://wiki.qemu.org/ChangeLog/7.0) used for cpu emulation, inside the Docker Desktop VM.
- [Linux kernel 5.15.49](https://hub.docker.com/layers/docker/for-desktop-kernel/5.15.49-13422a825f833d125942948cf8a8688cef721ead/images/sha256-ebf1f6f0cb58c70eaa260e9d55df7c43968874d62daced966ef6a5c5cd96b493?context=explore)

### Bug fixes and enhancements

#### For all platforms

- Docker Desktop now allows the use of TLS when talking to HTTP and HTTPS proxies to encrypt proxy usernames and passwords.
- Docker Desktop now stores HTTP and HTTPS proxy passwords in the OS credential store.
- If Docker Desktop detects that the HTTP or HTTPS proxy password has changed then it will prompt developers for the new password.
- The **Bypass proxy settings for these hosts and domains** setting now handles domain names correctly for HTTPS.
- The **Remote Repositories** view and Tip of the Day now works with HTTP and HTTPS proxies which require authentication
- We’ve introduced dark launch for features that are in early stages of the product development lifecycle. Users that are opted in can opt out at any time in the settings under the “beta features” section.
- Added categories to the Extensions Marketplace.
- Added an indicator in the whale menu and on the **Extension** tab on when extension updates are available.
- Fixed failing uninstalls of extensions with image names that do not have a namespace, as in 'my-extension'.
- Show port mapping explicitly in the **Container** tab.
- Changed the refresh rate for disk usage information for images to happen automatically once a day.
- Made the tab style consistent for the **Container** and **Volume** tabs.
- Fixed Grpcfuse filesharing mode enablement in **Settings**. Fixes [docker/for-mac#6467](https://github.com/docker/for-mac/issues/6467)
- Virtualization Framework and VirtioFS are disabled for users running macOS < 12.5.
- Ports on the **Containers** tab are now clickable.
- The Extensions SDK now allows `ddClient.extension.vm.cli.exec`, `ddClient.extension.host.cli.exec`, `ddClient.docker.cli.exec` to accept a different working directory and pass environment variables through the options parameters.
- Added a small improvement to navigate to the Extensions Marketplace when clicking on **Extensions** in the sidebar.
- Added a badge to identify new extensions in the Marketplace.
- Fixed kubernetes not starting with the containerd integration.
- Fixed `kind` not starting with the containerd integration.
- Fixed dev environments not working with the containerd integration.
- Implemented `docker diff` in the containerd integration.
- Implemented `docker run —-platform` in the containerd integration.
- Fixed insecure registries not working with the containerd integration.
- Fixed a bug that showed incorrect values on used space in **Settings**.
- Docker Desktop now installs credential helpers from Github releases. See [docker/for-win#10247](https://github.com/docker/for-win/issues/10247), [docker/for-win#12995](https://github.com/docker/for-win/issues/12995).
- Fixed an issue where users were logged out of Docker Desktop after 7 days.

#### For Mac

- Added **Hide**, **Hide others**, **Show all** menu items for Docker Desktop. See [docker/for-mac#6446](https://github.com/docker/for-mac/issues/6446).
- Fixed a bug which caused the application to be deleted when running the install utility from the installed application. Fixes [docker/for-mac#6442](https://github.com/docker/for-mac/issues/6442).
- By default Docker will not create the /var/run/docker.sock symlink on the host and use the docker-desktop CLI context instead.

#### For Linux

- Fixed a bug that prevented pushing images from the Dashboard

## 4.12.0

{{< release-date date="2022-09-01" >}}

### New

- Added the ability to use containerd for pulling and storing images. This is an experimental feature.
- Docker Desktop now runs untagged images. Fixes [docker/for-mac#6425](https://github.com/docker/for-mac/issues/6425).
- Added search capabilities to Docker Extension's Marketplace. Fixes [docker/roadmap#346](https://github.com/docker/roadmap/issues/346).
- Added the ability to zoom in, out or set Docker Desktop to Actual Size. This is done by using keyboard shortcuts ⌘ + / CTRL +, ⌘ - / CTRL -, ⌘ 0 / CTRL 0 on Mac and Windows respectively, or through the View menu on Mac.
- Added compose stop button if any related container is stoppable.
- Individual compose containers are now deletable from the **Container** view.
- Removed the workaround for virtiofsd <-> qemu protocol mismatch on Fedora 35, as it is no longer needed. Fedora 35 users should upgrade the qemu package to the most recent version (qemu-6.1.0-15.fc35 as of the time of writing).
- Implemented an integrated terminal for containers.
- Added a tooltip to display the link address for all external links by default.

### Updates

- [Docker Compose v2.10.2](https://github.com/docker/compose/releases/tag/v2.10.2)
- [Docker Scan v0.19.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.19.0)
- [Kubernetes v1.25.0](https://github.com/kubernetes/kubernetes/releases/tag/v1.25.0)
- [Go 1.19](https://github.com/golang/go/releases/tag/go1.19)
- [cri-dockerd v0.2.5](https://github.com/Mirantis/cri-dockerd/releases/tag/v0.2.5)
- [Buildx v0.9.1](https://github.com/docker/buildx/releases/tag/v0.9.1)
- [containerd v1.6.8](https://github.com/containerd/containerd/releases/tag/v1.6.8)
- [containerd v1.6.7](https://github.com/containerd/containerd/releases/tag/v1.6.7)
- [runc v1.1.4](https://github.com/opencontainers/runc/releases/tag/v1.1.4)
- [runc v1.1.3](https://github.com/opencontainers/runc/releases/tag/v1.1.3)

### Security

#### For all platforms

- Fixed [CVE-2023-0626](https://www.cve.org/cverecord?id=CVE-2023-0626) which allows RCE via query parameters in the message-box route in the Electron client.
- Fixed [CVE-2023-0625](https://www.cve.org/cverecord?id=CVE-2023-0625) which allows RCE via extension description/changelog which could be abused by a malicious extension.

#### For Windows

- Fixed [CVE-2023-0627](https://www.cve.org/cverecord?id=CVE-2023-0627) which allows to bypass for the `--no-windows-containers` installation flag which was introduced in version 4.11. This flag allows administrators to disable the use of Windows containers.
- Fixed [CVE-2023-0633](https://www.cve.org/cverecord?id=CVE-2023-0633) in which an argument injection to the Docker Desktop installer which may result in local privilege escalation.

### Bug fixes and minor enhancements

#### For all platforms

- Compose V2 is now enabled after factory reset.
- Compose V2 is now enabled by default on new installations of Docker Desktop.
- Precedence order of environment variables in Compose is more consistent, and clearly [documented](../compose/how-tos/environment-variables/envvars-precedence.md).
- Upgraded kernel to 5.10.124.
- Improved overall performance issues caused by calculating disk size. Related to [docker/for-win#9401](https://github.com/docker/for-win/issues/9401).
- Docker Desktop now prevents users on ARM macs without Rosetta installed from switching back to Compose V1, which has only intel binaries.
- Changed the default sort order to descending for volume size and the **Created** column, along with the container's **Started** column.
- Re-organized container row actions by keeping only the start/stop and delete actions visible at all times, while allowing access to the rest via the row menu item.
- The Quickstart guide now runs every command immediately.
- Defined the sort order for container/compose **Status** column to running > some running > paused > some paused > exited > some exited > created.
- Fixed issues with the image list appearing empty in Docker Desktop even though there are images. Related to [docker/for-win#12693](https://github.com/docker/for-win/issues/12693) and [docker/for-mac#6347](https://github.com/docker/for-mac/issues/6347).
- Defined what images are "in use" based on whether or not system containers are displayed. If system containers related to Kubernetes and Extensions are not displayed, the related images are not defined as "in use."
- Fixed a bug that made Docker clients in some languages hang on `docker exec`. Fixes [https://github.com/apocas/dockerode/issues/534](https://github.com/apocas/dockerode/issues/534).
- A failed spawned command when building an extension no longer causes Docker Desktop to unexpectedly quit.
- Fixed a bug that caused extensions to be displayed as disabled in the left menu when they are not.
- Fixed `docker login` to private registries when Registry Access Management is enabled and access to Docker Hub is blocked.
- Fixed a bug where Docker Desktop fails to start the Kubernetes cluster if the current cluster metadata is not stored in the `.kube/config` file.
- Updated the tooltips in Docker Desktop and MUI theme package to align with the overall system design.
- Copied terminal contents do not contain non-breaking spaces anymore.

#### For Mac

- Minimum version to install or update Docker Desktop on macOS is now 10.15. Fixes [docker/for-mac#6007](https://github.com/docker/for-mac/issues/6007).
- Fixed a bug where the Tray menu incorrectly displays "Download will start soon..." after downloading the update. Fixes some issue reported in [for-mac/issues#5677](https://github.com/docker/for-mac/issues/5677)
- Fixed a bug that didn't restart Docker Desktop after applying an update.
- Fixed a bug that caused the connection to Docker to be lost when the computer sleeps if a user is using virtualization.framework and restrictive firewall software.
- Fixed a bug that caused Docker Desktop to run in the background even after a user had quit the application. Fixes [docker/for-mac##6440](https://github.com/docker/for-mac/issues/6440)
- Disabled both Virtualization Framework and VirtioFS for users running macOS < 12.5

#### For Windows

- Fixed a bug where versions displayed during an update could be incorrect. Fixes [for-win/issues#12822](https://github.com/docker/for-win/issues/12822).

## 4.11.1

{{< release-date date="2022-08-05" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed regression preventing VM system locations (e.g. /var/lib/docker) from being bind mounted [for-mac/issues#6433](https://github.com/docker/for-mac/issues/6433)

#### For Windows

- Fixed `docker login` to private registries from WSL2 distribution [docker/for-win#12871](https://github.com/docker/for-win/issues/12871)

## 4.11.0

{{< release-date date="2022-07-28" >}}

### New

- Docker Desktop is now fully supported for Docker Business customers inside VMware ESXi and Azure VMs. For more information, see [Run Docker Desktop inside a VM or VDI environment](setup/vm-vdi.md)
- Added two new extensions ([vcluster](https://hub.docker.com/extensions/loftsh/vcluster-dd-extension) and [PGAdmin4](https://hub.docker.com/extensions/mochoa/pgadmin4-docker-extension)) to the Extensions Marketplace.
- The ability to sort extensions has been added to the Extensions Marketplace.
- Fixed a bug that caused some users to be asked for feedback too frequently. You'll now only be asked for feedback twice a year.
- Added custom theme settings for Docker Desktop. This allows you to specify dark or light mode for Docker Desktop independent of your device settings. Fixes [docker/for-win#12747](https://github.com/docker/for-win/issues/12747)
- Added a new flag for Windows installer. `--no-windows-containers` disables the Windows containers integration.
- Added a new flag for Mac install command. `--user <username>` sets up Docker Desktop for a specific user, preventing them from needing an admin password on first run.

### Updates

- [Docker Compose v2.7.0](https://github.com/docker/compose/releases/tag/v2.7.0)
- [Docker Compose "Cloud Integrations" v1.0.28](https://github.com/docker/compose-cli/releases/tag/v1.0.28)
- [Kubernetes v1.24.2](https://github.com/kubernetes/kubernetes/releases/tag/v1.24.2)
- [Go 1.18.4](https://github.com/golang/go/releases/tag/go1.18.4)

### Bug fixes and enhancements

#### For all platforms

- Added the Container / Compose icon as well as the exposed port(s) / exit code to the Containers screen.
- Updated the Docker theme palette colour values to match our design system.
- Improved an error message from `docker login` if Registry Access Management is blocking the Docker engine's access to Docker Hub.
- Increased throughput between the Host and Docker. For example increasing performance of `docker cp`.
- Collecting diagnostics takes less time to complete.
- Selecting or deselecting a compose app on the containers overview now selects/deselects all its containers.
- Tag names on the container overview image column are visible.
- Added search decorations to the terminal's scrollbar so that matches outside the viewport are visible.
- Fixed an issue with search which doesn't work well on containers page [docker/for-win#12828](https://github.com/docker/for-win/issues/12828).
- Fixed an issue which caused infinite loading on the **Volume** screen [docker/for-win#12789](https://github.com/docker/for-win/issues/12789).
- Fixed a problem in the Container UI where resizing or hiding columns didn't work. Fixes [docker/for-mac#6391](https://github.com/docker/for-mac/issues/6391).
- Fixed a bug where the state of installing, updating, or uninstalling multiple extensions at once was lost when leaving the Marketplace screen.
- Fixed an issue where the compose version in the about page would only get updated from v2 to v1 after restarting Docker Desktop.
- Fixed an issue where users cannot see the log view because their underlying hardware didn't support WebGL2 rendering. Fixes [docker/for-win#12825](https://github.com/docker/for-win/issues/12825).
- Fixed a bug where the UI for Containers and Images got out of sync.
- Fixed a startup race when the experimental virtualization framework is enabled.

#### For Mac

- Fixed an issue executing Compose commands from the UI. Fixes [docker/for-mac#6400](https://github.com/docker/for-mac/issues/6400).

#### For Windows

- Fixed horizontal resizing issue. Fixes [docker/for-win#12816](https://github.com/docker/for-win/issues/12816).
- If an HTTP/HTTPS proxy is configured in the UI, then it automatically sends traffic from image builds and running containers to the proxy. This avoids the need to separately configure environment variables in each container or build.
- Added the `--backend=windows` installer option to set Windows containers as the default backend.

#### For Linux

- Fixed bug related to setting up file shares with spaces in their path.

## 4.10.1

{{< release-date date="2022-07-05" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed a bug where actions in the UI failed with Compose apps that were created from WSL. Fixes [docker/for-win#12806](https://github.com/docker/for-win/issues/12806).

#### For Mac

- Fixed a bug where the install command failed because paths were not initialized. Fixes [docker/for-mac#6384](https://github.com/docker/for-mac/issues/6384).

## 4.10.0

{{< release-date date="2022-06-30" >}}

### New

- You can now add environment variables before running an image in Docker Desktop.
- Added features to make it easier to work with a container's logs, such as regular expression search and the ability to clear container logs while the container is still running.
- Implemented feedback on the containers table. Added ports and separated container and image names.
- Added two new extensions, Ddosify and Lacework, to the Extensions Marketplace.

### Removed

- Removed Homepage while working on a new design. You can provide [feedback here](https://docs.google.com/forms/d/e/1FAIpQLSfYueBkJHdgxqsWcQn4VzBn2swu4u_rMQRIMa8LExYb_72mmQ/viewform?entry.1237514594=4.10).

### Updates

- [Docker Engine v20.10.17](../engine/release-notes/20.10.md#201017)
- [Docker Compose v2.6.1](https://github.com/docker/compose/releases/tag/v2.6.1)
- [Kubernetes v1.24.1](https://github.com/kubernetes/kubernetes/releases/tag/v1.24.1)
- [cri-dockerd to v0.2.1](https://github.com/Mirantis/cri-dockerd/releases/tag/v0.2.1)
- [CNI plugins to v1.1.1](https://github.com/containernetworking/plugins/releases/tag/v1.1.1)
- [containerd to v1.6.6](https://github.com/containerd/containerd/releases/tag/v1.6.6)
- [runc to v1.1.2](https://github.com/opencontainers/runc/releases/tag/v1.1.2)
- [Go 1.18.3](https://github.com/golang/go/releases/tag/go1.18.3)

### Bug fixes and enhancements

#### For all platforms

- Added additional bulk actions for starting/pausing/stopping selected containers in the **Containers** tab.
- Added pause and restart actions for compose projects in the **Containers** tab.
- Added icons and exposed ports or exit code information in the **Containers** tab.
- External URLs can now refer to extension details in the Extension Marketplace using links such as `docker-desktop://extensions/marketplace?extensionId=docker/logs-explorer-extension`.
- The expanded or collapsed state of the Compose apps is now persisted.
- `docker extension` CLI commands are available with Docker Desktop by default.
- Increased the size of the screenshots displayed in the Extension marketplace.
- Fixed a bug where a Docker extension fails to load if its backend container(s) are stopped. Fixes [docker/extensions-sdk#16](https://github.com/docker/extensions-sdk/issues/162).
- Fixed a bug where the image search field is cleared without a reason. Fixes [docker/for-win#12738](https://github.com/docker/for-win/issues/12738).
- Fixed a bug where the license agreement does not display and silently blocks Docker Desktop startup.
- Fixed the displayed image and tag for unpublished extensions to actually display the ones from the installed unpublished extension.
- Fixed the duplicate footer on the Support screen.
- Dev Environments can be created from a subdirectory in a GitHub repository.
- Removed the error message if the tips of the day cannot be loaded when using Docker Desktop offline. Fixes [docker/for-mac#6366](https://github.com/docker/for-mac/issues/6366).

#### For Mac

- Fixed a bug with location of bash completion files on macOS. Fixes [docker/for-mac#6343](https://github.com/docker/for-mac/issues/6343).
- Fixed a bug where Docker Desktop does not start if the username is longer than 25 characters. Fixes [docker/for-mac#6122](https://github.com/docker/for-mac/issues/6122).
- Fixed a bug where Docker Desktop was not starting due to invalid system proxy configuration. Fixes some issues reported in [docker/for-mac#6289](https://github.com/docker/for-mac/issues/6289).
- Fixed a bug where Docker Desktop failed to start when the experimental virtualization framework is enabled.
- Fixed a bug where the tray icon still displayed after uninstalling Docker Desktop.

#### For Windows

- Fixed a bug which caused high CPU usage on Hyper-V. Fixes [docker/for-win#12780](https://github.com/docker/for-win/issues/12780).
- Fixed a bug where Docker Desktop for Windows would fail to start. Fixes [docker/for-win#12784](https://github.com/docker/for-win/issues/12784).
- Fixed the `--backend=wsl-2` installer flag which did not set the backend to WSL 2. Fixes [docker/for-win#12746](https://github.com/docker/for-win/issues/12746).

#### For Linux

- Fixed a bug when settings cannot be applied more than once.
- Fixed Compose version displayed in the `About` screen.

### Known Issues

- Occasionally the Docker engine will restart during a `docker system prune`. This is a [known issue](https://github.com/moby/buildkit/pull/2177) in the version of buildkit used in the current engine and will be fixed in future releases.

## 4.9.1

{{< release-date date="2022-06-16" >}}

{{< desktop-install all=true version="4.9.1" build_path="/81317/" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed blank dashboard screen. Fixes [docker/for-win#12759](https://github.com/docker/for-win/issues/12759).

## 4.9.0

{{< release-date date="2022-06-02" >}}

### New

- Added additional guides on the homepage for: Elasticsearch, MariaDB, Memcached, MySQL, RabbitMQ and Ubuntu.
- Added a footer to the Docker Desktop Dashboard with general information about the Docker Desktop update status and Docker Engine statistics
- Re-designed the containers table, adding:
  - A button to copy a container ID to the clipboard
  - A pause button for each container
  - Column resizing for the containers table
  - Persistence of sorting and resizing for the containers table
  - Bulk deletion for the containers table

### Updates

- [Compose v2.6.0](https://github.com/docker/compose/releases/tag/v2.6.0)
- [Docker Engine v20.10.16](../engine/release-notes/20.10.md#201016)
- [containerd v1.6.4](https://github.com/containerd/containerd/releases/tag/v1.6.4)
- [runc v1.1.1](https://github.com/opencontainers/runc/releases/tag/v1.1.1)
- [Go 1.18.2](https://github.com/golang/go/releases/tag/go1.18.2)

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue which caused Docker Desktop to hang if you quit the app whilst Docker Desktop was paused.
- Fixed the Kubernetes cluster not resetting properly after the PKI expires.
- Fixed an issue where the Extensions Marketplace was not using the defined http proxies.
- Improved the logs search functionality in Docker Desktop Dashboard to allow spaces.
- Middle-button mouse clicks on buttons in the Dashboard now behave as a left-button click instead of opening a blank window.

#### For Mac

- Fixed an issue to avoid creating `/opt/containerd/bin` and `/opt/containerd/lib` on the host if `/opt` has been added to the file sharing directories list.

#### For Windows

- Fixed a bug in the WSL 2 integration where if a file or directory is bind-mounted to a container, and the container exits, then the file or directory is replaced with the other type of object with the same name. For example, if a file is replaced with a directory or a directory with a file, any attempts to bind-mount the new object fails.
- Fixed a bug where the Tray icon and Dashboard UI didn't show up and Docker Desktop didn't fully start. Fixes [docker/for-win#12622](https://github.com/docker/for-win/issues/12622).

### Known issues

#### For Linux

- Changing ownership rights for files in bind mounts fails. This is due to the way we have implemented file sharing between the host and VM within which the Docker Engine runs. We aim to resolve this issue in the next release.

## 4.8.2

{{< release-date date="2022-05-18" >}}

### Updates

- [Compose v2.5.1](https://github.com/docker/compose/releases/tag/v2.5.1)

### Bug fixes and minor enahancements

- Fixed an issue with manual proxy settings which caused problems when pulling images. Fixes [docker/for-win#12714](https://github.com/docker/for-win/issues/12714) and [docker/for-mac#6315](https://github.com/docker/for-mac/issues/6315).
- Fixed high CPU usage when extensions are disabled. Fixes [docker/for-mac#6310](https://github.com/docker/for-mac/issues/6310).
- Docker Desktop now redacts HTTP proxy passwords in log files and diagnostics.

### Known issues

#### For Linux

- Changing ownership rights for files in bind mounts fails. This is due to the way we have implemented file sharing between the host and VM within which the Docker Engine runs. We aim to resolve this issue in the next release.

## 4.8.1

{{< release-date date="2022-05-09" >}}

### New

- Released [Docker Desktop for Linux](setup/install/linux/index.md).
- Beta release of [Docker Extensions](../extensions/index.md) and Extensions SDK.
- Created a Docker Homepage where you can run popular images and discover how to use them.
- [Compose V2 is now GA](https://www.docker.com/blog/announcing-compose-v2-general-availability/)

### Bug fixes and enhancements

- Fixed a bug that caused the Kubernetes cluster to be deleted when updating Docker Desktop.

### Known issues

#### For Linux

- Changing ownership rights for files in bind mounts fails. This is due to the way we have implemented file sharing between the host and VM within which the Docker Engine runs. We aim to resolve this issue in the next release.

## 4.8.0

{{< release-date date="2022-05-06" >}}

### New

- Released [Docker Desktop for Linux](setup/install/linux/index.md).
- Beta release of [Docker Extensions](../extensions/index.md) and Extensions SDK.
- Created a Docker Homepage where you can run popular images and discover how to use them.
- [Compose V2 is now GA](https://www.docker.com/blog/announcing-compose-v2-general-availability/)

### Updates

- [Compose v2.5.0](https://github.com/docker/compose/releases/tag/v2.5.0)
- [Go 1.18.1](https://github.com/golang/go/releases/tag/go1.18.1)
- [Kubernetes 1.24](https://github.com/kubernetes/kubernetes/releases/tag/v1.24.0)

### Bug fixes and minor enhancements

#### For all platforms

- Introduced reading system proxy. You no longer need to manually configure proxies unless it differs from your OS level proxy.
- Fixed a bug that showed Remote Repositories in the Dashboard when running behind a proxy.
- Fixed vpnkit establishing and blocking the client connection even if the server is gone. See [docker/for-mac#6235](https://github.com/docker/for-mac/issues/6235)
- Made improvements on the Volume tab in Docker Desktop:
  - Volume size is displayed.
  - Columns can be resized, hidden and reordered.
  - A columns sort order and hidden state is persisted, even after Docker Desktop restarts.
  - Row selection is persisted when switching between tabs, even after Docker Desktop restarts.
- Fixed a bug in the Dev Environments tab that did not add a scroll when more items were added to the screen.
- Standardised the header title and action in the Dashboard.
- Added support for downloading Registry Access Management policies through HTTP proxies.
- Fixed an issue related to empty remote repositories when the machine is in sleep mode for an extended period of time.
- Fixed a bug where dangling images were not selected in the cleanup process if their name was not marked as "&lt;none>" but their tag is.
- Improved the error message when `docker pull` fails because an HTTP proxy is required.
- Added the ability to clear the search bar easily in Docker Desktop.
- Renamed the "Containers / Apps" tab to "Containers".
- Fixed a silent crash in the Docker Desktop installer when `C:\ProgramData\DockerDesktop` is a file or a symlink.
- Fixed a bug where an image with no namespace, for example `docker pull <private registry>/image`, would be erroneously blocked by Registry Access Management unless access to Docker Hub was enabled in settings.

#### For Mac

- Docker Desktop's icon now matches Big Sur Style guide. See [docker/for-mac#5536](https://github.com/docker/for-mac/issues/5536)
- Fixed a problem with duplicate Dock icons and Dock icon not working as expected. Fixes [docker/for-mac#6189](https://github.com/docker/for-mac/issues/6189).
- Improved support for the `Cmd+Q` shortcut.

#### For Windows

- Improved support for the `Ctrl+W` shortcut.

### Known issues

#### For all platforms

- Currently, if you are running a Kubernetes cluster, it will be deleted when you upgrade to Docker Desktop 4.8.0. We aim to fix this in the next release.

#### For Linux

- Changing ownership rights for files in bind mounts fails. This is due to the way we have implemented file sharing between the host and VM within which the Docker Engine runs. We aim to resolve this issue in the next release.

## 4.7.1

{{< release-date date="2022-04-19" >}}

### Bug fixes and enhancements

#### For all platforms

- Fixed a crash on the Quick Start Guide final screen.

#### For Windows

- Fixed a bug where update was failing with a symlink error. Fixes [docker/for-win#12650](https://github.com/docker/for-win/issues/12650).
- Fixed a bug that prevented using Windows container mode. Fixes [docker/for-win#12652](https://github.com/docker/for-win/issues/12652).

## 4.7.0

{{< release-date date="2022-04-07" >}}

### New

- IT Administrators can now install Docker Desktop remotely using the command line.
- Add the Docker Software Bill of Materials (SBOM) CLI plugin. The new CLI plugin enables users to generate SBOMs for Docker images.
- Use [cri-dockerd](https://github.com/Mirantis/cri-dockerd) for new Kubernetes clusters instead of `dockershim`. The change is transparent from the user's point of view and Kubernetes containers run on the Docker Engine as before. `cri-dockerd` allows Kubernetes to manage Docker containers using the standard [Container Runtime Interface](https://github.com/kubernetes/cri-api#readme), the same interface used to control other container runtimes. For more information, see [The Future of Dockershim is cri-dockerd](https://www.mirantis.com/blog/the-future-of-dockershim-is-cri-dockerd/).

### Updates

- [Docker Engine v20.10.14](../engine/release-notes/20.10.md#201014)
- [Compose v2.4.1](https://github.com/docker/compose/releases/tag/v2.4.1)
- [Buildx 0.8.2](https://github.com/docker/buildx/releases/tag/v0.8.2)
- [containerd v1.5.11](https://github.com/containerd/containerd/releases/tag/v1.5.11)
- [Go 1.18](https://golang.org/doc/go1.18)

### Security

- Update Docker Engine to v20.10.14 to address [CVE-2022-24769](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24769)
- Update containerd to v1.5.11 to address [CVE-2022-24769](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24769)

### Bug fixes and enhancements

#### For all platforms

- Fixed a bug where the Registry Access Management policy was never refreshed after a failure.
- Logs and terminals in the UI now respect your OS theme in light and dark mode.
- Easily clean up many volumes at once via multi-select checkboxes.
- Improved login feedback.

#### For Mac

- Fixed an issue that sometimes caused Docker Desktop to display a blank white screen. Fixes [docker/for-mac#6134](https://github.com/docker/for-mac/issues/6134).
- Fixed a problem where gettimeofday() performance drops after waking from sleep when using Hyperkit. Fixes [docker/for-mac#3455](https://github.com/docker/for-mac/issues/3455).
- Fixed an issue that caused Docker Desktop to become unresponsive during startup when `osxfs` is used for file sharing.

#### For Windows

- Fixed volume title. Fixes [docker/for-win#12616](https://github.com/docker/for-win/issues/12616).
- Fixed a bug in the WSL 2 integration that caused Docker commands to stop working after restarting Docker Desktop or after switching to Windows containers.

## 4.6.1

{{< release-date date="2022-03-22" >}}

### Updates

- [Buildx 0.8.1](https://github.com/docker/buildx/releases/tag/v0.8.1)

### Bug fixes and enhancements

- Prevented spinning in vpnkit-forwarder filling the logs with error messages.
- Fixed diagnostics upload when there is no HTTP proxy set. Fixes [docker/for-mac#6234](https://github.com/docker/for-mac/issues/6234).
- Removed a false positive "vm is not running" error from self-diagnose. Fixes [docker/for-mac#6233](https://github.com/docker/for-mac/issues/6233).

## 4.6.0

{{< release-date date="2022-03-14" >}}

### New

#### For all platforms

- The Docker Desktop Dashboard Volume Management feature now offers the ability to efficiently clean up volumes using multi-select checkboxes.

#### For Mac

- Docker Desktop 4.6.0 gives macOS users the option of enabling a new experimental file sharing technology called VirtioFS. During testing VirtioFS has been shown to drastically reduce the time taken to sync changes between the host and VM, leading to substantial performance improvements. For more information, see [VirtioFS](settings-and-maintenance/settings.md#beta-features).

### Updates

#### For all platforms

- [Docker Engine v20.10.13](../engine/release-notes/20.10.md#201013)
- [Compose v2.3.3](https://github.com/docker/compose/releases/tag/v2.3.3)
- [Buildx 0.8.0](https://github.com/docker/buildx/releases/tag/v0.8.0)
- [containerd v1.4.13](https://github.com/containerd/containerd/releases/tag/v1.4.13)
- [runc v1.0.3](https://github.com/opencontainers/runc/releases/tag/v1.0.3)
- [Go 1.17.8](https://golang.org/doc/go1.17)
- [Linux kernel 5.10.104](https://hub.docker.com/layers/docker/for-desktop-kernel/5.10.104-379cadd2e08e8b25f932380e9fdaab97755357b3/images/sha256-7753b60f4544e5c5eed629d12151a49c8a4b48d98b4fb30e4e65cecc20da484d?context=explore)

### Security

#### For all platforms

- Fixed [CVE-2022-0847](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0847), aka “Dirty Pipe”, an issue that could enable attackers to modify files in container images on the host, from inside a container.
  If using the WSL 2 backend, you must update WSL 2 by running `wsl --update`.

#### For Windows

- Fixed [CVE-2022-26659](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-26659), which could allow an attacker to overwrite any administrator writable file on the system during the installation or the update of Docker Desktop.

#### For Mac

- [Qemu 6.2.0](https://wiki.qemu.org/ChangeLog/6.2)

### Bug fixes and enhancements

#### For all platforms

- Fixed uploading diagnostics when an HTTPS proxy is set.
- Made checking for updates from the systray menu open the Software updates settings section.

#### For Mac

- Fixed the systray menu not displaying all menu items after starting Docker Desktop. Fixes [docker/for-mac#6192](https://github.com/docker/for-mac/issues/6192).
- Fixed a regression about Docker Desktop not starting in background anymore. Fixes [docker/for-mac#6167](https://github.com/docker/for-mac/issues/6167).
- Fixed missing Docker Desktop Dock icon. Fixes [docker/for-mac#6173](https://github.com/docker/for-mac/issues/6173).
- Used speed up block device access when using the experimental `virtualization.framework`. See [benchmarks](https://github.com/docker/roadmap/issues/7#issuecomment-1050626886).
- Increased default VM memory allocation to half of physical memory (min 2 GB, max 8 GB) for better out-of-the-box performances.

#### For Windows

- Fixed the UI stuck in `starting` state forever although Docker Desktop is working fine from the command line.
- Fixed missing Docker Desktop systray icon [docker/for-win#12573](https://github.com/docker/for-win/issues/12573)
- Fixed Registry Access Management under WSL 2 with latest 5.10.60.1 kernel.
- Fixed a UI crash when selecting the containers of a Compose application started from a WSL 2 environment. Fixes [docker/for-win#12567](https://github.com/docker/for-win/issues/12567).
- Fixed copying text from terminal in Quick Start Guide. Fixes [docker/for-win#12444](https://github.com/docker/for-win/issues/12444).

### Known issues

#### For Mac

- After enabling VirtioFS, containers with processes running with different Unix user IDs may experience caching issues. For example if a process running as `root` queries a file and another process running as user `nginx` tries to access the same file immediately, the `nginx` process will get a "Permission Denied" error.

## 4.5.1

{{< release-date date="2022-02-15" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed an issue that caused new installations to default to the Hyper-V backend instead of WSL 2.
- Fixed a crash in the Docker Desktop Dashboard which would make the systray menu disappear.

If you are running Docker Desktop on Windows Home, installing 4.5.1 will switch it back to WSL 2 automatically. If you are running another version of Windows, and you want Docker Desktop to use the WSL 2 backend, you must manually switch by enabling the **Use the WSL 2 based engine** option in the **Settings > General** section.
Alternatively, you can edit the Docker Desktop settings file located at `%APPDATA%\Docker\settings.json` and manually switch the value of the `wslEngineEnabled` field to `true`.

## 4.5.0

{{< release-date date="2022-02-10" >}}

### New

- Docker Desktop 4.5.0 introduces a new version of the Docker menu which creates a consistent user experience across all operating systems. For more information, see the blog post [New Docker Menu & Improved Release Highlights with Docker Desktop 4.5](https://www.docker.com/blog/new-docker-menu-improved-release-highlights-with-docker-desktop-4-5/)
- The 'docker version' output now displays the version of Docker Desktop installed on the machine.

### Updates

- [Amazon ECR Credential Helper v0.6.0](https://github.com/awslabs/amazon-ecr-credential-helper/releases/tag/v0.6.0)

### Security

#### For Mac

- Fixed [CVE-2021-44719](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44719) where Docker Desktop could be used to access any user file on the host from a container, bypassing the allowed list of shared folders.

#### For Windows

- Fixed [CVE-2022-23774](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23774) where Docker Desktop allows attackers to move arbitrary files.

### Bug fixes and enhancements

#### For all platforms

- Fixed an issue where Docker Desktop incorrectly prompted users to sign in after they quit Docker Desktop and start the application.
- Increased the filesystem watch (inotify) limits by setting `fs.inotify.max_user_watches=1048576` and `fs.inotify.max_user_instances=8192` in Linux. Fixes [docker/for-mac#6071](https://github.com/docker/for-mac/issues/6071).

#### For Mac

- Fixed an issue that caused the VM to become unresponsive during startup when using `osxfs` and when no host directories are shared with the VM.
- Fixed an issue that didn't allow users to stop a Docker Compose application using Docker Desktop Dashboard if the application was started in a different version of Docker Compose. For example, if the user started a Docker Compose application in V1 and then switched to Docker Compose V2, attempts to stop the Docker Compose application would fail.
- Fixed an issue where Docker Desktop incorrectly prompted users to sign in after they quit Docker Desktop and start the application.
- Fixed an issue where the **About Docker Desktop** window wasn't working anymore.
- Limit the number of CPUs to 8 on Mac M1 to fix the startup problem. Fixes [docker/for-mac#6063](https://github.com/docker/for-mac/issues/6063).

#### For Windows

- Fixed an issue related to compose app started with version 2, but the dashboard only deals with version 1

### Known issues

#### For Windows

Installing Docker Desktop 4.5.0 from scratch has a bug which defaults Docker Desktop to use the Hyper-V backend instead of WSL 2. This means, Windows Home users will not be able to start Docker Desktop as WSL 2 is the only supported backend. To work around this issue, you must uninstall 4.5.0 from your machine and then download and install Docker Desktop 4.5.1 or a higher version. Alternatively, you can edit the Docker Desktop settings.json file located at `%APPDATA%\Docker\settings.json` and manually switch the value of the `wslEngineEnabled` field to `true`.

## 4.4.4

{{< release-date date="2022-01-24" >}}

### Bug fixes and enhancements

#### For Windows

- Fixed logging in from WSL 2. Fixes [docker/for-win#12500](https://github.com/docker/for-win/issues/12500).

### Known issues

#### For Windows

- Clicking **Proceed to Desktop** after signing in through the browser, sometimes does not bring the Dashboard to the front.
- After logging in, when the Dashboard receives focus, it sometimes stays in the foreground even when clicking a background window. As a workaround you need to click the Dashboard before clicking another application window.
- The tips of the week show on top of the mandatory login dialog when an organization restriction is enabled via a `registry.json` file.

## 4.4.3

{{< release-date date="2022-01-14" >}}

### Bug fixes and enhancements

#### For Windows

- Disabled Dashboard shortcuts to prevent capturing them even when minimized or un-focussed. Fixes [docker/for-win#12495](https://github.com/docker/for-win/issues/12495).

### Known issues

#### For Windows

- Clicking **Proceed to Desktop** after signing in through the browser, sometimes does not bring the Dashboard to the front.
- After logging in, when the Dashboard receives focus, it sometimes stays in the foreground even when clicking a background window. As a workaround you need to click the Dashboard before clicking another application window.
- The tips of the week show on top of the mandatory login dialog when an organization restriction is enabled via a `registry.json` file.

## 4.4.2

{{< release-date date="22-01-13" >}}

### New

- Easy, Secure sign in with Auth0 and Single Sign-on
  - Single Sign-on: Users with a Docker Business subscription can now configure SSO to authenticate using their identity providers (IdPs) to access Docker. For more information, see [Single Sign-on](../security/authentication/single-sign-on/index.md).
  - Signing in to Docker Desktop now takes you through the browser so that you get all the benefits of auto-filling from password managers.

### Upgrades

- [Docker Engine v20.10.12](../engine/release-notes/20.10.md#201012)
- [Compose v2.2.3](https://github.com/docker/compose/releases/tag/v2.2.3)
- [Kubernetes 1.22.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.22.5)
- [docker scan v0.16.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.16.0)

### Security

- Fixed [CVE-2021-45449](../security/security-announcements.md#cve-2021-45449) that affects users currently on Docker Desktop version 4.3.0 or 4.3.1.

Docker Desktop version 4.3.0 and 4.3.1 has a bug that may log sensitive information (access token or password) on the user's machine during login.
This only affects users if they are on Docker Desktop 4.3.0, 4.3.1 and the user has logged in while on 4.3.0, 4.3.1. Gaining access to this data would require having access to the user’s local files.

### Bug fixes and enhancements

#### For all platforms

- Docker Desktop displays an error if `registry.json` contains more than one organization in the `allowedOrgs` field. If you are using multiple organizations for different groups of developers, you must provision a separate `registry.json` file for each group.
- Fixed a regression in Compose that reverted the container name separator from `-` to `_`. Fixes [docker/compose-switch](https://github.com/docker/compose-switch/issues/24).

#### For Mac

- Fixed the memory statistics for containers in the Dashboard. Fixes [docker/for-mac/#4774](https://github.com/docker/for-mac/issues/6076).
- Added a deprecated option to `settings.json`: `"deprecatedCgroupv1": true`, which switches the Linux environment back to cgroups v1. If your software requires cgroups v1, you should update it to be compatible with cgroups v2. Although cgroups v1 should continue to work, it is likely that some future features will depend on cgroups v2. It is also possible that some Linux kernel bugs will only be fixed with cgroups v2.
- Fixed an issue where putting the machine to Sleep mode after pausing Docker Desktop results in Docker Desktop not being able to resume from pause after the machine comes out of Sleep mode. Fixes [for-mac#6058](https://github.com/docker/for-mac/issues/6058).

#### For Windows

- Doing a `Reset to factory defaults` no longer shuts down Docker Desktop.

### Known issues

#### For all platforms

- The tips of the week show on top of the mandatory login dialog when an organization restriction is enabled via a `registry.json` file.

#### For Windows

- Clicking **Proceed to Desktop** after logging in in the browser, sometimes does not bring the Dashboard to the front.
- After logging in, when the Dashboard receives focus, it sometimes stays in the foreground even when clicking a background window. As a workaround you need to click the Dashboard before clicking another application window.
- When the Dashboard is open, even if it does not have focus or is minimized, it will still catch keyboard shortcuts (e.g. ctrl-r for Restart)

## 4.3.2

{{< release-date date="2021-12-21" >}}

### Security

- Fixed [CVE-2021-45449](../security/security-announcements.md#cve-2021-45449) that affects users currently on Docker Desktop version 4.3.0 or 4.3.1.

Docker Desktop version 4.3.0 and 4.3.1 has a bug that may log sensitive information (access token or password) on the user's machine during login.
This only affects users if they are on Docker Desktop 4.3.0, 4.3.1 and the user has logged in while on 4.3.0, 4.3.1. Gaining access to this data would require having access to the user’s local files.

### Upgrades

[docker scan v0.14.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.14.0)

### Security

**Log4j 2 CVE-2021-44228**: We have updated the `docker scan` CLI plugin.
This new version of `docker scan` is able to detect [Log4j 2
CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) and [Log4j 2
CVE-2021-45046](https://nvd.nist.gov/vuln/detail/CVE-2021-45046)

For more information, read the blog post [Apache Log4j 2
CVE-2021-44228](https://www.docker.com/blog/apache-log4j-2-cve-2021-44228/).

## 4.3.1

{{< release-date date="2021-12-11" >}}

### Upgrades

[docker scan v0.11.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.11.0)

### Security

**Log4j 2 CVE-2021-44228**: We have updated the `docker scan` CLI plugin for you.
Older versions of `docker scan` in Docker Desktop 4.3.0 and earlier versions are
not able to detect [Log4j 2
CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228).

For more information, read the
blog post [Apache Log4j 2
CVE-2021-44228](https://www.docker.com/blog/apache-log4j-2-cve-2021-44228/).

## 4.3.0

{{< release-date date="2021-12-02" >}}

### Upgrades

- [Docker Engine v20.10.11](../engine/release-notes/20.10.md#201011)
- [containerd v1.4.12](https://github.com/containerd/containerd/releases/tag/v1.4.12)
- [Buildx 0.7.1](https://github.com/docker/buildx/releases/tag/v0.7.1)
- [Compose v2.2.1](https://github.com/docker/compose/releases/tag/v2.2.1)
- [Kubernetes 1.22.4](https://github.com/kubernetes/kubernetes/releases/tag/v1.22.4)
- [Docker Hub Tool v0.4.4](https://github.com/docker/hub-tool/releases/tag/v0.4.4)
- [Go 1.17.3](https://golang.org/doc/go1.17)

### Bug fixes and minor changes

#### For all platforms

- Added a self-diagnose warning if the host lacks Internet connectivity.
- Fixed an issue which prevented users from saving files from a volume using the Save As option in the Volumes UI. Fixes [docker/for-win#12407](https://github.com/docker/for-win/issues/12407).
- Docker Desktop now uses cgroupv2. If you need to run `systemd` in a container then:
  - Ensure your version of `systemd` supports cgroupv2. [It must be at least `systemd` 247](https://github.com/systemd/systemd/issues/19760#issuecomment-851565075). Consider upgrading any `centos:7` images to `centos:8`.
  - Containers running `systemd` need the following options: [`--privileged --cgroupns=host -v /sys/fs/cgroup:/sys/fs/cgroup:rw`](https://serverfault.com/questions/1053187/systemd-fails-to-run-in-a-docker-container-when-using-cgroupv2-cgroupns-priva).

#### For Mac

- Docker Desktop on Apple silicon no longer requires Rosetta 2, with the exception of [three optional command line tools](troubleshoot-and-support/troubleshoot/known-issues.md).

#### For Windows

- Fixed an issue that caused Docker Desktop to fail during startup if the home directory path contains a character used in regular expressions. Fixes [docker/for-win#12374](https://github.com/docker/for-win/issues/12374).

### Known issue

Docker Desktop Dashboard incorrectly displays the container memory usage as zero on
Hyper-V based machines.
You can use the [`docker stats`](/reference/cli/docker/container/stats/)
command on the command line as a workaround to view the
actual memory usage. See
[docker/for-mac#6076](https://github.com/docker/for-mac/issues/6076).

### Deprecation

- The following internal DNS names are deprecated and will be removed from a future release: `docker-for-desktop`, `docker-desktop`, `docker.for.mac.host.internal`, `docker.for.mac.localhost`, `docker.for.mac.gateway.internal`. You must now use `host.docker.internal`, `vm.docker.internal`, and `gateway.docker.internal`.
- Removed: Custom RBAC rules have been removed from Docker Desktop as it gives `cluster-admin` privileges to all Service Accounts. Fixes [docker/for-mac/#4774](https://github.com/docker/for-mac/issues/4774).

## 4.2.0

{{< release-date date="2021-11-09" >}}

### New

**Pause/Resume**: You can now pause your Docker Desktop session when you are not actively using it and save CPU resources on your machine.

- Ships [Docker Public Roadmap#226](https://github.com/docker/roadmap/issues/226)

**Software Updates**: The option to turn off automatic check for updates is now available for users on all Docker subscriptions, including Docker Personal and Docker Pro. All update-related settings have been moved to the **Software Updates** section.

- Ships [Docker Public Roadmap#228](https://github.com/docker/roadmap/issues/228)

**Window management**: The Docker Desktop Dashboard window size and position persists when you close and reopen Docker Desktop.

### Upgrades

- [Docker Engine v20.10.10](../engine/release-notes/20.10.md#201010)
- [containerd v1.4.11](https://github.com/containerd/containerd/releases/tag/v1.4.11)
- [runc v1.0.2](https://github.com/opencontainers/runc/releases/tag/v1.0.2)
- [Go 1.17.2](https://golang.org/doc/go1.17)
- [Compose v2.1.1](https://github.com/docker/compose/releases/tag/v2.1.1)
- [docker-scan 0.9.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.9.0)

### Bug fixes and minor changes

#### For all platforms

- Improved: Self-diagnose now also checks for overlap between host IPs and `docker networks`.
- Fixed the position of the indicator that displays the availability of an update on the Docker Desktop Dashboard.

#### For Mac

- Fixed an issue that caused Docker Desktop to stop responding upon clicking **Exit** on the fatal error dialog.
- Fixed a rare startup failure affecting users having a `docker volume` bind-mounted on top of a directory from the host. If existing, this fix will also remove manually user added `DENY DELETE` ACL entries on the corresponding host directory.
- Fixed a bug where a `Docker.qcow2` file would be ignored on upgrade and a fresh `Docker.raw` used instead, resulting in containers and images disappearing. Note that if a system has both files (due to the previous bug) then the most recently modified file will be used, to avoid recent containers and images disappearing again. To force the use of the old `Docker.qcow2`, delete the newer `Docker.raw` file. Fixes [docker/for-mac#5998](https://github.com/docker/for-mac/issues/5998).
- Fixed a bug where subprocesses could fail unexpectedly during shutdown, triggering an unexpected fatal error popup. Fixes [docker/for-mac#5834](https://github.com/docker/for-mac/issues/5834).

#### For Windows

- Fixed Docker Desktop sometimes hanging when clicking Exit in the fatal error dialog.
- Fixed an issue that frequently displayed the **Download update** popup when an update has been downloaded but hasn't been applied yet [docker/for-win#12188](https://github.com/docker/for-win/issues/12188).
- Fixed installing a new update killing the application before it has time to shut down.
- Fixed: Installation of Docker Desktop now works even with group policies preventing users to start prerequisite services (e.g. LanmanServer) [docker/for-win#12291](https://github.com/docker/for-win/issues/12291).

## 4.1.1

{{< release-date date="2021-10-12" >}}

### Bug fixes and minor changes

#### For Mac

> When upgrading from 4.1.0, the Docker menu does not change to **Update and restart** so you can just wait for the download to complete (icon changes) and then select **Restart**. This bug is fixed in 4.1.1, for future upgrades.

- Fixed a bug where a `Docker.qcow2` file would be ignored on upgrade and a fresh `Docker.raw` used instead, resulting in containers and images disappearing. If a system has both files (due to the previous bug), then the most recently modified file will be used to avoid recent containers and images disappearing again. To force the use of the old `Docker.qcow2`, delete the newer `Docker.raw` file. Fixes [docker/for-mac#5998](https://github.com/docker/for-mac/issues/5998).
- Fixed the update notification overlay sometimes getting out of sync between the **Settings** button and the **Software update** button in the Docker Desktop Dashboard.
- Fixed the menu entry to install a newly downloaded Docker Desktop update. When an update is ready to install, the **Restart** option changes to **Update and restart**.

#### For Windows

- Fixed a regression in WSL 2 integrations for some distributions (e.g. Arch or Alpine). Fixes [docker/for-win#12229](https://github.com/docker/for-win/issues/12229)
- Fixed update notification overlay sometimes getting out of sync between the Settings button and the Software update button in the Dashboard.

## 4.1.0

{{< release-date date="2021-09-30" >}}

### New

- **Software Updates**: The Settings tab now includes a new section to help you manage Docker Desktop updates. The **Software Updates** section notifies you whenever there's a new update and allows you to download the update or view information on what's included in the newer version.
- **Compose V2** You can now specify whether to use Docker Compose V2 in the General settings.
- **Volume Management**: Volume management is now available for users on any subscription, including Docker Personal. Ships [Docker Public Roadmap#215](https://github.com/docker/roadmap/issues/215)

### Upgrades

- [Compose V2](https://github.com/docker/compose/releases/tag/v2.0.0)
- [Buildx 0.6.3](https://github.com/docker/buildx/releases/tag/v0.6.3)
- [Kubernetes 1.21.5](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.5)
- [Go 1.17.1](https://github.com/golang/go/releases/tag/go1.17.1)
- [Alpine 3.14](https://alpinelinux.org/posts/Alpine-3.14.0-released.html)
- [Qemu 6.1.0](https://wiki.qemu.org/ChangeLog/6.1)
- Base distribution to debian:bullseye

### Bug fixes and minor changes

#### For Windows

- Fixed a bug related to anti-malware software triggering, self-diagnose avoids calling the `net.exe` utility.
- Fixed filesystem corruption in the WSL 2 Linux VM in self-diagnose. This can be caused by [microsoft/WSL#5895](https://github.com/microsoft/WSL/issues/5895).
- Fixed `SeSecurityPrivilege` requirement issue. See [docker/for-win#12037](https://github.com/docker/for-win/issues/12037).
- Fixed CLI context switch sync with UI. See [docker/for-win#11721](https://github.com/docker/for-win/issues/11721).
- Added the key `vpnKitMaxPortIdleTime` to `settings.json` to allow the idle network connection timeout to be disabled or extended.
- Fixed a crash on exit. See [docker/for-win#12128](https://github.com/docker/for-win/issues/12128).
- Fixed a bug where the CLI tools would not be available in WSL 2 distributions.
- Fixed switching from Linux to Windows containers that was stuck because access rights on panic.log. See [for-win#11899](https://github.com/docker/for-win/issues/11899).

### Known Issues

#### For Windows

Docker Desktop may fail to start when upgrading to 4.1.0 on some WSL-based distributions such as ArchWSL. See [docker/for-win#12229](https://github.com/docker/for-win/issues/12229)

## 4.0.1

{{< release-date date="2021-09-13" >}}

### Upgrades

- [Compose V2 RC3](https://github.com/docker/compose/releases/tag/v2.0.0-rc.3)
  - Compose v2 is now hosted on github.com/docker/compose.
  - Fixed go panic on downscale using `compose up --scale`.
  - Fixed a race condition in `compose run --rm` while capturing exit code.

### Bug fixes and minor changes

#### For all platforms

- Fixed a bug where copy-paste was not available in the Docker Desktop Dashboard.

#### For Windows

- Fixed a bug where Docker Desktop would not start correctly with the Hyper-V engine. See [docker/for-win#11963](https://github.com/docker/for-win/issues/11963)

## 4.0.0

{{< release-date date="2021-08-31" >}}

### New

Docker has [announced](https://www.docker.com/blog/updating-product-subscriptions/) updates and extensions to the product subscriptions to increase productivity, collaboration, and added security for our developers and businesses.

The updated [Docker Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement) includes a change to the terms for **Docker Desktop**.

- Docker Desktop **remains free** for small businesses (fewer than 250 employees AND less than $10 million in annual revenue), personal use, education, and non-commercial open source projects.
- It requires a paid subscription (**Pro, Team, or Business**), for as little as $5 a month, for professional use in larger enterprises.
- The effective date of these terms is August 31, 2021. There is a grace period until January 31, 2022 for those that will require a paid subscription to use Docker Desktop.
- The Docker Pro and Docker Team subscriptions now **include commercial use** of Docker Desktop.
- The existing Docker Free subscription has been renamed **Docker Personal**.
- **No changes** to Docker Engine or any other upstream **open source** Docker or Moby project.

To understand how these changes affect you, read the [FAQs](https://www.docker.com/pricing/faq).
For more information, see [Docker subscription overview](../subscription-billing/index.md).

### Upgrades

- [Compose V2 RC2](https://github.com/docker/compose-cli/releases/tag/v2.0.0-rc.2)
  - Fixed project name to be case-insensitive for `compose down`. See [docker/compose-cli#2023](https://github.com/docker/compose-cli/issues/2023)
  - Fixed non-normalized project name.
  - Fixed port merging on partial reference.
- [Kubernetes 1.21.4](https://github.com/kubernetes/kubernetes/releases/tag/v1.21.4)

### Bug fixes and minor changes

#### For Mac

- Fixed a bug where SSH was not available for builds from git URL. Fixes [for-mac#5902](https://github.com/docker/for-mac/issues/5902)

#### For Windows

- Fixed a bug where the CLI tools would not be available in WSL 2 distributions.
- Fixed a bug when switching from Linux to Windows containers due to access rights on `panic.log`. [for-win#11899](https://github.com/docker/for-win/issues/11899)


---

# Index

*Sección: Desktop*

---
build:
  render: never
title: Settings and maintenance
weight: 40
---


---

# How to back up and restore your Docker Desktop data

*Sección: Desktop*

Use this procedure to back up and restore your images and container data. This is useful if you want to reset your VM disk or to move your Docker environment to a new computer, or recover from a failed Docker Desktop update or installation.

> [!IMPORTANT]
>
> If you use volumes or bind-mounts to store your container data, backing up your containers may not be needed, but make sure to remember the options that were used when creating the container or use a [Docker Compose file](../../reference/compose-file/index.md) if you want to re-create your containers with the same configuration after re-installation.

## If Docker Desktop is functioning normally

### Save your data

1. Commit your containers to an image with [`docker container commit`](/reference/cli/docker/container/commit/).

   Committing a container stores filesystem changes and some container configurations, such as labels and environment variables, as a local image. Be aware that environment variables may contain sensitive
   information such as passwords or proxy-authentication, so take care when pushing the resulting image to a registry.

   Also note that filesystem changes in a volume that are attached to the
   container are not included in the image, and must be backed up separately.

   If you used a [named volume](../../engine/storage/index.md#more-details-about-mount-types) to store container data, such as databases, refer to the [back up, restore, or migrate data volumes](../../engine/storage/volumes.md#back-up-restore-or-migrate-data-volumes) page in the storage section.

2. Use [`docker push`](/reference/cli/docker/image/push/) to push any
   images you have built locally and want to keep to the [Docker Hub registry](../../docker-hub/index.md).
   
   > [!TIP]
   >
   > [Set the repository visibility to private](../../docker-hub/repos/index.md) if your image includes sensitive content.

   Alternatively, use [`docker image save -o images.tar image1 [image2 ...]`](/reference/cli/docker/image/save/)
   to save any images you want to keep to a local `.tar` file. 

After backing up your data, you can uninstall the current version of Docker Desktop
and [install a different version](../release-notes.md) or reset Docker Desktop to factory defaults.

### Restore your data

1. Load your images.

   - If you pushed to Docker Hub:
   
      ```console
      $ docker pull <my-backup-image>
      ```
   
   - If you saved a `.tar` file:
   
      ```console
      $ docker image load -i images.tar
      ```

2. Re-create your containers if needed, using [`docker run`](/reference/cli/docker/container/run/),
   or [Docker Compose](../../compose/index.md).

To restore volume data, refer to [backup, restore, or migrate data volumes](../../engine/storage/volumes.md#back-up-restore-or-migrate-data-volumes). 

## If Docker Desktop fails to start or you want to back up the whole Docker Desktop VM

If Docker Desktop cannot launch and must be reinstalled, you can back up its VM disk and image data directly from disk. Docker Desktop must be fully stopped before backing up these files.

{{< tabs >}}
{{< tab name="Windows" >}}

1. Back up Docker containers/images.

   Backup the following file:

   ```console
   %LOCALAPPDATA%\Docker\wsl\data\docker_data.vhdx
   ```

   Copy it to a safe location. 

1. Back up WSL distributions.

   If you're running any WSL Linux distributions (Ubuntu, Alpine, etc.), back them up using [Microsoft's guide](https://learn.microsoft.com/en-us/windows/wsl/faq#how-can-i-back-up-my-wsl-distributions-).

1. Restore. 

   After reinstalling Docker Desktop, restore the `docker_data.vhdx` to the same location and re-import your WSL distributions if needed.

{{< /tab >}}
{{< tab name="Mac" >}}

1. Back up Docker containers/images.

   Backup the following file:

   ```console
   ~/Library/Containers/com.docker.docker/Data/vms/0/data/Docker.raw
   ```

   Copy it to a safe location. 

   > [!TIP]
   >
   > To include Docker Desktop data in Time Machine backups, make sure the `~/Library/Containers/com.docker.docker` directory is not excluded from your Time Machine backup configuration.

1. Restore. 

   After reinstalling Docker Desktop, restore the `Docker.raw` to the same location.

{{< /tab >}}
{{< tab name="Linux" >}}

1. Back up Docker containers/images:

   Backup the following file:

   ```console
   ~/.docker/desktop/vms/0/data/Docker.raw
   ```

   Copy it to a safe location.

1. Restore. 

   After reinstalling Docker Desktop, restore the `Docker.raw` to the same location.

{{< /tab >}}
{{< /tabs >}}


---

# Change your Docker Desktop settings

*Sección: Desktop*

Customize Docker Desktop behavior and optimize performance and resource usage with Docker Desktop's settings.

To open **Settings** either:

- Select the Docker menu {{< inline-image src="../images/whale-x.svg" alt="whale menu" >}} and then **Settings**
- Select the **Settings** icon from the Docker Desktop Dashboard.

You can also locate the `settings-store.json` file at:
 - Mac: `~/Library/Group\ Containers/group.com.docker/settings-store.json`
 - Windows: `C:\Users\[USERNAME]\AppData\Roaming\Docker\settings-store.json`
 - Linux: `~/.docker/desktop/settings-store.json`

For information on enforcing settings at an organization level, see [Settings Management](../../enterprise/security/hardened-desktop/settings-management/settings-reference.md).

## General

Configure startup behavior, UI appearance, terminal preferences, and feature defaults for Docker Desktop.

| Setting                                                           | Description                                                                | Default            | Platform     | Notes                                 |
| ----------------------------------------------------------------- | -------------------------------------------------------------------------- | ------------------ | ------------ | ------------------------------------- |
| **Start Docker Desktop when you sign in to your computer**        | Automatically start Docker Desktop when you sign in to your machine.        | Disabled           | All          | Recommended for frequent users.        |
| **Open Docker Dashboard when Docker Desktop starts**              | Automatically open the dashboard when starting Docker Desktop.              | Disabled           | All          |                                       |
| **Choose theme for Docker Desktop**                               | Apply a **Light** or **Dark** theme to Docker Desktop. | **Use system settings**. | All |                                   |
| **Configure shell completions**                                  | Edits your shell configuration to enable word completion for commands, flags, and Docker objects when you press `<Tab>` in your terminal. For more information, see [Completion](../../engine/cli/completion.md). | Disabled | All | |
| **Choose container terminal** | Sets which terminal opens when you select a container terminal. Use the integrated terminal to run commands in a running container from the Dashboard. For more information, see [Explore containers](../use-desktop/container.md). | Disabled | All | |
| **Enable Docker terminal**.                                       | Interact with your host machine and execute commands directly from Docker Desktop.  | Disabled | All | |
| **Enable Docker Debug by default**                                | Use Docker Debug by default opening the integrated terminal. For more information, see [Explore containers](../use-desktop/container.md#integrated-terminal).   | Disabled | All | |
| **Include VM in Time Machine backups**                            | Back up the Docker Desktop virtual machine. | Disabled | Mac | |
| **Use containerd for pulling and storing images**     | Uses containerd image store instead of classic image store. For more information, see [containerd image store](../features/containerd.md).| Enabled  | All   |           |
| **Expose daemon on tcp://localhost:2375 without TLS** | Allow legacy clients to connect to the Docker daemon. Use with caution as exposing the daemon without TLS can result in remote code execution attacks. | Disabled                  | Windows (Hyper-V backend only) | |
| **Use the WSL 2 based engine** | WSL 2 provides better performance than the Hyper-V backend. For more information, see [Docker Desktop WSL 2 backend](../features/wsl/index.md). | Disabled | Windows | |
| **Add \*.docker.internal to host file**                | Adds internal DNS entries.                                  | Enabled                   | Windows                        | Helps resolve Docker-internal domains |
| **Choose Virtual Machine Manager (VMM)**              | Choose the VMM for creating and managing the Docker Desktop Linux VM. For more information, see [Virtual Machine Manager](../features/vmm.md). | | Mac, Windows | Select **Docker VMM** for optimized container performance. Docker VMM is in Beta. |
| **Choose file sharing implementation for your containers** | Choose whether you want to share files using **VirtioFS**, or **gRPC FUSE** | **VirtioFS** | Mac | Use VirtioFS for speedy file sharing. VirtioFS has reduced the time taken to complete filesystem operations by [up to 98%](https://github.com/docker/roadmap/issues/7#issuecomment-1044452206). It is the only file sharing implementation supported by Docker VMM. |
|**Use Rosetta for x86_64/amd64 emulation on Apple Silicon** | Accelerate x86/AMD64 binary emulation on Apple Silicon. This option is only available if you have selected **Apple Virtualization framework** as the Virtual Machine Manager. | Disabled | Mac | |
| **Send usage statistics** | Send diagnostics, crash reports, and usage data to Docker to improve and troubleshoot the application. Docker may periodically prompt you for more information. | Enabled | All | |
| **Use Enhanced Container Isolation** | Prevent containers from breaching the Linux VM. For more information, see [Enhanced Container Isolation](../../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md). | Disabled | All | Must be signed in and have a Docker Business subscription. |
| **Show CLI hints**                                   | Display helpful CLI suggestions in terminal.               | Enabled                  | All        | Improves discoverability              |
| **Enable Docker Scout image analysis**                | Show a **Start analysis** button when inspecting an image, which analyzes the image with Docker Scout.         | Enabled                   | All   | |
| **Enable background SBOM indexing** | Automatically analyze images that you build or pull. | Disabled | All | |
| **Automatically check configuration** | Regularly check your configuration to ensure no unexpected changes have been made by another application. Notifies you if changes are found with the option to restore the configuration directly from the notification. For more information, see the [FAQs](../troubleshoot-and-support/faqs/macfaqs.md#why-do-i-keep-getting-a-notification-telling-me-an-application-has-changed-my-desktop-configurations). | Enabled | Mac | Docker Desktop checks if your setup, configured during installation, has been altered by external apps like Orbstack. Docker Desktop checks the symlinks of Docker binaries to `/usr/local/bin` and the symlink of the default Docker socket. Additionally, Docker Desktop ensures that the context is switched to `desktop-linux` on startup. |

## Resources

Control the CPU, memory, disk, file sharing, proxy, and network resources available to Docker Desktop.

### Advanced

| Setting             | Description                               | Platform | Notes                                 |
| ------------------- | ----------------------------------------- | -------- | ------------------------------------- |
| **CPU limit** | Specify the maximum number of CPUs to be used by Docker Desktop. | Mac, Linux, Windows Hyper-V | |
| **Memory limit** | RAM allocated to the Docker VM | Mac, Linux, Windows Hyper-V | Defaults to 50% of your host's memory. |
| **Swap** | Configure swap file size as needed. | Mac, Linux, Windows Hyper-V | 1 GB default. |
| **Disk usage limit** | Specify the maximum amount of disk space the engine can use. | Mac, Linux, Windows Hyper-V | |
|  **Disk image location** | Specify the location of the Linux volume where containers and images are stored. On the **Advanced** tab, you can limit resources available to the Docker Linux VM. | Mac, Linux, Windows Hyper-V | You can also move the disk image to a different location. If you attempt to move a disk image to a location that already has one, you are asked if you want to use the existing image or replace it. |
| **Resource Saver** | Enable or disable [Resource Saver mode](../use-desktop/resource-saver.md), which significantly reduces CPU and memory utilization on the host by automatically turning off the Linux VM when Docker Desktop is idle. | Mac, Linux, Windows Hyper-V | Restarts automatically when containers run. Restart may take 3–10 seconds. |

In WSL 2 mode, configure memory, CPU, and swap limits on the [WSL 2 utility VM](https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configure-global-options-with-wslconfig).

> [!TIP]
>
> If you feel Docker Desktop starting to get slow or you're running
> multi-container workloads, increase the memory and disk image space allocation.

### File sharing

Use File sharing to allow local directories on your machine to be shared with
Linux containers. This is especially useful for editing source code in an IDE on
the host while running and testing the code in a container.

| Setting             | Description                               | Platform | Notes                                 |
| ------------------- | ----------------------------------------- | -------- | ------------------------------------- |
| **Synchronized file shares** | Fast and flexible host-to-VM file sharing, enhancing bind mount performance through the use of synchronized filesystem caches. To learn more, see [Synchronized file share](../features/synchronized-file-sharing.md). | Mac, Linux, Windows Hyper-V | Available with Pro, Team, and Business subscriptions. |
| **Virtual file shares** | Share local directories with Linux containers. By default the `/Users`, `/Volumes`, `/private`, `/tmp` and `/var/folders` directory are shared. If your project is outside this directory then it must be added to the list, otherwise you may get `Mounts denied` or `cannot start service` errors at runtime. | Mac, Linux, Windows Hyper-V | |


- Share only the directories that you need with the container. File sharing
introduces overhead as any changes to the files on the host need to be notified
to the Linux VM. Sharing too many files can lead to high CPU load and slow
filesystem performance.
- Shared folders are designed to allow application code to be edited
on the host while being executed in containers. For non-code items
such as cache directories or databases, the performance will be much
better if they are stored in the Linux VM, using a [data volume](../../engine/storage/volumes.md)
(named volume) or [data container](../../engine/storage/volumes.md).
- If you share the whole of your home directory into a container, Mac may
prompt you to give Docker access to personal areas of your home directory such as
your Reminders or Downloads.
- By default, Mac file systems are case-insensitive while Linux is case-sensitive.
On Linux, it is possible to create two separate files: `test` and `Test`,
while on Mac these filenames would actually refer to the same underlying
file. This can lead to problems where an app works correctly on a developer's
machine (where the file contents are shared) but fails when run in Linux in
production (where the file contents are distinct). To avoid this, Docker Desktop
insists that all shared files are accessed as their original case. Therefore,
if a file is created called `test`, it must be opened as `test`. Attempts to
open `Test` will fail with the error "No such file or directory". Similarly,
once a file called `test` is created, attempts to create a second file called
`Test` will fail.

For more information, see [Volume mounting requires file sharing for any project directories outside of `/Users`](../troubleshoot-and-support/troubleshoot/topics.md).

### Proxies

Docker Desktop supports HTTP/HTTPS and SOCKS5 proxies. SOCKS5 requires a Business subscription.

To prevent developers from accidentally changing the proxy settings, see
[Settings Management](../../enterprise/security/hardened-desktop/settings-management/index.md#what-features-can-i-configure-with-settings-management).

#### Docker Desktop proxy

Used for Docker Desktop host-level traffic: signing in to Docker, the Desktop application, CLI, and extensions. Acts as a fallback for `docker image pull` only when [Containers proxy](#containers-proxy) is not configured.

| Proxy mode | Description |
|------------|-------------|
| **System proxy** | Use the proxy configured on the host (static or Proxy Auto-Configuration (PAC)). Docker Desktop reads this automatically. |
| **No proxy** | Connect directly without a proxy. |
| **Manual configuration** | Enter a **Web Server (HTTP)** and **Secure Web Server (HTTPS)** URL manually. Use the format `http://proxy:port` or `https://proxy:port`. You can also specify hosts and domains that should bypass the proxy, for example: `registry-1.docker.com,*.docker.com,10.0.0.0/8`. |

> [!NOTE]
>
> If you use a PAC file hosted on a web server, add the MIME type `application/x-ns-proxy-autoconfig` for the `.pac` extension. Without this, the PAC file may not parse correctly. See [Hardened Docker Desktop](../../enterprise/security/hardened-desktop/air-gapped-containers.md#proxy-auto-configuration-files).

#### Containers proxy

Used for `docker image pull` (always enforced - all `docker pull` and Compose pull operations go through this proxy) and for outbound traffic from running containers when air-gapped container enforcement is configured. If a PAC file is configured here, ensure it returns an appropriate proxy server for Docker registry endpoints, or image pulls will fail.

| Proxy mode | Description |
|------------|-------------|
| **Same as host proxy** | Use the same proxy configuration as the Docker Desktop proxy. |
| **System proxy** | Use the proxy configured on the host. |
| **No proxy** | Connect directly without a proxy. |
| **Manual configuration** | Enter a **Web Server (HTTP)** and **Secure Web Server (HTTPS)** URL manually. Use the format `http://proxy:port` or `https://proxy:port`. You can also specify hosts and domains that should bypass the proxy, for example: `registry-1.docker.com,*.docker.com,10.0.0.0/8`. |

> [!NOTE]
>
> The HTTPS proxy used for image scanning is configured using the `HTTPS_PROXY` environment variable.

#### Windows Docker daemon proxy

When you run Windows containers, enable **Use proxy for Windows Docker daemon**
to let the Windows Docker daemon connect to Docker Desktop's internal proxy.
This allows Windows containers to use the configured Docker Desktop proxy, and
it is required if you want [Registry Access Management](../../enterprise/security/hardened-desktop/registry-access-management.md)
restrictions to apply to Windows image operations. Administrators can manage
the same behavior with
[**Override Windows "dockerd" port**](../../enterprise/security/hardened-desktop/settings-management/settings-reference.md#override-windows-dockerd-port).

#### Proxy authentication

| Method |  Behavior | Notes |
|--------|-----------| ----- |
| **Basic** | Docker Desktop prompts for credentials and caches them in the OS credential store. | Use an `https://` proxy URL to protect passwords in transit. Supports TLS 1.3. |
| **Kerberos / NTLM** |  Centralizes authentication — developers aren't prompted for credentials, reducing the risk of account lockouts. If the proxy returns multiple schemes in a 407 response, Docker Desktop defaults to Basic. | Requires a Business subscription. To enable Kerberos or NTLM proxy authentication you must pass the `--proxy-enable-kerberosntlm` installer flag during installation via the command line, and ensure your proxy server is properly configured for Kerberos or NTLM authentication. |

### Network

> [!NOTE]
>
> On Windows, the **Network** tab is not available in Windows container mode because Windows manages networking.

| Setting | Description | Platform |
|---------|-------------|----------|
| **Docker subnet** | Set a custom subnet to avoid conflicts with IPs in your environment. Docker Desktop uses a private IPv4 network for internal services, including a DNS server and HTTP proxy. Default: `192.168.65.0/24`. | All |
| **Use kernel networking for UDP** | Use a more efficient kernel networking path for UDP traffic. May not be compatible with VPN software. | Mac |
| **Enable host networking** | Allows containers started with `--net=host` to use `localhost` to connect to TCP and UDP services on the host. Also allows host software to use `localhost` to connect to TCP and UDP services in the container. | Mac |

On Windows and Mac, you can also set the default networking mode and DNS resolution behavior. For more information, see [Networking](../features/networking/networking-how-tos.md#network-how-tos-for-mac-and-windows).

### WSL integration (Windows only)

| Setting             | Description                               | Notes                               |
| ------------------- | ----------------------------------------- | ------------------------------------- |
| WSL distribution integration| Select which WSL 2 distributions have Docker WSL integration enabled. | Integration is enabled on your default WSL distribution by default. To change your default distribution, run `wsl --set-default <distribution name>`. |

For more details on configuring Docker Desktop to use WSL 2, see
[Docker Desktop WSL 2 backend](../features/wsl/index.md).

## Docker Engine

Configure the Docker daemon using a JSON configuration file.

The file is located at `$HOME/.docker/daemon.json`. Edit it directly in the Docker Desktop Dashboard or in a text editor.

To see the full list of possible configuration options, see the
[dockerd command reference](/reference/cli/dockerd/).

## Builders

Use the **Builders** tab to inspect and manage builders in the Docker Desktop settings.

### Inspect

To inspect builders, find the builder that you want to inspect and select the
expand icon. You can only inspect active builders.

Inspecting an active builder shows:

- BuildKit version
- Status
- Driver type
- Supported capabilities and platforms
- Disk usage
- Endpoint address

### Select a different builder

The **Selected builder** section displays the selected builder.
To select a different builder:

1. Find the builder that you want to use under **Available builders**
2. Open the drop-down menu next to the builder's name.
3. Select **Use** to switch to this builder.

Your build commands now use the selected builder by default.

### Create a builder

To create a builder, use the Docker CLI. See
[Create a new builder](/build/builders/manage/#create-a-new-builder)

### Remove a builder

You can remove a builder if:

- The builder isn't your [selected builder](/build/builders/#selected-builder)
- The builder isn't [associated with a Docker context](/build/builders/#default-builder).

  To remove builders associated with a Docker context, remove the context using
  the `docker context rm` command.

To remove a builder:

1. Find the builder that you want to remove under **Available builders**
2. Open the drop-down menu.
3. Select **Remove** to remove this builder.

If the builder uses the `docker-container` or `kubernetes` driver,
the build cache is also removed, along with the builder.

### Stop and start a builder

Builders that use the
[`docker-container` driver](/build/builders/drivers/docker-container/)
run the BuildKit daemon in a container.
You can start and stop the BuildKit container using the drop-down menu.

Running a build automatically starts the container if it's stopped.

You can only start and stop builders using the `docker-container` driver.

## AI

From the AI tab, you can configure settings for:

- [Gordon](../../ai/gordon/index.md), the AI-powered assistant that takes action on your Docker workflows.
- [Docker Model Runner](../../ai/model-runner/index.md), which makes it easy to manage, run, and deploy AI models using Docker.

## Kubernetes

> [!NOTE]
>
> On Windows the **Kubernetes** tab is not available in Windows container mode.

Enable and configure the built-in standalone Kubernetes cluster for testing container deployments.

| Setting             | Description                               |
| ------------------- | ----------------------------------------- |
| **Enable Kubernetes** | Install and run a standalone Kubernetes server as a Docker container for testing deployments. |
| **Cluster provisioning method** | Choose either **Kubeadm**, a single-node cluster with the version set by Docker Desktop, or **Kind**, a multi-node cluster where you can set the version and number of nodes. |
| **Show system containers (advanced)** | Show internal containers when using Docker commands. |
| **Reset Kubernetes cluster** | Delete all stacks and Kubernetes resources. |

For more information about using the Kubernetes integration with Docker Desktop,
see [Explore the Kubernetes view](../use-desktop/kubernetes.md).

## Software updates

Manage how and when Docker Desktop checks for and downloads updates.

| Setting             | Description                               | Default                             |
| ------------------- | ----------------------------------------- | ------------------------------------- |
| **Automatically check for updates** | Notifies you of available updates in the Docker menu and Dashboard footer. | Enabled |
| **Always download updates** | Automatically download new versions of Docker Desktop in the background. | Disabled |
| **Automatically update components** | Update Docker Desktop components (such as Docker Compose, Docker Scout, and the Docker CLI) independently, without a full restart. | Enabled |

## Extensions

Enable Docker Extensions and control which extensions are available to install and run.

| Setting             | Description                               |
| ------------------- | ----------------------------------------- |
| **Enable Docker Extensions** | Turn Docker Extensions on or off. Turned off by default. |
| **Allow only extensions distributed through the Docker Marketplace** | Restrict extensions to Marketplace-approved sources only. |
| **Show Docker Extensions system containers** | Show containers used by Docker Extensions. |

For more information about Docker extensions, see [Docker Extensions](../../extensions/index.md).

## Beta features

Beta features provide access to future product functionality.
These features are intended for testing and feedback only as they may change
between releases without warning or remove them entirely from a future
release. Beta features must not be used in production environments.
Docker doesn't offer support for beta features.

You can also sign up to the [Developer Preview program](https://www.docker.com/community/get-involved/developer-preview/) from the **Beta features** tab.

For a list of current experimental features in the Docker CLI, see [Docker CLI Experimental features](https://github.com/docker/cli/blob/master/experimental/README.md).

## Notifications

Choose which types of Docker Desktop notifications you want to receive.

| Notification type | Default|
| ----------------- | ------ |
| Status updates on tasks and processes | Enabled |
| Recommendations from Docker | Enabled |
| Docker announcements | Enabled |
| Docker surveys | Enabled |
| Error notifications | Always Enabled (cannot be changed) |
| New releases | Always Enabled (cannot be changed) |

Notifications appear briefly in the lower-right of the Docker Desktop Dashboard, then move to the **Notifications** drawer, accessible from the top-right of the Dashboard.

## Advanced (Mac only)

Reconfigure CLI tool installation paths and privileged system permissions. With Docker Desktop version 4.88.0 and earlier, these can be set during installation.

| Setting             | Description                               | Notes                               |
| ------------------- | ----------------------------------------- | ------------------------------------- |
| CLI tools installation — **System** | Install Docker CLI tools to `/usr/local/bin`. | Requires password with version 4.89.0 and later. |
| CLI tools installation — **User** | Install Docker CLI tools to `$HOME/.docker/bin`. This is the default with version 4.89.0 and later. | Automatically added to your PATH in version 4.89.0 and later. |
| **Allow the default Docker socket to be used** | Creates `/var/run/docker.sock` which some third party clients may use to communicate with Docker Desktop. For more information, see [permission requirements for macOS](../setup/install/mac-permission-requirements.md#installing-symlinks). | Requires password |
| **Allow privileged port mapping** | Starts the privileged helper process which binds the ports that are between 1 and 1024. For more information, see [permission requirements for macOS](../setup/install/mac-permission-requirements.md#binding-privileged-ports). | Available with version 4.88.0 and earlier. Requires password |

## Docker Offload

Enable Docker Offload and configure idle timeout and GPU support for cloud-based workloads.

| Setting             | Description                               | Notes                                 |
| ------------------- | ----------------------------------------- | ------------------------------------- |
| **Enable Docker Offload** | Run your containers in the cloud.  | Requires sign-in and an Offload subscription |
| **Idle timeout** | Set the duration of time between no activity and Docker Offload entering idle mode. For details about idle timeout, see [Session management and idle state](../../offload/about.md#session-management-and-idle-state). | |
| **Enable GPU support** | Let your workloads use cloud GPU if available. | |


---

# Index

*Sección: Desktop*

---
build:
  render: never
title: Setup
weight: 10
---


---

# Allowlist for Docker Desktop

*Sección: Desktop*

{{< summary-bar feature_name="Allow list" >}}

This page contains the domain URLs that you need to add to a firewall allowlist to ensure Docker Desktop works properly within your organization.

## Domain URLs to allow

| Domains                                                                              | Description                                  |
| ------------------------------------------------------------------------------------ | -------------------------------------------- |
| https://notify.bugsnag.com                                                           | Error reports                                |
| https://sessions.bugsnag.com                                                         | Error reports                                |
| https://auth.docker.io                                                               | Authentication                               |
| https://cdn.auth0.com                                                                | Authentication                               |
| https://login.docker.com                                                             | Authentication                               |
| https://auth.docker.com                                                              | Authentication                               |
| https://desktop.docker.com                                                           | Update                                       |
| https://hub.docker.com                                                               | Docker Hub                                   |
| https://registry-1.docker.io                                                         | Docker Pull/Push                             |
| https://production.cloudfront.docker.com                                             | Docker Pull/Push                             |
| https://docker-pinata-support.s3.amazonaws.com                                       | Troubleshooting                              |
| https://api.dso.docker.com                                                           | Docker Scout service                         |
| https://api.docker.com                                                               | New API                                      |
| https://api.offload.docker.com                                                       | Docker Offload                               |
| https://dhi.io                                                                       | Docker Hardened Images                       |
| https://registry.scout.docker.com                                                    | Docker Scout registry for DHI attestations   |
| https://ai-backend-service.docker.com                                                | [Gordon](../../ai/gordon/index.md)       |


---

# Install

*Sección: Desktop*




---

# Install Docker Desktop on Linux

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees or more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopLinuxInstall).

This page contains information about general system requirements, supported platforms, and instructions on how to install Docker Desktop for Linux.

> [!IMPORTANT]
>
> Docker Desktop on Linux runs a Virtual Machine (VM) which creates and uses a custom docker context, `desktop-linux`, on startup.
>
> This means images and containers deployed on the Linux Docker Engine (before installation) are not available in Docker Desktop for Linux.
>
> {{< accordion title=" Docker Desktop vs Docker Engine: What's the difference?" >}}

> [!IMPORTANT]
>
> For commercial use of Docker Engine obtained via Docker Desktop within larger enterprises (exceeding 250 employees or with annual revenue surpassing $10 million USD), a [paid subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopLinuxInstall) is required.

Docker Desktop for Linux provides a user-friendly graphical interface that simplifies the management of containers and services. It includes Docker Engine as this is the core technology that powers Docker containers. Docker Desktop for Linux also comes with additional features like Docker Scout and Docker Extensions.

### Installing Docker Desktop and Docker Engine

Docker Desktop for Linux and Docker Engine can be installed side-by-side on the
same machine. Docker Desktop for Linux stores containers and images in an isolated
storage location within a VM and offers
controls to restrict [its resources](../../../settings-and-maintenance/settings.md#resources). Using a dedicated storage
location for Docker Desktop prevents it from interfering with a Docker Engine
installation on the same machine.

While it's possible to run both Docker Desktop and Docker Engine simultaneously,
there may be situations where running both at the same time can cause issues.
For example, when mapping network ports (`-p` / `--publish`) for containers, both
Docker Desktop and Docker Engine may attempt to reserve the same port on your
machine, which can lead to conflicts ("port already in use").

We generally recommend stopping the Docker Engine while you're using Docker Desktop
to prevent the Docker Engine from consuming resources and to prevent conflicts
as described above.

Use the following command to stop the Docker Engine service:

```console
$ sudo systemctl stop docker docker.socket containerd
```

Depending on your installation, the Docker Engine may be configured to automatically
start as a system service when your machine starts. Use the following command to
disable the Docker Engine service, and to prevent it from starting automatically:

```console
$ sudo systemctl disable docker docker.socket containerd
```

### Switching between Docker Desktop and Docker Engine

The Docker CLI can be used to interact with multiple Docker Engines. For example,
you can use the same Docker CLI to control a local Docker Engine and to control
a remote Docker Engine instance running in the cloud. [Docker Contexts](../../../../engine/manage-resources/contexts.md)
allow you to switch between Docker Engines instances.

When installing Docker Desktop, a dedicated "desktop-linux" context is created to
interact with Docker Desktop. On startup, Docker Desktop automatically sets its
own context (`desktop-linux`) as the current context. This means that subsequent
Docker CLI commands target Docker Desktop. On shutdown, Docker Desktop resets
the current context to the `default` context.

Use the `docker context ls` command to view what contexts are available on your
machine. The current context is indicated with an asterisk (`*`).

```console
$ docker context ls
NAME            DESCRIPTION                               DOCKER ENDPOINT                                  ...
default *       Current DOCKER_HOST based configuration   unix:///var/run/docker.sock                      ...
desktop-linux                                             unix:///home/<user>/.docker/desktop/docker.sock  ...
```

If you have both Docker Desktop and Docker Engine installed on the same machine,
you can run the `docker context use` command to switch between the Docker Desktop
and Docker Engine contexts. For example, use the "default" context to interact
with the Docker Engine:

```console
$ docker context use default
default
Current context is now "default"
```

And use the `desktop-linux` context to interact with Docker Desktop:

```console
$ docker context use desktop-linux
desktop-linux
Current context is now "desktop-linux"
```

Refer to the [Docker Context documentation](../../../../engine/manage-resources/contexts.md) for more details.
{{< /accordion >}}

## Supported platforms

Docker provides `.deb` and `.rpm` packages for the following Linux distributions
and architectures:

| Platform                                   | x86_64 / amd64 |
| :----------------------------------------- | :------------: |
| [Ubuntu](ubuntu.md)                        |       ✅       |
| [Debian](debian.md)                        |       ✅       |
| [Red Hat Enterprise Linux (RHEL)](rhel.md) |       ✅       |
| [Fedora](fedora.md)                        |       ✅       |

An experimental package is available for [Arch](archlinux.md)-based distributions. Docker has not tested or verified the installation.

Docker supports Docker Desktop on the current and previous LTS releases of the aforementioned distributions, as well as the most recent version.

## General system requirements

To install Docker Desktop successfully, your Linux host must meet the following general requirements:

- 64-bit kernel and CPU support for virtualization.
- KVM virtualization support. Follow the [KVM virtualization support instructions](#kvm-virtualization-support) to check if the KVM kernel modules are enabled and how to provide access to the KVM device.
- QEMU must be version 5.2 or later. We recommend upgrading to the latest version.
- systemd init system.
- GNOME, KDE, or MATE desktop environments are supported but others may work.
  - For many Linux distributions, the GNOME environment does not support tray icons. To add support for tray icons, you need to install a GNOME extension. For example, [AppIndicator](https://extensions.gnome.org/extension/615/appindicator-support/).
- At least 4 GB of RAM.
- Enable configuring ID mapping in user namespaces, see [File sharing](../../../troubleshoot-and-support/faqs/linuxfaqs.md#how-do-i-enable-file-sharing). Note that for Docker Desktop version 4.35 and later, this is not required anymore.
- Recommended: [Initialize `pass`](../../sign-in.md#credentials-management-for-linux-users) for credentials management.

Docker Desktop for Linux runs a Virtual Machine (VM). For more information on why, see [Why Docker Desktop for Linux runs a VM](../../../troubleshoot-and-support/faqs/linuxfaqs.md#why-does-docker-desktop-for-linux-run-a-vm).

> [!NOTE]
>
> Docker does not provide support for running Docker Desktop for Linux in nested virtualization scenarios. We recommend that you run Docker Desktop for Linux natively on supported distributions.

### KVM virtualization support

Docker Desktop runs a VM that requires [KVM support](https://www.linux-kvm.org).

The `kvm` module should load automatically if the host has virtualization support. To load the module manually, run:

```console
$ modprobe kvm
```

Depending on the processor of the host machine, the corresponding module must be loaded:

```console
$ modprobe kvm_intel  # Intel processors

$ modprobe kvm_amd    # AMD processors
```

If the above commands fail, you can view the diagnostics by running:

```console
$ kvm-ok
```

To check if the KVM modules are enabled, run:

```console
$ lsmod | grep kvm
kvm_amd               167936  0
ccp                   126976  1 kvm_amd
kvm                  1089536  1 kvm_amd
irqbypass              16384  1 kvm
```

#### Set up KVM device user permissions

To check ownership of `/dev/kvm`, run :

```console
$ ls -al /dev/kvm
```

Add your user to the kvm group in order to access the kvm device:

```console
$ sudo usermod -aG kvm $USER
```

Sign out and sign back in so that your group membership is re-evaluated.

## Using Docker SDKs with Docker Desktop

Docker Desktop for Linux uses a per-user socket instead of the system-wide `/var/run/docker.sock`. Docker SDKs and tools that connect directly to the Docker daemon need the `DOCKER_HOST` environment variable set to connect to Docker Desktop. For configuration details, see [How do I use Docker SDKs with Docker Desktop for Linux?](../../../troubleshoot-and-support/faqs/linuxfaqs.md#how-do-i-use-docker-sdks-with-docker-desktop-for-linux).

## Where to go next

- Install Docker Desktop for Linux for your specific Linux distribution:
  - [Install on Ubuntu](ubuntu.md)
  - [Install on Debian](debian.md)
  - [Install on Red Hat Enterprise Linux (RHEL)](rhel.md)
  - [Install on Fedora](fedora.md)
  - [Install on Arch](archlinux.md)


---

# Install Docker Desktop on Arch-based distributions

*Sección: Desktop*

{{< summary-bar feature_name="Docker Desktop Archlinux" >}}

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees OR more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopArchlinuxInstall).

This page contains information on how to install, launch and upgrade Docker Desktop on an Arch-based distribution. 

## Prerequisites

To install Docker Desktop successfully, you must meet the [general system requirements](index.md#general-system-requirements).

## Install Docker Desktop

1. [Install the Docker client binary on Linux](../../../../engine/install/binaries.md#install-daemon-and-client-binaries-on-linux). Static binaries for the Docker client are available for Linux as `docker`. You can use:

   ```console
   $ wget https://download.docker.com/linux/static/stable/x86_64/docker-{{% param "docker_ce_version" %}}.tgz -qO- | tar xvfz - docker/docker --strip-components=1
   $ sudo cp -rp ./docker /usr/local/bin/ && rm -r ./docker
   ```

2. Download the latest Arch package from the [Release notes](../../../release-notes.md).

3. Install the package:

   ```console
   $ sudo pacman -U ./docker-desktop-x86_64.pkg.tar.zst
   ```

   By default, Docker Desktop is installed at `/opt/docker-desktop`.

## Launch Docker Desktop

{{% include "desktop-linux-launch.md" %}}

## Next steps

- Explore [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopArchlinuxInstall) to see what Docker can offer you.
- Take a look at [Get started with Docker](/get-started/tutorials/run-an-app.md) to learn how to build an image and run it as a containerized application.
- [Explore Docker Desktop](../../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, how to run and submit diagnostics, and submit issues.
- [FAQs](../../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../../settings-and-maintenance/backup-and-restore.md) provides instructions
  on backing up and restoring data related to Docker.


---

# Install Docker Desktop on Debian

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees OR more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopDebianInstall).

This page contains information on how to install, launch, and upgrade Docker Desktop on a Debian distribution.

## Prerequisites

To install Docker Desktop successfully, you must:

- Meet the [general system requirements](index.md#general-system-requirements).
- Have a 64-bit version of Debian 12.
- For a Gnome Desktop environment, you must also install AppIndicator and KStatusNotifierItem [Gnome extensions](https://extensions.gnome.org/extension/615/appindicator-support/).
- If you're not using GNOME, you must install `gnome-terminal` to enable terminal access from Docker Desktop:

  ```console
  $ sudo apt install gnome-terminal
  ```

## Install Docker Desktop

Recommended approach to install Docker Desktop on Debian:

1. Set up Docker's `apt` repository.
   See step one of [Install using the `apt` repository](../../../../engine/install/debian.md#install-using-the-repository).

2. Download the latest [DEB package](https://desktop.docker.com/linux/main/amd64/docker-desktop-amd64.deb?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-linux-amd64). For checksums, see the [Release notes](../../../release-notes.md).

3. Install the package using `apt`:

  ```console
  $ sudo apt-get update
  $ sudo apt-get install ./docker-desktop-amd64.deb
  ```

  > [!NOTE]
  >
  > At the end of the installation process, `apt` displays an error due to installing a downloaded package. You
  > can ignore this error message.
  >
  > ```text
  > N: Download is performed unsandboxed as root, as file '/home/user/Downloads/docker-desktop.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
  > ```

   By default, Docker Desktop is installed at `/opt/docker-desktop`.

The DEB package includes a post-install script that completes additional setup steps automatically.

The post-install script:

- Sets the capability on the Docker Desktop binary to map privileged ports and set resource limits.
- Adds a DNS name for Kubernetes to `/etc/hosts`.
- Creates a symlink from `/usr/local/bin/com.docker.cli` to `/usr/bin/docker`.
  This is because the classic Docker CLI is installed at `/usr/bin/docker`. The Docker Desktop installer also installs a Docker CLI binary that includes cloud-integration capabilities and is essentially a wrapper for the Compose CLI, at`/usr/local/bin/com.docker.cli`. The symlink ensures that the wrapper can access the classic Docker CLI. 

## Launch Docker Desktop

{{% include "desktop-linux-launch.md" %}}

## Upgrade Docker Desktop

Once a new version for Docker Desktop is released, the Docker UI shows a notification.
You need to download the new package each time you want to upgrade Docker Desktop and run:

```console
$ sudo apt-get install ./docker-desktop-amd64.deb
```

## Next steps

- Explore [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopDebianInstall) to see what Docker can offer you.
- Take a look at [Get started with Docker](/get-started/tutorials/run-an-app.md) to learn how to build an image and run it as a containerized application.
- [Explore Docker Desktop](../../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, how to run and submit diagnostics, and submit issues.
- [FAQs](../../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../../settings-and-maintenance/backup-and-restore.md) provides instructions
  on backing up and restoring data related to Docker.


---

# Install Docker Desktop on Fedora

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees OR more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopFedoraInstall).

This page contains information on how to install, launch and upgrade Docker Desktop on a Fedora distribution.

## Prerequisites

To install Docker Desktop successfully, you must:

- Meet the [general system requirements](index.md#general-system-requirements).
- Have a 64-bit version of Fedora 43 or later.
- For a GNOME desktop environment you must install AppIndicator and KStatusNotifierItem [GNOME extensions](https://extensions.gnome.org/extension/615/appindicator-support/).
- If you're not using GNOME, you must install `gnome-terminal` to enable terminal access from Docker Desktop:

   ```console
   $ sudo dnf install gnome-terminal
   ```

## Install Docker Desktop

To install Docker Desktop on Fedora:

1. Set up [Docker's package repository](../../../../engine/install/fedora.md#set-up-the-repository).

2. Download the latest [RPM package](https://desktop.docker.com/linux/main/amd64/docker-desktop-x86_64.rpm?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-linux-amd64). For checksums, see the [Release notes](../../../release-notes.md).

3. Install the package with dnf as follows:

   ```console
   $ sudo dnf install ./docker-desktop-x86_64.rpm
   ```

   By default, Docker Desktop is installed at `/opt/docker-desktop`.

The RPM package includes a post-install script that completes additional setup steps automatically.

The post-install script:

- Sets the capability on the Docker Desktop binary to map privileged ports and set resource limits.
- Adds a DNS name for Kubernetes to `/etc/hosts`.
- Creates a symlink from `/usr/local/bin/com.docker.cli` to `/usr/bin/docker`.
  This is because the classic Docker CLI is installed at `/usr/bin/docker`. The Docker Desktop installer also installs a Docker CLI binary that includes cloud-integration capabilities and is essentially a wrapper for the Compose CLI, at`/usr/local/bin/com.docker.cli`. The symlink ensures that the wrapper can access the classic Docker CLI. 

## Launch Docker Desktop

{{% include "desktop-linux-launch.md" %}}

## Upgrade Docker Desktop

Once a new version for Docker Desktop is released, the Docker UI shows a notification.
You need to first remove the previous version and then download the new package each time you want to upgrade Docker Desktop. Run:

```console
$ sudo dnf remove docker-desktop
$ sudo dnf install ./docker-desktop-x86_64.rpm
```

## Next steps

- Explore [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopFedoraInstall) to see what Docker can offer you.
- Take a look at [Get started with Docker](/get-started/tutorials/run-an-app.md) to learn how to build an image and run it as a containerized application.
- [Explore Docker Desktop](../../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, how to run and submit diagnostics, and submit issues.
- [FAQs](../../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../../settings-and-maintenance/backup-and-restore.md) provides instructions
  on backing up and restoring data related to Docker.


---

# Install Docker Desktop on RHEL

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees or more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopRhelInstall).

This page contains information on how to install, launch and upgrade Docker Desktop on a Red Hat Enterprise Linux (RHEL) distribution.

## Prerequisites

To install Docker Desktop successfully, you must:

- Meet the [general system requirements](index.md#general-system-requirements).
- Have a 64-bit version of either RHEL 9 or RHEL 10.

- If `pass` is not installed, or it can't be installed, you must enable [CodeReady Linux Builder (CRB) repository](https://access.redhat.com/articles/4348511) and [Extra Packages for Enterprise Linux (EPEL)](https://docs.fedoraproject.org/en-US/epel/).

   {{< tabs group="os_version" >}}
   {{< tab name="RHEL 10" >}}
   ```console
   $ sudo subscription-manager repos --enable codeready-builder-for-rhel-10-$(arch)-rpms
   $ sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm
   $ sudo dnf install pass
   ```

   {{< /tab >}}
   {{< tab name="RHEL 9" >}}
   ```console
   $ sudo subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms
   $ sudo dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
   $ sudo dnf install pass
   ```

   {{< /tab >}}
   {{< /tabs >}}

- For a GNOME desktop environment you must install AppIndicator and KStatusNotifierItem [GNOME extensions](https://extensions.gnome.org/extension/615/appindicator-support/). You must also enable EPEL.

   {{< tabs group="os_version" >}}
   {{< tab name="RHEL 10" >}}
   ```console
   $ # enable EPEL as described above
   $ sudo dnf install gnome-shell-extension-appindicator
   $ sudo gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com
   ```

   {{< /tab >}}
   {{< tab name="RHEL 9" >}}
   ```console
   $ # enable EPEL as described above
   $ sudo dnf install gnome-shell-extension-appindicator
   $ sudo gnome-extensions enable appindicatorsupport@rgcjonas.gmail.com
   ```

   {{< /tab >}}
   {{< /tabs >}}

- If you're not using GNOME, you must install `gnome-terminal` to enable terminal access from Docker Desktop:

   ```console
   $ sudo dnf install gnome-terminal
   ```

## Install Docker Desktop

To install Docker Desktop on RHEL:

1. Set up Docker's package repository as follows:

   ```console
   $ sudo dnf config-manager --add-repo {{% param "download-url-base" %}}/docker-ce.repo
   ```

2. Download the latest [RPM package](https://desktop.docker.com/linux/main/amd64/docker-desktop-x86_64-rhel.rpm?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-linux-amd64).

3. Install the package with dnf as follows:

   ```console
   $ sudo dnf install ./docker-desktop-x86_64-rhel.rpm
   ```

The RPM package includes a post-install script that completes additional setup steps automatically.

The post-install script:

- Sets the capability on the Docker Desktop binary to map privileged ports and set resource limits.
- Adds a DNS name for Kubernetes to `/etc/hosts`.
- Creates a symlink from `/usr/local/bin/com.docker.cli` to `/usr/bin/docker`.
  This is because the classic Docker CLI is installed at `/usr/bin/docker`. The Docker Desktop installer also installs a Docker CLI binary that includes cloud-integration capabilities and is essentially a wrapper for the Compose CLI, at `/usr/local/bin/com.docker.cli`. The symlink ensures that the wrapper can access the classic Docker CLI. 
- Creates a symlink from `/usr/libexec/qemu-kvm` to `/usr/local/bin/qemu-system-x86_64`.

## Launch Docker Desktop

{{% include "desktop-linux-launch.md" %}}

> [!TIP]
>
> To attach Red Hat subscription data to containers, see [Red Hat verified solution](https://access.redhat.com/solutions/5870841).
>
> For example:
> ```console
> $ docker run --rm -it -v "/etc/pki/entitlement:/etc/pki/entitlement" -v "/etc/rhsm:/etc/rhsm-host" -v "/etc/yum.repos.d/redhat.repo:/etc/yum.repos.d/redhat.repo" registry.access.redhat.com/ubi9
> ```

## Upgrade Docker Desktop

Once a new version for Docker Desktop is released, the Docker UI shows a notification.
You need to first remove the previous version and then download the new package each time you want to upgrade Docker Desktop. Run:

```console
$ sudo dnf remove docker-desktop
$ sudo dnf install ./docker-desktop-<arch>-rhel.rpm
```

## Next steps

- Review [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopRhelInstall) to see what Docker can offer you.
- Take a look at [Get started with Docker](/get-started/tutorials/run-an-app.md) to learn how to build an image and run it as a containerized application.
- [Explore Docker Desktop](../../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, how to run and submit diagnostics, and submit issues.
- [FAQs](../../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../../settings-and-maintenance/backup-and-restore.md) provides instructions
  on backing up and restoring data related to Docker.


---

# Install Docker Desktop on Ubuntu

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees or more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopUbuntuInstall).

This page contains information on how to install, launch and upgrade Docker Desktop on an Ubuntu distribution.

## Prerequisites

To install Docker Desktop successfully, you must:

- Meet the [general system requirements](index.md#general-system-requirements).
- Have an x86-64 system with Ubuntu 26.04 LTS or 24.04 LTS.
- For a GNOME desktop environment, you must install AppIndicator and KStatusNotifierItem [GNOME extensions](https://extensions.gnome.org/extension/615/appindicator-support/).
- If you're not using GNOME, you must install `gnome-terminal` to enable terminal access from Docker Desktop:
  ```console
  $ sudo apt install gnome-terminal
  ```

## Install Docker Desktop

Recommended approach to install Docker Desktop on Ubuntu:

1. Set up Docker's package repository.
   See step one of [Install using the `apt` repository](../../../../engine/install/ubuntu.md#install-using-the-repository).

2. Download the latest [DEB package](https://desktop.docker.com/linux/main/amd64/docker-desktop-amd64.deb?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-linux-amd64). For checksums, see the [Release notes](../../../release-notes.md).

3. Install the package using `apt`:

   ```console
   $ sudo apt-get update
   $ sudo apt install ./docker-desktop-amd64.deb
   ```

   > [!NOTE]
   >
   > At the end of the installation process, `apt` displays an error due to installing a downloaded package. You
   > can ignore this error message.
   >
   > ```text
   > N: Download is performed unsandboxed as root, as file '/home/user/Downloads/docker-desktop.deb' couldn't be accessed by user '_apt'. - pkgAcquire::Run (13: Permission denied)
   > ```

   By default, Docker Desktop is installed at `/opt/docker-desktop`.

The DEB package includes a post-install script that completes additional setup steps automatically.

The post-install script:

- Sets the capability on the Docker Desktop binary to map privileged ports and set resource limits.
- Adds a DNS name for Kubernetes to `/etc/hosts`.
- Creates a symlink from `/usr/local/bin/com.docker.cli` to `/usr/bin/docker`.
  This is because the classic Docker CLI is installed at `/usr/bin/docker`. The Docker Desktop installer also installs a Docker CLI binary that includes cloud-integration capabilities and is essentially a wrapper for the Compose CLI, at `/usr/local/bin/com.docker.cli`. The symlink ensures that the wrapper can access the classic Docker CLI.

## Launch Docker Desktop

{{% include "desktop-linux-launch.md" %}}

## Upgrade Docker Desktop

When a new version for Docker Desktop is released, the Docker UI shows a notification.
You need to download the new package each time you want to upgrade Docker Desktop and run:

```console
$ sudo apt install ./docker-desktop-amd64.deb
```

## Next steps

- Review [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopUbuntuInstall) to see what Docker can offer you.
- Follow [Get started with Docker](/get-started/tutorials/run-an-app.md) to learn how to build an image and run it as a containerized application.
- [Explore Docker Desktop](../../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, how to run and submit diagnostics, and submit issues.
- [FAQs](../../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../../settings-and-maintenance/backup-and-restore.md) provides instructions
  on backing up and restoring data related to Docker.


---

# Install Docker Desktop on Mac

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees or more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopMacInstall).

This page provides download links, system requirements, and step-by-step installation instructions for Docker Desktop on Mac.

{{< button text="Docker Desktop for Mac with Apple silicon" url="https://desktop.docker.com/mac/main/arm64/Docker.dmg?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-mac-arm64" marlin_label="download_dmg_click" >}}
{{< button text="Docker Desktop for Mac with Intel chip" url="https://desktop.docker.com/mac/main/amd64/Docker.dmg?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-mac-amd64" marlin_label="download_dmg_click" >}}

*For checksums, see [Release notes](../../release-notes.md).*

## System requirements

{{< tabs >}}
{{< tab name="Mac with Apple silicon" >}}

- A supported version of macOS.

  > [!IMPORTANT]
  >
  > Docker Desktop is supported on the current and two previous major macOS releases. As new major versions of macOS are made generally available, Docker stops supporting the oldest version and supports the newest version of macOS (in addition to the previous two releases).

- At least 4 GB of RAM.
- For the best experience, it's recommended that you install Rosetta 2. Rosetta 2 is no longer strictly required, however there are a few optional command line tools that still require Rosetta 2 when using Darwin/AMD64. See [Known issues](../../troubleshoot-and-support/troubleshoot/known-issues.md). To install Rosetta 2 manually from the command line, run the following command:

   ```console
   $ softwareupdate --install-rosetta
   ```
{{< /tab >}}
{{< tab name="Mac with Intel chip" >}}

- A supported version of macOS.

  > [!IMPORTANT]
  >
  > Docker Desktop is supported on the current and two previous major macOS releases. As new major versions of macOS are made generally available, Docker stops supporting the oldest version and supports the newest version of macOS (in addition to the previous two releases).

- At least 4 GB of RAM.

{{< /tab >}}
{{< /tabs >}}

> **Before you install or update**
>
> - Quit tools that might call Docker in the background (Visual Studio Code, terminals, agent apps).
>
> - If you manage fleets or install via MDM, use the [**PKG installer**](../../../enterprise/enterprise-deployment/pkg-install-and-configure.md).
>
> - Keep the installer volume mounted until the installation completes.
>
> If you encounter a "Docker.app is damaged" dialog, see [Fix "Docker.app is damaged" on macOS](../../troubleshoot-and-support/troubleshoot/mac-damaged-dialog.md).

## Install and run Docker Desktop on Mac

> [!TIP]
>
> See the [FAQs](../../troubleshoot-and-support/faqs/general.md#how-do-I-run-docker-desktop-without-administrator-privileges) on how to install and run Docker Desktop without needing administrator privileges.

### Install interactively

1. Download the installer using the download buttons at the top of the page, or from the [release notes](../../release-notes.md).

2. Double-click `Docker.dmg` to open the installer, then drag the Docker icon to the **Applications** folder. By default, Docker Desktop is installed at `/Applications/Docker.app`.

3. Double-click `Docker.app` in the **Applications** folder to start Docker.

4. The Docker menu displays the Docker Subscription Service Agreement.

    Here’s a summary of the key points: 
    - Docker Desktop is free for small businesses (fewer than 250 employees AND less than $10 million in annual revenue), personal use, education, and non-commercial open source projects.
    - Otherwise, it requires a paid subscription for professional use.
    - Paid subscriptions are also required for government entities.
    - Docker Pro, Team, and Business subscriptions include commercial use of Docker Desktop.

5. Select **Accept** to continue. 

   Note that Docker Desktop won't run if you do not agree to the terms. You can choose to accept the terms at a later date by opening Docker Desktop.

   For more information, see [Docker Desktop Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement). It is recommended that you also read the [FAQs](https://www.docker.com/pricing/faq).

6. From the installation window, select either: 
   - **Use recommended settings (Requires password)**. This lets Docker Desktop automatically set the necessary configuration settings. 
   - **Use advanced settings**. You can then set the location of the Docker CLI tools either in the system or user directory, and enable the default Docker socket. With version 4.88.0 and earlier, you can also enable privileged port mapping. See [Settings](../../settings-and-maintenance/settings.md#advanced), for more information and how to set the location of the Docker CLI tools.
7. Select **Finish**. If you have applied any of the previous configurations that require a password in step 6, enter your password to confirm your choice.  

### Install from the command line

After downloading `Docker.dmg` from either the download buttons at the top of the page or from the [release notes](../../release-notes.md), run the following commands in a terminal to install Docker Desktop in the **Applications** folder:

```console
$ sudo hdiutil attach Docker.dmg
$ sudo /Volumes/Docker/Docker.app/Contents/MacOS/install
$ sudo hdiutil detach /Volumes/Docker
```

By default, Docker Desktop is installed at `/Applications/Docker.app`. As macOS typically performs security checks the first time an application is used, the `install` command can take several minutes to run.

#### Installer flags

The `install` command accepts the following flags:

##### Installation behavior

- `--accept-license`: Accepts the [Docker Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement) now, rather than requiring it to be accepted when the application is first run.
- `--user=<username>`: Performs the privileged configurations once during installation. This removes the need for the user to grant root privileges on first run. For more information, see [Privileged helper permission requirements](mac-permission-requirements.md#permission-requirements). To find the username, enter `ls /Users` in the CLI.

##### Security and access

- `--allowed-org=<org name>`: Requires the user to sign in and be part of the specified Docker Hub organization when running the application
- `--user=<username>`: Performs the privileged configurations once during installation. This removes the need for the user to grant root privileges on first run. For more information, see [Privileged helper permission requirements](mac-permission-requirements.md#permission-requirements). To find the username, enter `ls /Users` in the CLI.
- `--admin-settings`: Automatically creates an `admin-settings.json` file which is used by administrators to control certain Docker Desktop settings on client machines within their organization. For more information, see [Settings Management](../../../enterprise/security/hardened-desktop/settings-management/index.md).
  - It must be used together with the `--allowed-org=<org name>` flag. 
  - For example: `--allowed-org=<org name> --admin-settings="{'configurationFileVersion': 2, 'enhancedContainerIsolation': {'value': true, 'locked': false}}"`

##### Proxy configuration

- `--proxy-http-mode=<mode>`: Sets the HTTP Proxy mode. The two modes are `system` (default) or `manual`.
- `--override-proxy-http=<URL>`: Sets the URL of the HTTP proxy that must be used for outgoing HTTP requests. It requires `--proxy-http-mode` to be `manual`.
- `--override-proxy-https=<URL>`: Sets the URL of the HTTP proxy that must be used for outgoing HTTPS requests, requires `--proxy-http-mode` to be `manual`
- `--override-proxy-exclude=<hosts/domains>`: Bypasses proxy settings for the hosts and domains. It's a comma-separated list.
- `--override-proxy-pac=<PAC file URL>`: Sets the PAC file URL. This setting takes effect only when using `manual` proxy mode.
- `--override-proxy-embedded-pac=<PAC script>`: Specifies an embedded PAC (Proxy Auto-Config) script. This setting takes effect only when using `manual` proxy mode and has precedence over the `--override-proxy-pac` flag.

###### Example of specifying PAC file

```console
$ sudo /Applications/Docker.app/Contents/MacOS/install --user testuser --proxy-http-mode="manual" --override-proxy-pac="http://localhost:8080/myproxy.pac"
```

###### Example of specifying PAC script

```console
$ sudo /Applications/Docker.app/Contents/MacOS/install --user testuser --proxy-http-mode="manual" --override-proxy-embedded-pac="function FindProxyForURL(url, host) { return \"DIRECT\"; }"
```

> [!TIP]
>
> As an IT administrator, you can use endpoint management (MDM) software to identify the number of Docker Desktop instances and their versions within your environment. This can provide accurate license reporting, help ensure your machines use the latest version of Docker Desktop, and enable you to [enforce sign-in](../../../enterprise/security/enforce-sign-in/index.md).
> - [Intune](https://learn.microsoft.com/en-us/mem/intune/apps/app-discovered-apps)
> - [Jamf](https://docs.jamf.com/10.25.0/jamf-pro/administrator-guide/Application_Usage.html)
> - [Kandji](https://support.kandji.io/support/solutions/articles/72000559793-view-a-device-application-list)
> - [Kolide](https://www.kolide.com/features/device-inventory/properties/mac-apps)
> - [Workspace One](https://blogs.vmware.com/euc/2022/11/how-to-use-workspace-one-intelligence-to-manage-app-licenses-and-reduce-costs.html)

## Where to go next

- Explore [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopMacInstall) to see what Docker can offer you.
- [Build and share a containerized application](/get-started/tutorials/run-an-app.md).
- [Explore Docker Desktop](../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, how
  to run and submit diagnostics, and submit issues.
- [FAQs](../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../settings-and-maintenance/backup-and-restore.md) provides instructions
  on backing up and restoring data related to Docker.


---

# Understand permission requirements for Docker Desktop on Mac

*Sección: Desktop*

This page contains information about the permission requirements for running and installing Docker Desktop on Mac.

It also provides clarity on running containers as `root` as opposed to having `root` access on the host.

Docker Desktop on Mac is designed with security in mind. Administrative rights are only required when absolutely necessary.

## Permission requirements

Docker Desktop for Mac is run as an unprivileged user. However, Docker Desktop requires certain functionalities to perform a limited set of privileged configurations such as:
 - [Installing symlinks](#installing-symlinks) in`/usr/local/bin`.
 - [Ensuring `localhost` and `kubernetes.docker.internal` are defined](#ensuring-localhost-and-kubernetesdockerinternal-are-defined) in `/etc/hosts`. Some old macOS installs don't have `localhost` in `/etc/hosts`, which causes Docker to fail. Defining the DNS name `kubernetes.docker.internal` allows Docker to share Kubernetes contexts with containers.
  - [Binding privileged ports](#binding-privileged-ports) that are less than 1024. Although privileged ports (ports below 1024) are not typically used as a security boundary, operating systems still prevent unprivileged processes from binding to them which breaks commands like `docker run -p 127.0.0.1:80:80 docker/getting-started`. (Applies to version 4.88 and earlier).
  - Securely caching the Registry Access Management policy which is read-only for the developer. (Applies to version 4.88 and earlier).

Privileged access, when needed, is granted through the **Advanced** page in **Settings**. With version 4.88 and earlier, this is granted during installation.

From the **Advanced** page, you can enable:
- The location of the Docker CLI tools either in the system or user directory
- The default Docker socket

If you work in an environment with elevated security requirements, for instance where local administrative access is prohibited, then you can leave these settings at their defaults to avoid granting privileged access.

Depending on which advanced settings you configure, you must enter your password to confirm.

### Installing symlinks

The Docker binaries are installed by default in `/Applications/Docker.app/Contents/Resources/bin`. By default, Docker Desktop creates symlinks for the binaries in `$HOME/.docker/bin`, which is automatically added to your terminal's `PATH`.

You can change the symlink location to `/usr/local/bin` from the **Advanced** page in **Settings**. If `/usr/local/bin` is not writable by unprivileged users, Docker Desktop requires authorization to confirm this choice before the symlinks to Docker binaries are created there.

You are also given the option to enable the installation of the `/var/run/docker.sock` symlink from the **Advanced** page in **Settings**. Creating this symlink ensures various Docker clients relying on the default Docker socket path work without additional changes.

As the `/var/run` is mounted as a tmpfs, its content is deleted on restart, symlink to the Docker socket included. To ensure the Docker socket exists after restart, Docker Desktop sets up a `launchd` startup task that creates the symlink by running `ln -s -f /Users/<user>/.docker/run/docker.sock /var/run/docker.sock`. This ensures the you aren't prompted on each startup to create the symlink. If you don't enable this option, the symlink and the startup task is not created and you may have to explicitly set the `DOCKER_HOST` environment variable to `/Users/<user>/.docker/run/docker.sock` in the clients it is using. The Docker CLI relies on the current context to retrieve the socket path, the current context is set to `desktop-linux` on Docker Desktop startup.

### Ensuring `localhost` and `kubernetes.docker.internal` are defined

It is your responsibility to ensure that localhost is resolved to `127.0.0.1` and if Kubernetes is used, that `kubernetes.docker.internal` is resolved to `127.0.0.1`.

### Binding privileged ports

You can choose to enable privileged port mapping during installation (version 4.88.0 and earlier), or from the **Advanced** page in **Settings** post-installation. Docker Desktop requires authorization to confirm this choice.

## Installing from the command line

Privileged configurations are applied during the installation with the `--user` flag on the [install command](mac-install.md#install-from-the-command-line). In this case, you are not prompted to grant root privileges on the first run of Docker Desktop. Specifically, the `--user` flag:
- Uninstalls the previous `com.docker.vmnetd` if present
- Sets up symlinks
- Ensures that `localhost` is resolved to `127.0.0.1`

The limitation of this approach is that Docker Desktop can only be run by one user-account per machine, namely the one specified in the `-–user` flag.

## Privileged helper (version 4.88 and earlier)

In the limited situations when the privileged helper is needed, for example binding privileged ports or caching the Registry Access Management policy, the privileged helper is started by `launchd` and runs in the background unless it is disabled at runtime as previously described. The Docker Desktop backend communicates with the privileged helper over the Unix domain socket `/var/run/com.docker.vmnetd.sock`. The functionalities it performs are:
- Binding privileged ports that are less than 1024.
- Securely caching the Registry Access Management policy which is read-only for the developer.
- Uninstalling the privileged helper.

The removal of the privileged helper process is done in the same way as removing `launchd` processes.

```console
$ ps aux | grep vmnetd
root             28739   0.0  0.0 34859128    228   ??  Ss    6:03PM   0:00.06 /Library/PrivilegedHelperTools/com.docker.vmnetd
user             32222   0.0  0.0 34122828    808 s000  R+   12:55PM   0:00.00 grep vmnetd

$ sudo launchctl unload -w /Library/LaunchDaemons/com.docker.vmnetd.plist
Password:

$ ps aux | grep vmnetd
user             32242   0.0  0.0 34122828    716 s000  R+   12:55PM   0:00.00 grep vmnetd

$ rm /Library/LaunchDaemons/com.docker.vmnetd.plist

$ rm /Library/PrivilegedHelperTools/com.docker.vmnetd
```

## Backend helper socket

The Docker Desktop backend process (`com.docker.backend`) uses an internal helper socket
(`~/Library/Containers/com.docker.docker/Data/forkexecd.sock`) to fork and execute
helper processes as part of running Docker Desktop.

This socket does not run as `root` and grants no elevated privileges. It is owned by,
and accessible only to, the same macOS user running Docker Desktop, and is contained
in Docker Desktop's application container.

## Containers running as root within the Linux VM

With Docker Desktop, the Docker daemon and containers run in a lightweight Linux
VM managed by Docker. This means that although containers run by default as
`root`, this doesn't grant `root` access to the Mac host machine. The Linux VM
serves as a security boundary and limits what resources can be accessed from the
host. Any directories from the host bind mounted into Docker containers still
retain their original permissions.

## Enhanced Container Isolation

In addition, Docker Desktop supports [Enhanced Container Isolation
mode](../../../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md) (ECI),
available to Business customers only, which further secures containers without
impacting developer workflows.

ECI automatically runs all containers within a Linux user-namespace, such that
root in the container is mapped to an unprivileged user inside the Docker
Desktop VM. ECI uses this and other advanced techniques to further secure
containers within the Docker Desktop Linux VM, such that they are further
isolated from the Docker daemon and other services running inside the VM.


---

# Install Docker Desktop on Windows

*Sección: Desktop*

> **Docker Desktop terms**
>
> Commercial use of Docker Desktop in larger enterprises (more than 250
> employees OR more than $10 million USD in annual revenue) requires a [paid
> subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopWindowsInstall).

This page provides download links, system requirements, and step-by-step installation instructions for Docker Desktop on Windows.

{{< button text="Docker Desktop for Windows - x86_64" url="https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-win-amd64" marlin_label="download_exe_click" >}}
{{< button text="Docker Desktop for Windows - x86_64 on the Microsoft Store" url="https://apps.microsoft.com/detail/xp8cbj40xlbwkx?hl=en-GB&gl=GB" >}}
{{< button text="Docker Desktop for Windows - Arm (Early Access)" url="https://desktop.docker.com/win/main/arm64/Docker%20Desktop%20Installer.exe?utm_source=docker&utm_medium=webreferral&utm_campaign=docs-driven-download-win-arm64" marlin_label="download_exe_click" >}}

_For checksums, see [Release notes](../../release-notes.md)_

## Installation modes
 
Docker Desktop supports two installation modes. Per-user installation is recommended for most users and is selected by default in the installer. It does not require administrator privileges to install or update, and the WSL 2 backend it uses covers the needs of the vast majority of Docker Desktop users.
 
| | Per-user (recommended) | All users |
|---|---|---|
| Install location | `%LOCALAPPDATA%\Programs\DockerDesktop` | `C:\Program Files\Docker\Docker` |
| Registry keys | Current User (HKCU) | Local Machine (HKLM) |
| Admin rights to install | Not required | Required |
| Admin rights to update | Not required | Required |
| Linux containers backend | WSL 2 or Docker VMM | WSL 2, Hyper-V, or Docker VMM |
| Windows containers | Not supported | Supported |
| Security | Smaller attack surface; no privileged system service installed | Requires privileged system service; broader access to host resources |

For more information, see [Understand permission requirements for Windows](windows-permission-requirements.md).

## System requirements

> [!TIP]
>
> **Which backend should I use?**
>
> Docker Desktop for Windows supports three backends: WSL 2, Hyper-V, and Docker VMM (Beta). WSL 2 is the default and works for most users without administrator privileges. Hyper-V is only available with all-users installation. Docker VMM is a container-optimized hypervisor that reclaims idle memory and improves file I/O. For more information, see [Virtual Machine Manager](../../features/vmm.md).

{{< tabs >}}
{{< tab name="WSL 2 backend, x86_64" >}}

- WSL version 2.1.5 or later. To check your version, see [WSL: Verification and setup](#wsl-verification-and-setup)
- If you intend to use Enhanced Container Isolation, ensure you’re using WSL version 2.6 or later. This is required because ECI depends on a Linux kernel version of at least 6.3.0, and WSL 2.6+ bundles Linux kernel version 6.6.
- Windows 10 64-bit: Enterprise, Pro, or Education version 22H2 (build 19045).
- Windows 11 64-bit: Enterprise, Pro, or Education version 23H2 (build 22631) or higher.
- The Windows Server service (LanmanServer) must be enabled and its start mode set to **Automatic**.
- Turn on the WSL 2 feature on Windows. For detailed instructions, refer to the
  [Microsoft documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
- The following hardware prerequisites are required to successfully run
  WSL 2 on Windows 10 or Windows 11:
  - 64-bit processor with [Second Level Address Translation (SLAT)](https://en.wikipedia.org/wiki/Second_Level_Address_Translation)
  - 8GB system RAM
  - Enable hardware virtualization in BIOS/UEFI. For more information, see
    [Virtualization](../../troubleshoot-and-support/troubleshoot/topics.md#docker-desktop-fails-due-to-virtualization-not-working).

For more information on setting up WSL 2 with Docker Desktop, see [WSL](../../features/wsl/index.md).

> [!NOTE]
>
> Docker only supports Docker Desktop on Windows for those versions of Windows that are still within [Microsoft’s servicing timeline](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). Docker Desktop is not supported on server versions of Windows, such as Windows Server 2019 or Windows Server 2022. For more information on how to run containers on Windows Server, see [Microsoft's official documentation](https://learn.microsoft.com/virtualization/windowscontainers/quick-start/set-up-environment).

> [!IMPORTANT]
>
> To run [Windows containers](#windows-containers), you need Windows 10 or Windows 11 Professional or Enterprise edition.
> Windows Home or Education editions only allow you to run Linux containers.

{{< /tab >}}
{{< tab name="Hyper-V backend, x86_64" >}}

- Windows 10 64-bit: Enterprise, Pro, or Education version 22H2 (build 19045).
- Windows 11 64-bit: Enterprise, Pro, or Education version 23H2 (build 22631) or higher.
- The Windows Server service (LanmanServer) must be enabled and its start mode set to **Automatic**.
- Turn on Hyper-V and Containers Windows features.
- The following hardware prerequisites are required to successfully run Client
  Hyper-V on Windows 10:

  - 64 bit processor with [Second Level Address Translation (SLAT)](https://en.wikipedia.org/wiki/Second_Level_Address_Translation)
  - 8GB system RAM
  - Turn on BIOS/UEFI-level hardware virtualization support in the
    BIOS/UEFI settings. For more information, see
    [Virtualization](../../troubleshoot-and-support/troubleshoot/topics.md#virtualization).

> [!NOTE]
>
> Docker only supports Docker Desktop on Windows for those versions of Windows that are still within [Microsoft’s servicing timeline](https://support.microsoft.com/en-us/help/13853/windows-lifecycle-fact-sheet). Docker Desktop is not supported on server versions of Windows, such as Windows Server 2019 or Windows Server 2022. For more information on how to run containers on Windows Server, see [Microsoft's official documentation](https://learn.microsoft.com/virtualization/windowscontainers/quick-start/set-up-environment).

> [!IMPORTANT]
>
> To run [Windows containers](#windows-containers), you need Windows 10 or Windows 11 Professional or Enterprise edition.
> Windows Home or Education editions only allow you to run Linux containers.

{{< /tab >}}
{{< tab name="WSL 2 backend, Arm (Early Access)" >}}

- WSL version 2.1.5 or later. To check your version, see [WSL: Verification and setup](#wsl-verification-and-setup)
- Windows 10 64-bit: Enterprise, Pro, or Education version 22H2 (build 19045).
- Windows 11 64-bit: Enterprise, Pro, or Education version 23H2 (build 22631) or higher.
- The Windows Server service (LanmanServer) must be enabled and its start mode set to **Automatic**.
- Turn on the WSL 2 feature on Windows. For detailed instructions, refer to the
  [Microsoft documentation](https://docs.microsoft.com/en-us/windows/wsl/install-win10).
- The following hardware prerequisites are required to successfully run
  WSL 2 on Windows 10 or Windows 11:
  - 64-bit processor with [Second Level Address Translation (SLAT)](https://en.wikipedia.org/wiki/Second_Level_Address_Translation)
  - 8GB system RAM
  - Enable hardware virtualization in BIOS/UEFI. For more information, see
    [Virtualization](../../troubleshoot-and-support/troubleshoot/topics.md#virtualization).

> [!IMPORTANT]
>
> Windows containers are not supported.

{{< /tab >}}
{{< /tabs >}}

Containers and images created with Docker Desktop are shared between all
user accounts on machines where it is installed. This is because all Windows
accounts use the same VM to build and run containers. Note that it is not possible to share containers and images between user accounts when using the Docker Desktop WSL 2 backend.

Running Docker Desktop inside a VMware ESXi or Azure VM is supported for Docker Business customers.
It requires enabling nested virtualization on the hypervisor first.
For more information, see [Running Docker Desktop in a VM or VDI environment](../vm-vdi.md).

## Install Docker Desktop on Windows

### Install interactively

1. Download the installer using the download button at the top of the page, or from the [release notes](../../release-notes.md).

2. Double-click `Docker Desktop Installer.exe` to run the installer. The installer will ask which installation mode you prefer. Choosing per-user installs to `%LOCALAPPDATA%\Programs\DockerDesktop` and requires no administrator privileges. Choosing all users will prompt for elevation.

   > [!NOTE]
   >
   >If you want to switch installation mode at a later date, you need to uninstall and reinstall Docker Desktop.

3. When prompted, select your backend on the Configuration page: **Use WSL 2 instead of Hyper-V** for WSL 2, or leave it unselected for Hyper-V. You can switch to Docker VMM after installation from **Settings** > **General**.

    On systems that support only one backend, Docker Desktop automatically selects the available option.

4. Follow the instructions on the installation wizard to authorize the installer and proceed with the installation.

5. When the installation is successful, select **Close** to complete the installation process.

6. [Start Docker Desktop](#start-docker-desktop).

### Install from the command line

After downloading `Docker Desktop Installer.exe`, run the following command in a terminal to install Docker Desktop to `%LOCALAPPDATA%\Programs\DockerDesktop`.

For per-user installation, run:

```console
$ "Docker Desktop Installer.exe" install --user
```

To install for all users on the machine (requires administrator privileges):
 
```console
$ "Docker Desktop Installer.exe" install
```

If you're using PowerShell you should run it as:
 
```powershell
# Per-user installation (no admin required)
Start-Process 'Docker Desktop Installer.exe' -Wait -ArgumentList 'install', '--user'
 
# All-users installation (run as administrator)
Start-Process 'Docker Desktop Installer.exe' -Wait install
```

If using the Windows Command Prompt:
 
```sh
# Per-user installation (no admin required)
start /w "" "Docker Desktop Installer.exe" install --user
 
# All-users installation (run as administrator)
start /w "" "Docker Desktop Installer.exe" install
```

If using all-users installation and your administrator account is different to your user account, you must add the user to the **docker-users** group to access features that require higher privileges, such as creating and managing the Hyper-V VM, or using Windows containers:

```console
$ net localgroup docker-users <user> /add
```

> [!WARNING]
>
> Membership in `docker-users` grants access to the Docker daemon socket, which is equivalent to granting administrative privileges on the host. Only add users who require access to Windows containers or Hyper-V VM management. For Linux containers using the WSL 2 backend, this group membership is not required. See [Protect the Docker daemon socket](../../../engine/security/protect-access.md) for more information.

If you're deploying via MDM (such as Intune) and the `docker-users` group isn't populated automatically, see [Why isn't the `docker-users` group populated when the MSI is installed with Intune or another MDM solution?](../../../enterprise/enterprise-deployment/faq.md#why-isnt-the-docker-users-group-populated-when-the-msi-is-installed-with-intune-or-another-mdm-solution).

See the [Installer flags](#installer-flags) section to see what flags the `install` command accepts.

> [!NOTE]
>
>If you want to switch installation mode at a later date, you need to uninstall and reinstall Docker Desktop.

## Start Docker Desktop

Docker Desktop does not start automatically after installation. To start Docker Desktop:

1. Search for Docker, and select **Docker Desktop** in the search results.

2. The Docker menu ({{< inline-image src="images/whale-x.svg" alt="whale menu" >}}) displays the Docker Subscription Service Agreement.

   {{% include "desktop-license-update.md" %}}

3. Select **Accept** to continue. Docker Desktop starts after you accept the terms.

   Note that Docker Desktop won't run if you do not agree to the terms. You can choose to accept the terms at a later date by opening Docker Desktop.

   For more information, see [Docker Desktop Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement/). It is recommended that you read the [FAQs](https://www.docker.com/pricing/faq).

> [!TIP]
>
> As an IT administrator, you can use endpoint management (MDM) software to identify the number of Docker Desktop instances and their versions within your environment. This can provide accurate license reporting, help ensure your machines use the latest version of Docker Desktop, and enable you to [enforce sign-in](../../../enterprise/security/enforce-sign-in/index.md).
> - [Intune](https://learn.microsoft.com/en-us/mem/intune/apps/app-discovered-apps)
> - [Jamf](https://docs.jamf.com/10.25.0/jamf-pro/administrator-guide/Application_Usage.html)
> - [Kandji](https://support.kandji.io/support/solutions/articles/72000559793-view-a-device-application-list)
> - [Kolide](https://www.kolide.com/features/device-inventory/properties/mac-apps)
> - [Workspace One](https://blogs.vmware.com/euc/2022/11/how-to-use-workspace-one-intelligence-to-manage-app-licenses-and-reduce-costs.html)


## Advanced system configuration and installation options

### WSL: Verification and setup

If you have chosen to use WSL, first verify that your installed version meets system requirements by running the following command in your terminal:

```console
wsl --version
```

If version details do not appear, you are likely using the inbox version of WSL. This version does not support modern capabilities and must be updated.

You can update or install WSL using one of the following methods:

#### Option 1: Install or update WSL via the terminal

1. Open PowerShell or Windows Command Prompt in administrator mode.
2. Run either the install or update command. You may be prompted to restart your machine. For more information, refer to [Install WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
```console
wsl --install

wsl --update
```

#### Option 2: Install WSL via the MSI package

If Microsoft Store access is blocked due to security policies:
1. Go to the official [WSL GitHub Releases page](https://github.com/microsoft/WSL/releases).
2. Download the `.msi` installer from the latest stable release (under the Assets drop-down).
3. Run the downloaded installer and follow the setup instructions.

### Installer flags

> [!NOTE]
>
> If you're using PowerShell, you need to use the `ArgumentList` parameter before any flags. 
> For example:
> ```powershell
> Start-Process 'Docker Desktop Installer.exe' -Wait -ArgumentList 'install', '--accept-license'
> ```

#### Installation behavior


- `--user`: Installs Docker Desktop in per-user mode, to `%LOCALAPPDATA%\Programs\DockerDesktop`. No administrator privileges are required. This is the recommended mode for most users. See [Installation modes](#installation-modes).
- `--quiet`: Suppresses information output when running the installer 
- `--accept-license`: Accepts the [Docker Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement) now, rather than requiring it to be accepted when the application is first run
- `--installation-dir=<path>`: Changes the default installation location (`C:\Program Files\Docker\Docker`)
- `--backend=<backend name>`: Selects the default backend to use for Docker Desktop, `hyper-v`, `windows` or `wsl-2` (default)
- `--always-run-service`: After installation completes, starts `com.docker.service` and sets the service startup type to Automatic. This circumvents the need for administrator privileges, which are otherwise necessary to start `com.docker.service`. `com.docker.service` is required by Windows containers and Hyper-V backend.

#### Security and access control

- `--allowed-org=<org name>`: Requires the user to sign in and be part of the specified Docker Hub organization when running the application
- `--admin-settings`: Automatically creates an `admin-settings.json` file which is used by admins to control certain Docker Desktop settings on client machines within their organization. For more information, see [Settings Management](../../../enterprise/security/hardened-desktop/settings-management/index.md).
  - It must be used together with the `--allowed-org=<org name>` flag. 
  - For example:`--allowed-org=<org name> --admin-settings="{'configurationFileVersion': 2, 'enhancedContainerIsolation': {'value': true, 'locked': false}}"`
- `--no-windows-containers`: Disables the Windows containers integration. This can improve security. For more information, see [Windows containers](windows-permission-requirements.md#windows-containers).

#### Proxy configuration

- `--proxy-http-mode=<mode>`: Sets the HTTP Proxy mode, `system` (default) or `manual`
- `--override-proxy-http=<URL>`: Sets the URL of the HTTP proxy that must be used for outgoing HTTP requests, requires `--proxy-http-mode` to be `manual`
- `--override-proxy-https=<URL>`: Sets the URL of the HTTP proxy that must be used for outgoing HTTPS requests, requires `--proxy-http-mode` to be `manual`
- `--override-proxy-exclude=<hosts/domains>`: Bypasses proxy settings for the hosts and domains. Uses a comma-separated list.
- `--proxy-enable-kerberosntlm`: Enables Kerberos and NTLM proxy authentication. If you are enabling this, ensure your proxy server is properly configured for Kerberos/NTLM authentication. Available with Docker Desktop 4.32 and later.
- `--override-proxy-pac=<PAC file URL>`: Sets the PAC file URL. This setting takes effect only when using `manual` proxy mode.
- `--override-proxy-embedded-pac=<PAC script>`: Specifies an embedded PAC (Proxy Auto-Config) script. This setting takes effect only when using `manual` proxy mode and has precedence over the `--override-proxy-pac` flag.

##### Example of specifying PAC file

```console
"Docker Desktop Installer.exe" install --proxy-http-mode="manual" --override-proxy-pac="http://localhost:8080/myproxy.pac"
```

##### Example of specifying PAC script

```console
"Docker Desktop Installer.exe" install --proxy-http-mode="manual" --override-proxy-embedded-pac="function FindProxyForURL(url, host) { return \"DIRECT\"; }"
```

#### Data root and disk location

- `--hyper-v-default-data-root=<path>`: Specifies the default location for the Hyper-V VM disk. 
- `--windows-containers-default-data-root=<path>`: Specifies the default location for the Windows containers.
- `--wsl-default-data-root=<path>`: Specifies the default location for the WSL distribution disk.

### Administrator privileges

In per-user mode, Docker Desktop can be installed and updated without administrator privileges. Some settings still require elevation and are marked **Requires password** in the Settings UI. Enabling WSL 2 for the first time also requires administrator privileges, but this is a one-time, per-machine operation.

In all-users mode, installing Docker Desktop requires administrator privileges. However, once installed, it can be used without administrative access. Some actions, though, still need elevated permissions. See [Understand permission requirements for Windows](windows-permission-requirements.md) for more detail.

See the [FAQs](../../troubleshoot-and-support/faqs/general.md#how-do-i-run-docker-desktop-without-administrator-privileges) on how to install and run Docker Desktop without needing administrator privileges.

If you're an IT admin and your users do not have administrator rights and plan to perform operations that require elevated privileges, be sure to install Docker Desktop using the `--always-run-service` installer flag. This ensures those actions can still be executed without prompting for User Account Control (UAC) elevation. See [Installer Flags](#installer-flags) for more detail.

### Windows containers

> [!NOTE]
>
> Windows containers are only supported in all-users installation mode. They are not available when Docker Desktop is installed per-user.

From the Docker Desktop menu, you can toggle which daemon (Linux or Windows)
the Docker CLI talks to. Select **Switch to Windows containers** to use Windows
containers, or select **Switch to Linux containers** to use Linux containers
(the default).

For more information on Windows containers, refer to the following documentation:

- Microsoft documentation on [Windows containers](https://docs.microsoft.com/en-us/virtualization/windowscontainers/about/index).

- [Build and Run Your First Windows Server Container (Blog Post)](https://www.docker.com/blog/build-your-first-docker-windows-server-container/)
  gives a quick tour of how to build and run native Docker Windows containers on Windows 10 and Windows Server 2016 evaluation releases.

- [Getting Started with Windows Containers (Lab)](https://github.com/docker/labs/blob/master/windows/windows-containers/README.md)
  shows you how to use the [MusicStore](https://github.com/aspnet/MusicStore/)
  application with Windows containers. The MusicStore is a standard .NET application and,
  [forked here to use containers](https://github.com/friism/MusicStore), is a good example of a multi-container application.

- To understand how to connect to Windows containers from the local host, see
  [I want to connect to a container from Windows](/manuals/desktop/features/networking.md#i-want-to-connect-to-a-container-from-the-host)

> [!NOTE]
>
> When you switch to Windows containers, **Settings** only shows those tabs that are active and apply to your Windows containers.

If you set proxies or daemon configuration in Windows containers mode, these
apply only on Windows containers. If you switch back to Linux containers,
proxies and daemon configurations return to what you had set for Linux
containers. Your Windows container settings are retained and become available
again when you switch back.

## Where to go next

- Explore [Docker's subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopWindowsInstall) to see what Docker can offer you.
- [Build and share a containerized application](/get-started/tutorials/run-an-app.md).
- [Explore Docker Desktop](../../use-desktop/index.md) and all its features.
- [Troubleshooting](../../troubleshoot-and-support/troubleshoot/index.md) describes common problems, workarounds, and
  how to get support.
- [FAQs](../../troubleshoot-and-support/faqs/general.md) provide answers to frequently asked questions.
- [Release notes](../../release-notes.md) lists component updates, new features, and improvements associated with Docker Desktop releases.
- [Back up and restore data](../../settings-and-maintenance/backup-and-restore.md) provides instructions on backing up and restoring data related to Docker.


---

# Understand permission requirements for Windows

*Sección: Desktop*

This page contains information about the permission requirements for running and installing Docker Desktop on Windows, the functionality of the privileged helper process `com.docker.service`, and the reasoning behind this approach.

It also provides clarity on running containers as `root` as opposed to having `Administrator` access on the host and the privileges of Docker Engine and Windows containers.

Docker Desktop on Windows is designed with security in mind. Administrative rights are only required when absolutely necessary.

## Permission requirements

The permissions required to install and run Docker Desktop depend on which [installation mode](windows-install.md#installation-modes) you use.
 
### Per-user installation
 
In per-user mode, Docker Desktop installs to `%LOCALAPPDATA%\Programs\DockerDesktop` and writes only to current-user registry keys (`HKCU`). This means:
 
- No administrator privileges are required to install or update Docker Desktop.
- After installation, Docker Desktop can be run without administrator privileges.
- Some settings marked **Requires password** in **Settings** still require elevation. When you change one of these settings and select **Apply**, Docker Desktop opens a UAC prompt for administrator access.
 
Per-user installation does not install the privileged helper service `com.docker.service` automatically. As a result, features that depend on it, such as the Hyper-V backend and Windows containers, are not available. Docker VMM (Beta) is available in per-user mode and does not require the privileged helper. For most users, the WSL 2 or Docker VMM backend covers the majority of use cases.
 
### All-users installation
 
In all-users mode, Docker Desktop installs to `C:\Program Files\Docker\Docker` and writes to Local Machine registry keys (`HKLM`). Both locations require administrator privileges to modify, so:
 
- Administrator privileges are required to install and update Docker Desktop.
- On installation you receive a UAC prompt which allows the privileged helper service `com.docker.service` to be installed.
- After installation, Docker Desktop can be run without administrator privileges.
 
Running Docker Desktop without the privileged helper does not require users to have `docker-users` group membership. However, some features that require privileged operations will have this requirement.
 
If you performed the installation, you are automatically added to the `docker-users` group, but other users must be added manually. This allows the administrator to control who has access to features that require higher privileges, such as creating and managing the Hyper-V VM, or using Windows containers.
 
When Docker Desktop launches, all non-privileged named pipes are created so that only the following users can access them:
- The user that launched Docker Desktop.
- Members of the local `Administrators` group.
- The `LOCALSYSTEM` account.
 
### Operations that always require elevation
 
The following require administrator privileges regardless of installation mode.
 
- Enabling WSL 2 for the first time: WSL 2 must be enabled on the machine before Docker Desktop can run. This is a one-time, per-machine operation. Once WSL 2 is enabled, it does not need to be enabled again for subsequent Docker Desktop installs or updates.
- Settings marked **Requires password**: Certain Docker Desktop settings affect system-level configuration and require administrator credentials to apply. These are clearly marked **Requires password**. When you change one of these settings and select **Apply**, Docker Desktop prompts for administrator credentials.

## Privileged helper

Docker Desktop needs to perform a limited set of privileged operations which are conducted by the privileged helper process `com.docker.service`. This approach allows, following the principle of least privilege, `Administrator` access to be used only for the operations for which it is absolutely necessary, while still being able to use Docker Desktop as an unprivileged user.

> [!NOTE]
>
> `com.docker.service` is only installed in all-users installation mode. It is not used in per-user installation, which relies on the WSL 2 or Docker VMM backend and does not support Hyper-V or Windows containers.

The privileged helper `com.docker.service` is a Windows service which runs in the background with `SYSTEM` privileges. It listens on the named pipe `//./pipe/dockerBackendV2`. The developer runs the Docker Desktop application, which connects to the named pipe and sends commands to the service. This named pipe is protected, and only users that are part of the `docker-users` group can have access to it.

The service performs the following functionalities:
- Ensuring that `kubernetes.docker.internal` is defined in the Win32 hosts file. Defining the DNS name `kubernetes.docker.internal` allows Docker to share Kubernetes contexts with containers.
- Ensuring that `host.docker.internal` and `gateway.docker.internal` are defined in the Win32 hosts file. They point to the host local IP address and allow an application to resolve the host IP using the same name from either the host itself or a container.
- Creating the Hyper-V VM `"DockerDesktopVM"` and managing its lifecycle - starting, stopping, and destroying it. The VM name is hard coded in the service code so the service cannot be used for creating or manipulating any other VMs.
- Moving the VHDX file or folder.
- Starting and stopping Windows Docker Engine and querying whether it's running.
- Deleting all Windows containers data files.
- Checking if Hyper-V is enabled.
- Checking if the bootloader activates Hyper-V.
- Checking if required Windows features are both installed and enabled.
- Conducting healthchecks and retrieving the version of the service itself.
- Securely caching the Registry Access Management policy which is read-only for the developer. (Applies to version 4.88.0 and earlier)

The service start mode depends on which container engine is selected, and, for WSL, on whether it is needed to maintain `host.docker.internal` and `gateway.docker.internal` in the Win32 hosts file. This is controlled by a setting under `Use the WSL 2 based engine` in the settings page. When this is set, WSL engine behaves the same as Hyper-V. So:
- With Windows containers, or Hyper-v Linux containers, the service is started when the system boots and runs all the time, even when Docker Desktop isn't running. This is required so you can launch Docker Desktop without admin privileges.
- With WSL2 Linux containers, the service isn't necessary and therefore doesn't run automatically when the system boots. When you switch to Windows containers or Hyper-V Linux containers, or choose to maintain `host.docker.internal` and `gateway.docker.internal` in the Win32 hosts file, a UAC prompt appears asking you to accept the privileged operation to start the service. If accepted, the service is started and set to start automatically upon the next Windows boot.

## Containers running as root within the Linux VM

The Linux Docker daemon and containers run in a minimal, special-purpose Linux
VM managed by Docker. It is immutable so you can’t extend it or change the
installed software.  This means that although containers run by default as
`root`, this doesn't allow altering the VM and doesn't grant `Administrator`
access to the Windows host machine. The Linux VM serves as a security boundary
and limits what resources from the host can be accessed. File sharing uses a
user-space crafted file server and any directories from the host bind mounted
into Docker containers still retain their original permissions.  Containers don't have access to any host files beyond those explicitly shared.

## Enhanced Container Isolation

In addition, Docker Desktop supports [Enhanced Container Isolation
mode](../../../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md) (ECI),
available to Business customers only, which further secures containers without
impacting developer workflows.

ECI automatically runs all containers within a Linux user-namespace, such that
root in the container is mapped to an unprivileged user inside the Docker
Desktop VM. ECI uses this and other advanced techniques to further secure
containers within the Docker Desktop Linux VM, such that they are further
isolated from the Docker daemon and other services running inside the VM.

## Windows containers

> [!WARNING]
>
> Enabling Windows containers has important security implications.

> [!NOTE]
>
> Windows containers are only supported in all-users installation mode. They are not available when Docker Desktop is installed per-user. See [Installation modes](windows-install.md#installation-modes).

Unlike the Linux Docker Engine and containers which run in a VM, Windows containers are implemented using operating system features, and run directly on the Windows host. If you enable Windows containers during installation, the `ContainerAdministrator` user used for administration inside the container is a local administrator on the host machine. Enabling Windows containers during installation makes it so that members of the `docker-users` group are able to elevate to administrators on the host. For organizations who don't want their developers to run Windows containers, a `-–no-windows-containers` installer flag is available to disable their use.

## Networking

For network connectivity, Docker Desktop uses a user-space process (`vpnkit`), which inherits constraints like firewall rules, VPN, HTTP proxy properties etc. from the user that launched it.


---

# Sign in to Docker Desktop

*Sección: Desktop*

Docker recommends signing in with the **Sign in** option in the top-right corner of the Docker Dashboard. 

In large enterprises where admin access is restricted, administrators can [enforce sign-in](../../enterprise/security/enforce-sign-in/index.md). 

> [!TIP]
>
> Explore [Docker's core subscriptions](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopSignIn) to see what else Docker can offer you. 

## Benefits of signing in

- Access your Docker Hub repositories directly from Docker Desktop.

- Increase your pull rate limit compared to anonymous users. See [Usage and limits](../../docker-hub/usage/index.md).

- Enhance your organization’s security posture for containerized development with [Hardened Desktop](../../enterprise/security/hardened-desktop/index.md).

> [!NOTE]
>
> Docker Desktop automatically signs you out after 90 days, or after 30 days of inactivity. 

## Signing in with Docker Desktop for Linux

Docker Desktop for Linux relies on [`pass`](https://www.passwordstore.org/) to store credentials in GPG-encrypted files.
Before signing in to Docker Desktop with your [Docker ID](/accounts/individual/create-account/), you must initialize `pass`.
Docker Desktop displays a warning if `pass` is not configured.

1. Generate a GPG key. You can initialize pass by using a gpg key. To generate a gpg key, run:

   ``` console
   $ gpg --generate-key
   ``` 
2. Enter your name and email once prompted. 

   Once confirmed, GPG creates a key pair. Look for the `pub` line that contains your GPG ID, for example:

   ```text
   ...
   pubrsa3072 2022-03-31 [SC] [expires: 2024-03-30]
    3ABCD1234EF56G78
   uid          Molly <molly@example.com>
   ```
3. Copy the GPG ID and use it to initialize `pass`. For example

   ```console
   $ pass init 3ABCD1234EF56G78
   ``` 

   You should see output similar to: 

   ```text
   mkdir: created directory '/home/molly/.password-store/'
   Password store initialized for <generated_gpg-id_public_key>
   ```

Once you initialize `pass`, you can sign in and pull your private images.
When Docker CLI or Docker Desktop use credentials, a user prompt may pop up for the password you set during the GPG key generation.

```console
$ docker pull molly/privateimage
Using default tag: latest
latest: Pulling from molly/privateimage
3b9cc81c3203: Pull complete 
Digest: sha256:3c6b73ce467f04d4897d7a7439782721fd28ec9bf62ea2ad9e81a5fb7fb3ff96
Status: Downloaded newer image for molly/privateimage:latest
docker.io/molly/privateimage:latest
```

## What's next?

- [Explore Docker Desktop](../use-desktop/index.md) and its features. 
- Change your [Docker Desktop settings](../settings-and-maintenance/settings.md).
- [Browse common FAQs](../troubleshoot-and-support/faqs/general.md).


---

# Run Docker Desktop for Windows in a VM or VDI environment

*Sección: Desktop*

Docker recommends running Docker Desktop natively on Mac, Linux, or Windows. However, Docker Desktop for Windows can run inside a virtual desktop provided the virtual desktop is properly configured.

To run Docker Desktop in a virtual desktop environment, you have two options,
depending on whether nested virtualization is supported:

- If your environment supports nested virtualization, you can run Docker Desktop
  with its default local Linux VM.
- If nested virtualization is not supported, Docker recommends subscribing to and using Docker Offload.

## Use Docker Offload

[Docker Offload](/offload/) lets you offload container workloads to a high-performance, fully hosted cloud environment,
enabling a seamless hybrid experience.

Docker Offload is useful in virtual desktop environments where nested virtualization isn't supported. In these
environments, Docker Desktop can use Docker Offload to ensure you can still build and run containers without relying on
local virtualization.

Docker Offload decouples the Docker Desktop client from the Docker Engine,
allowing the Docker CLI and Docker Desktop Dashboard to interact with
cloud-based resources as if they were local. When you run a container, Docker
provisions a secure, isolated, and ephemeral cloud environment connected to
Docker Desktop via an SSH tunnel. Despite running remotely, features like bind
mounts and port forwarding continue to work seamlessly, providing a local-like
experience. To use Docker Offload:

For more information, see the [Docker Offload product
page](https://www.docker.com/products/docker-offload/) and the [Docker Offload
documentation](/offload/).

## Virtual desktop support when using nested virtualization

> [!NOTE]
>
> Support for running Docker Desktop on a virtual desktop is available to Docker Business customers, on VMware ESXi or Azure VMs only.

Docker support includes installing and running Docker Desktop within the VM, provided that nested virtualization is correctly enabled. The only hypervisors successfully tested are VMware ESXi and Azure, and there is no support for other VMs. For more information on Docker Desktop support, see [Get support](../../support/index.md).

For troubleshooting problems and intermittent failures that are outside of Docker's control, you should contact your hypervisor vendor. Each hypervisor vendor offers different levels of support. For example, Microsoft supports running nested Hyper-V both on-prem and on Azure, with some version constraints. This may not be the case for VMware ESXi.

Docker does not support running multiple instances of Docker Desktop on the same machine in a VM or VDI environment.

> [!TIP]
>
> If you're running Docker Desktop inside a Citrix VDI, note that Citrix can be used with a variety of underlying hypervisors, for example VMware, Hyper-V, Citrix Hypervisor/XenServer. Docker Desktop requires nested virtualization, which is not supported by Citrix Hypervisor/XenServer.
>
> Check with your Citrix administrator or VDI infrastructure team to confirm which hypervisor is being used, and whether nested virtualization is enabled.

## Turn on nested virtualization

You must turn on nested virtualization before you install Docker Desktop on a
virtual machine that will not use Docker Cloud.

### Turn on nested virtualization on VMware ESXi

Nested virtualization of other hypervisors like Hyper-V inside a vSphere VM [is not a supported scenario](https://kb.vmware.com/s/article/2009916). However, running Hyper-V VM in a VMware ESXi VM is technically possible and, depending on the version, ESXi includes hardware-assisted virtualization as a supported feature. A VM that had 1 CPU with 4 cores and 12GB of memory was used for internal testing.

For steps on how to expose hardware-assisted virtualization to the guest OS, [see VMware's documentation](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere/7-0/expose-hardware-assisted-virtualization.html).

### Turn on nested virtualization on an Azure Virtual Machine

Nested virtualization is supported by Microsoft for running Hyper-V inside an Azure VM.

For Azure virtual machines, [check that the VM size chosen supports nested virtualization](https://docs.microsoft.com/en-us/azure/virtual-machines/sizes). Microsoft provides [a helpful list on Azure VM sizes](https://docs.microsoft.com/en-us/azure/virtual-machines/acu) and highlights the sizes that currently support nested virtualization. D4s_v5 machines were used for internal testing. Use this specification or above for optimal performance of Docker Desktop.

## Docker Desktop support on Nutanix-powered VDI

Docker Desktop can be used within Nutanix-powered VDI environments provided that the underlying Windows environment supports WSL 2 or Windows container mode. Since Nutanix officially supports WSL 2, Docker Desktop should function as expected, as long as WSL 2 operates correctly within the VDI environment.

If using Windows container mode, confirm that the Nutanix environment supports Hyper-V or alternative Windows container backends.

### Supported configurations

Docker Desktop follows the VDI support definitions outlined [previously](#virtual-desktop-support-when-using-nested-virtualization):

- Persistent VDI environments (Supported): You receive the same virtual desktop instance across sessions, preserving installed software and configurations.

- Non-persistent VDI environments (Not supported): Docker Desktop does not support environments where the OS resets between sessions, requiring re-installation or reconfiguration each time.

### Support scope and responsibilities

For WSL 2-related issues, contact Nutanix support. For Docker Desktop-specific issues, contact Docker support.

## Additional resources

- [Docker Desktop on Microsoft Dev Box](../../enterprise/enterprise-deployment/dev-box.md)


---

# Index

*Sección: Desktop*

---
build:
  render: never
title: Troubleshoot and support
weight: 50
---


---

# FAQs

*Sección: Desktop*




---

# General FAQs for Desktop

*Sección: Desktop*

### Can I use Docker Desktop offline?

Yes, you can use Docker Desktop offline. However, you
cannot access features that require an active internet
connection. Additionally, any functionality that requires you to sign in won't work while using Docker Desktop offline or in air-gapped environments.

### How do I connect to the remote Docker Engine API?

To connect to the remote Engine API, you might need to provide the location of the Engine API for Docker clients and development tools.

Mac and Windows WSL 2 users can connect to the Docker Engine through a Unix socket: `unix:///var/run/docker.sock`. Docker Desktop for Linux uses a [per-user socket](linuxfaqs.md#how-do-i-use-docker-sdks-with-docker-desktop-for-linux) located at `~/.docker/desktop/docker.sock` instead of the system-wide `/var/run/docker.sock`.

If you are working with applications like [Apache Maven](https://maven.apache.org/)
that expect settings for `DOCKER_HOST` and `DOCKER_CERT_PATH` environment
variables, specify these to connect to Docker instances through Unix sockets.

For example:

```console
$ export DOCKER_HOST=unix:///var/run/docker.sock
```

Docker Desktop Windows users can connect to the Docker Engine through a **named pipe**: `npipe:////./pipe/docker_engine`, or **TCP socket** at this URL:
`tcp://localhost:2375`.

For details, see [Docker Engine API](../../../reference/api/engine/index.md).

### How do I connect from a container to a service on the host?

The host has a changing IP address, or none if you have no network access.
It is recommend that you connect to the special DNS name `host.docker.internal`,
which resolves to the internal IP address used by the host.

For more information and examples, see [how to connect from a container to a service on the host](/manuals/desktop/features/networking.md#connect-a-container-to-a-service-on-the-host).

### Can I pass through a USB device to a container?

Docker Desktop does not support direct USB device passthrough. However, you can use USB over IP to connect common USB devices to the Docker Desktop VM and in turn be forwarded to a container. For more details, see [Using USB/IP with Docker Desktop](../../features/usbip.md).

### How do I verify Docker Desktop is using a proxy server ?

To verify, look at the most recent events logged in `httpproxy.log`. This is located at `~/Library/Containers/com.docker.docker/Data/log/host` on macOS or `%LOCALAPPDATA%/Docker/log/host/` on Windows. 

The following shows a few examples of what you can expect to see:

- Docker Desktop using app level settings (proxy mode manual) for proxy:

   ```console
   host will use proxy: app settings http_proxy=http://172.211.16.3:3128 https_proxy=http://172.211.16.3:3128
   Linux will use proxy: app settings http_proxy=http://172.211.16.3:3128 https_proxy=http://172.211.16.3:3128
   ```

- Docker Desktop using system level settings (proxy mode system) for proxy:

   ```console
   host will use proxy: static system http_proxy=http://172.211.16.3:3128 https_proxy=http://172.211.16.3:3128 no_proxy=
   Linux will use proxy: static system http_proxy=http://172.211.16.3:3128 https_proxy=http://172.211.16.3:3128 no_proxy=
   ```

- Docker Desktop is not configured to use a proxy server:

   ```console
   host will use proxy: disabled
   Linux will use proxy: disabled
   ```

- Docker Desktop is configured to use app level settings (proxy mode manual) and using a PAC file:

   ```console
   using a proxy PAC file: http://127.0.0.1:8081/proxy.pac
   host will use proxy: app settings from PAC file http://127.0.0.1:8081/proxy.pac
   Linux will use proxy: app settings from PAC file http://127.0.0.1:8081/proxy.pac
   ```

- Connect request using the configured proxy server:

   ```console
   CONNECT desktop.docker.com:443: host connecting via static system HTTPS proxy http://172.211.16.3:3128
   ```

### How do I run Docker Desktop without administrator privileges?

Docker Desktop requires administrator privileges only for installation. Once installed, administrator privileges are not needed to run it. However, for non-admin users to run Docker Desktop, it must be installed using a specific installer flag and meet certain prerequisites, which vary by platform.

{{< tabs >}}
{{< tab name="Mac" >}}

To run Docker Desktop on Mac without requiring administrator privileges, install via the command line and pass the `--user=<userid>` installer flag:

```console
$ /Applications/Docker.app/Contents/MacOS/install --user=<userid>
```

You can then sign in to your machine with the user ID specified, and launch Docker Desktop. 

> [!NOTE]
> 
> Before launching Docker Desktop, if a `settings-store.json` file already exists in the `~/Library/Group Containers/group.com.docker/` directory, you will see a **Finish setting up Docker Desktop** window that prompts for administrator privileges when you select **Finish**. To avoid this, ensure you delete the `settings-store.json` file left behind from any previous installations before launching the application.

{{< /tab >}}
{{< tab name="Windows" >}}

> [!NOTE]
>
> If you are using the WSL 2 backend, first make sure that you meet the [minimum required version](../../features/wsl/best-practices.md) for WSL 2. Otherwise, update WSL 2 first.  

To run Docker Desktop on Windows without requiring administrator privileges, install via the command line and pass the `--always-run-service` installer flag.

```console
$ "Docker Desktop Installer.exe" install --always-run-service
```

{{< /tab >}}
{{< /tabs >}}


---

# FAQs for Docker Desktop for Linux

*Sección: Desktop*

### Why does Docker Desktop for Linux run a VM?

Docker Desktop for Linux runs a Virtual Machine (VM) for the following reasons:

1. To ensure that Docker Desktop provides a consistent experience across platforms.

   During research, the most frequently cited reason for users wanting Docker Desktop for Linux was to ensure a consistent Docker Desktop
   experience with feature parity across all major operating systems. Utilizing
   a VM ensures that the Docker Desktop experience for Linux users will closely
   match that of Windows and macOS.

2. To make use of new kernel features.

   Because Docker controls the kernel and the OS inside the VM, Docker can roll these out to all users immediately, even to users who are intentionally sticking on an LTS version of their machine OS.

3. To enhance security.

   Container image vulnerabilities pose a security risk for the host environment. There is a large number of unofficial images that are not guaranteed to be verified for known vulnerabilities. Malicious users can push images to public registries and use different methods to trick users into pulling and running them. The VM approach mitigates this threat as any malware that gains root privileges is restricted to the VM environment without access to the host.

   Why not run rootless Docker? Although this has the benefit of superficially limiting access to the root user so everything looks safer in "top", it allows unprivileged users to gain `CAP_SYS_ADMIN` in their own user namespace and access kernel APIs which are not expecting to be used by unprivileged users, resulting in [vulnerabilities](https://www.openwall.com/lists/oss-security/2022/01/18/7).

4. To provide the benefits of feature parity and enhanced security, with minimal impact on performance.

   The VM utilized by Docker Desktop for Linux uses [`VirtioFS`](https://virtio-fs.gitlab.io), a shared file system that allows virtual machines to access a directory tree located on the host. Docker's internal benchmarking shows that with the right resource allocation to the VM, near native file system performance can be achieved with VirtioFS.

   As such, the default memory available to the VM in Docker Desktop for Linux is adjusted. You can tweak this setting to your specific needs by using the **Memory** slider within the **Settings** > **Resources** tab of Docker Desktop.

### How do I enable file sharing?

Docker Desktop for Linux uses [VirtioFS](https://virtio-fs.gitlab.io/) as the
default (and currently only) mechanism to enable file sharing between the host
and Docker Desktop VM.

{{< accordion title="Additional information for Docker Desktop version 4.34 and earlier" >}}

In order not to require elevated privileges, without
unnecessarily restricting operations on the shared files, Docker Desktop runs
the file sharing service (`virtiofsd`) inside a user namespace (see
`user_namespaces(7)`) with UID and GID mapping configured. As a result Docker
Desktop relies on the host being configured to enable the current user to use
subordinate ID delegation. For this to be true `/etc/subuid` (see `subuid(5)`)
and `/etc/subgid` (see `subgid(5)`) must be present. Docker Desktop only
supports subordinate ID delegation configured via files. Docker Desktop maps the
current user ID and GID to 0 in the containers. It uses the first entry
corresponding to the current user in `/etc/subuid` and `/etc/subgid` to set up
mappings for IDs greater than 0 in the containers.

| ID in container | ID on host                                                                       |
| --------------- | -------------------------------------------------------------------------------- |
| 0 (root)        | ID of the user running Docker Desktop (e.g. 1000)                                |
| 1               | 0 + beginning of ID range specified in `/etc/subuid`/`/etc/subgid` (e.g. 100000) |
| 2               | 1 + beginning of ID range specified in `/etc/subuid`/`/etc/subgid` (e.g. 100001) |
| 3               | 2 + beginning of ID range specified in `/etc/subuid`/`/etc/subgid` (e.g. 100002) |
| ...             | ...                                                                              |

If `/etc/subuid` and `/etc/subgid` are missing, they need to be created.
Both should contain entries in the form -
`<username>:<start of id range>:<id range size>`. For example, to allow the current user
to use IDs from 100 000 to 165 535:

```console
$ grep "$USER" /etc/subuid >> /dev/null 2&>1 || (echo "$USER:100000:65536" | sudo tee -a /etc/subuid)
$ grep "$USER" /etc/subgid >> /dev/null 2&>1 || (echo "$USER:100000:65536" | sudo tee -a /etc/subgid)
```

To verify the configs have been created correctly, inspect their contents:

```console
$ echo $USER
exampleuser
$ cat /etc/subuid
exampleuser:100000:65536
$ cat /etc/subgid
exampleuser:100000:65536
```

In this scenario if a shared file is `chown`ed inside a Docker Desktop container
owned by a user with a UID of 1000, it shows up on the host as owned by
a user with a UID of 100999. This has the unfortunate side effect of preventing
easy access to such a file on the host. The problem is resolved by creating
a group with the new GID and adding our user to it, or by setting a recursive
ACL (see `setfacl(1)`) for folders shared with the Docker Desktop VM.

{{< /accordion >}}

### How do I use Docker SDKs with Docker Desktop for Linux?

Docker Desktop for Linux uses a per-user socket located at `~/.docker/desktop/docker.sock` instead of the system-wide `/var/run/docker.sock`. The Docker CLI handles this automatically through the `desktop-linux` context, but Docker SDKs and other tools that connect directly to the Docker daemon also need the `DOCKER_HOST` environment variable set.

Without setting `DOCKER_HOST`, SDKs attempt to connect to `/var/run/docker.sock` and fail with an error like:

```text
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```

To fix this, set the `DOCKER_HOST` environment variable before running your SDK-based application:

```console
export DOCKER_HOST=unix://$HOME/.docker/desktop/docker.sock
```

Or dynamically retrieve it from the `desktop-linux` context:

```console
export DOCKER_HOST=$(docker context inspect desktop-linux --format '{{ .Endpoints.docker.Host }}')
```

To make this permanent, add the export command to your shell profile (`~/.bashrc`, `~/.zshrc`, or similar):

```console
echo 'export DOCKER_HOST=unix://$HOME/.docker/desktop/docker.sock' >> ~/.bashrc
```

### Where does Docker Desktop store Linux containers?

Docker Desktop stores Linux containers and images in a single, large "disk image" file in the Linux filesystem. This is different from Docker on Linux, which usually stores containers and images in the `/var/lib/docker` directory on the host's filesystem.

#### Where is the disk image file?

To locate the disk image file, select **Settings** from the Docker Desktop Dashboard then **Advanced** from the **Resources** tab.

The **Advanced** tab displays the location of the disk image. It also displays the maximum size of the disk image and the actual space the disk image is consuming. Note that other tools might display space usage of the file in terms of the maximum file size, and not the actual file size.

##### What if the file is too large?

If the disk image file is too large, you can:

- Move it to a bigger drive
- Delete unnecessary containers and images
- Reduce the maximum allowable size of the file

##### How do I move the file to a bigger drive?

To move the disk image file to a different location:

1. Select **Settings** then **Advanced** from the **Resources** tab.

2. In the **Disk image location** section, select **Browse** and choose a new location for the disk image.

3. Select **Apply** for the changes to take effect.

Do not move the file directly in Finder as this can cause Docker Desktop to lose track of the file.

##### How do I delete unnecessary containers and images?

Check whether you have any unnecessary containers and images. If your client and daemon API are running version 1.25 or later (use the `docker version` command on the client to check your client and daemon API versions), you can see the detailed space usage information by running:

```console
$ docker system df -v
```

Alternatively, to list images, run:

```console
$ docker image ls
```

To list containers, run:

```console
$ docker container ls -a
```

If there are lots of redundant objects, run the command:

```console
$ docker system prune
```

This command removes all stopped containers, unused networks, dangling images, and build cache.

It might take a few minutes to reclaim space on the host depending on the format of the disk image file:

- If the file is named `Docker.raw`: space on the host should be reclaimed within a few seconds.
- If the file is named `Docker.qcow2`: space will be freed by a background process after a few minutes.

Space is only freed when images are deleted. Space is not freed automatically when files are deleted inside running containers. To trigger a space reclamation at any point, run the command:

```console
$ docker run --privileged --pid=host docker/desktop-reclaim-space
```

Note that many tools report the maximum file size, not the actual file size.
To query the actual size of the file on the host from a terminal, run:

```console
$ cd ~/.docker/desktop/vms/0/data
$ ls -klsh Docker.raw
2333548 -rw-r--r--@ 1 username  staff    64G Dec 13 17:42 Docker.raw
```

In this example, the actual size of the disk is `2333548` KB, whereas the maximum size of the disk is `64` GB.

##### How do I reduce the maximum size of the file?

To reduce the maximum size of the disk image file:

1. From Docker Desktop Dashboard select **Settings** then **Advanced** from the **Resources** tab.

2. The **Disk image size** section contains a slider that allows you to change the maximum size of the disk image. Adjust the slider to set a lower limit.

3. Select **Apply**.

When you reduce the maximum size, the current disk image file is deleted, and therefore, all containers and images are lost.


---

# FAQs for Docker Desktop for Mac

*Sección: Desktop*

### What is HyperKit?

HyperKit is a legacy hypervisor built on top of Hypervisor.framework in macOS.
Previous versions of Docker Desktop for Mac used HyperKit to run the Linux VM.

Current versions of Docker Desktop use the Apple Virtualization framework by
default. HyperKit is retained here as historical context for older
configurations.

### What is the benefit of HyperKit?

When HyperKit was the default hypervisor, it provided a lightweight
virtualization layer customized for Docker workloads and eliminated the need
for third-party VM products such as Oracle VirtualBox or VMware Fusion.

### Where does Docker Desktop store Linux containers and images? 

Docker Desktop stores Linux containers and images in a single, large "disk image" file in the Mac filesystem. This is different from Docker on Linux, which usually stores containers and images in the `/var/lib/docker` directory.

#### Where is the disk image file?

To locate the disk image file, select **Settings** from the Docker Desktop Dashboard then **Advanced** from the **Resources** tab.

The **Advanced** tab displays the location of the disk image. It also displays the maximum size of the disk image and the actual space the disk image is consuming. Note that other tools might display space usage of the file in terms of the maximum file size, and not the actual file size.

#### What if the file is too big?

If the disk image file is too big, you can:

- Move it to a bigger drive
- Delete unnecessary containers and images
- Reduce the maximum allowable size of the file

##### How do I move the file to a bigger drive?

To move the disk image file to a different location:

1. Select **Settings** then  **Advanced** from the **Resources** tab.

2. In the **Disk image location** section, select **Browse** and choose a new location for the disk image.

3. Select **Apply** for the changes to take effect.

> [!IMPORTANT]
>
> Do not move the file directly in Finder as this can cause Docker Desktop to lose track of the file.

##### How do I delete unnecessary containers and images?

Check whether you have any unnecessary containers and images. If your client and daemon API are running version 1.25 or later (use the `docker version` command on the client to check your client and daemon API versions), you can see the detailed space usage information by running:

```console
$ docker system df -v
```

Alternatively, to list images, run:

```console
$ docker image ls
```

To list containers, run:

```console
$ docker container ls -a
```

If there are lots of redundant objects, run the command:

```console
$ docker system prune
```

This command removes all stopped containers, unused networks, dangling images, and build cache.

It might take a few minutes to reclaim space on the host depending on the format of the disk image file. If the file is named:

- `Docker.raw`, space on the host is reclaimed within a few seconds.
- `Docker.qcow2`, space is freed by a background process after a few minutes.

Space is only freed when images are deleted. Space is not freed automatically when files are deleted inside running containers. To trigger a space reclamation at any point, run the command:

```console
$ docker run --privileged --pid=host docker/desktop-reclaim-space
```

Note that many tools report the maximum file size, not the actual file size.
To query the actual size of the file on the host from a terminal, run:

```console
$ cd ~/Library/Containers/com.docker.docker/Data/vms/0/data
$ ls -klsh Docker.raw
2333548 -rw-r--r--@ 1 username  staff    64G Dec 13 17:42 Docker.raw
```

In this example, the actual size of the disk is `2333548` KB, whereas the maximum size of the disk is `64` GB.

##### How do I reduce the maximum size of the file?

To reduce the maximum size of the disk image file:

1. Select **Settings** then  **Advanced** from the **Resources** tab.

2. The **Disk image size** section contains a slider that allows you to change the maximum size of the disk image. Adjust the slider to set a lower limit.

3. Select **Apply**.

When you reduce the maximum size, the current disk image file is deleted, and therefore, all containers and images are lost.

### How do I add TLS certificates?

You can add trusted Certificate Authorities (CAs) (used to verify registry
server certificates) and client certificates (used to authenticate to
registries) to your Docker daemon.

#### Add custom CA certificates (server side)

All trusted CAs (root or intermediate) are supported. Docker Desktop creates a
certificate bundle of all user-trusted CAs based on the Mac Keychain, and
appends it to Moby trusted certificates. So if an enterprise SSL certificate is
trusted by the user on the host, it is trusted by Docker Desktop.

To manually add a custom, self-signed certificate, start by adding the
certificate to the macOS keychain, which is picked up by Docker Desktop. Here is
an example:

```console
$ sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.crt
```

Or, if you prefer to add the certificate to your own local keychain only (rather
than for all users), run this command instead:

```console
$ security add-trusted-cert -d -r trustRoot -k ~/Library/Keychains/login.keychain ca.crt
```

See also, [Directory structures for
certificates](#directory-structures-for-certificates).

> [!NOTE]
>
> You need to restart Docker Desktop after making any changes to the keychain or
> to the `~/.docker/certs.d` directory in order for the changes to take effect.

For a complete explanation of how to do this, see the blog post [Adding
Self-signed Registry Certs to Docker & Docker Desktop for
Mac](https://blog.container-solutions.com/adding-self-signed-registry-certs-docker-mac).

#### Add client certificates

You can put your client certificates in
`~/.docker/certs.d/<MyRegistry>:<Port>/client.cert` and
`~/.docker/certs.d/<MyRegistry>:<Port>/client.key`.

When the Docker Desktop application starts, it copies the `~/.docker/certs.d`
folder on your Mac to the `/etc/docker/certs.d` directory on Moby (the Docker
Desktop `xhyve` virtual machine).

> [!NOTE]
>
> * You need to restart Docker Desktop after making any changes to the keychain
>   or to the `~/.docker/certs.d` directory in order for the changes to take
>   effect.
>
> * The registry cannot be listed as an _insecure registry_. Docker Desktop ignores certificates listed
>   under insecure registries, and does not send client certificates. Commands
>   like `docker run` that attempt to pull from the registry produce error
>   messages on the command line, as well as on the registry.

#### Directory structures for certificates

If you have this directory structure, you do not need to manually add the CA
certificate to your Mac OS system login:

```text
/Users/<user>/.docker/certs.d/
└── <MyRegistry>:<Port>
   ├── ca.crt
   ├── client.cert
   └── client.key
```

The following further illustrates and explains a configuration with custom
certificates:

```text
/etc/docker/certs.d/        <-- Certificate directory
└── localhost:5000          <-- Hostname:port
   ├── client.cert          <-- Client certificate
   ├── client.key           <-- Client key
   └── ca.crt               <-- Certificate authority that signed
                                the registry certificate
```

You can also have this directory structure, as long as the CA certificate is
also in your keychain.

```text
/Users/<user>/.docker/certs.d/
└── <MyRegistry>:<Port>
    ├── client.cert
    └── client.key
```

To learn more about how to install a CA root certificate for the registry and
how to set the client TLS certificate for verification, see
[Verify repository client with certificates](../../../engine/security/certificates.md)
in the Docker Engine topics.


---

# FAQs on Docker Desktop releases

*Sección: Desktop*

### How frequent will new releases be?

New releases are available every week, unless there are critical fixes that need to be released sooner. 

The **Automatically check for updates** setting in the **Software updates** tab is turned on by default. This means you receive notifications in the Docker menu and a notification badge on the Docker Desktop Dashboard when a new version is available. 

You can also let Docker Desktop automatically download new updates in the background by selecting the **Always download updates** checkbox.

Sometimes new versions are rolled out gradually over a few days. Therefore, if you wait, it will turn up soon. Alternatively, you can select **Check for updates** in the Docker menu to get the latest version immediately.

### How do I ensure that all users in my organization are using the same version?

This is managed through your IT administrator's endpoint management software.


---

# FAQs for Docker Desktop for Windows

*Sección: Desktop*

### Can I use VirtualBox alongside Docker Desktop?

Yes, you can run VirtualBox along with Docker Desktop if you have enabled the [Windows Hypervisor Platform](https://docs.microsoft.com/en-us/virtualization/api/) feature on your machine.

### Why is Windows 10 or Windows 11 required?

Docker Desktop uses the Windows Hyper-V features. While older Windows versions have Hyper-V, their Hyper-V implementations lack features critical for Docker Desktop to work.

### Can I run Docker Desktop on Windows Server?

No, running Docker Desktop on Windows Server is not supported.

### How do symlinks work on Windows?

Docker Desktop supports two types of symlinks: Windows native symlinks and symlinks created inside a container.

The Windows native symlinks are visible within the containers as symlinks, whereas symlinks created inside a container are represented as [mfsymlinks](https://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks). These are regular Windows files with a special metadata. Therefore the symlinks created inside a container appear as symlinks inside the container, but not on the host.

### File sharing with Kubernetes and WSL 2

Docker Desktop mounts the Windows host filesystem under `/run/desktop` inside the container running Kubernetes.
See the [Stack Overflow post](https://stackoverflow.com/questions/67746843/clear-persistent-volume-from-a-kubernetes-cluster-running-on-docker-desktop/69273405#69273) for an example of how to configure a Kubernetes Persistent Volume to represent directories on the host.

### How do I add custom CA certificates?

You can add trusted Certificate Authorities (CAs) to your Docker daemon to verify registry server certificates, and client certificates, to authenticate to registries.

Docker Desktop supports all trusted Certificate Authorities (CAs) (root or
intermediate). Docker recognizes certs stored under Trust Root
Certification Authorities or Intermediate Certification Authorities.

Docker Desktop creates a certificate bundle of all user-trusted CAs based on
the Windows certificate store, and appends it to Moby trusted certificates. Therefore, if an enterprise SSL certificate is trusted by the user on the host, it is trusted by Docker Desktop.

To learn more about how to install a CA root certificate for the registry, see
[Verify repository client with certificates](../../../engine/security/certificates.md)
in the Docker Engine topics.

### How do I add client certificates?

You can add your client certificates
in `~/.docker/certs.d/<MyRegistry>:<Port>/client.cert` and
`~/.docker/certs.d/<MyRegistry>:<Port>/client.key`. You do not need to push your certificates with `git` commands.

When the Docker Desktop application starts, it copies the
`~/.docker/certs.d` folder on your Windows system to the `/etc/docker/certs.d`
directory on Moby (the Docker Desktop virtual machine running on Hyper-V).

You need to restart Docker Desktop after making any changes to the keychain
or to the `~/.docker/certs.d` directory in order for the changes to take effect.

The registry cannot be listed as an insecure registry (see
[Docker Daemon](../../settings-and-maintenance/settings.md#docker-engine)). Docker Desktop ignores
certificates listed under insecure registries, and does not send client
certificates. Commands like `docker run` that attempt to pull from the registry
produce error messages on the command line, as well as on the registry.

To learn more about how to set the client TLS certificate for verification, see
[Verify repository client with certificates](../../../engine/security/certificates.md)
in the Docker Engine topics.


---

# Give feedback

*Sección: Desktop*

There are many ways you can provide feedback on Docker Desktop or Docker Desktop features.

### In-product feedback

On each Docker Desktop Dashboard view, there is a **Give feedback** link. This opens a feedback form where you can share ideas directly with the Docker Team.

### Feedback via Docker Community forums

To get help from the community, review current user topics, join or start a
discussion, sign in to the appropriate Docker forums:

- [Docker Desktop for Mac forum](https://forums.docker.com/c/docker-for-mac)
- [Docker Desktop for Windows forum](https://forums.docker.com/c/docker-for-windows)
- [Docker Desktop for Linux forum](https://forums.docker.com/c/docker-desktop-for-linux/60)

### Report bugs or problems on GitHub

To report bugs or problems, visit:
- [Docker Desktop issues on GitHub](https://github.com/docker/desktop-feedback)
- [Docker Extensions issues on GitHub](https://github.com/docker/extensions-sdk/issues)

### Feedback via Community Slack channels

You can also provide feedback through the following [Docker Community Slack](https://dockr.ly/comm-slack) channels:

- #docker-desktop-mac
- #docker-desktop-windows
- #docker-desktop-linux
- #extensions


---

# Troubleshoot Docker Desktop

*Sección: Desktop*

This page contains information on how to diagnose and troubleshoot Docker Desktop, and how to check the logs.

## Troubleshoot menu

To navigate to **Troubleshoot** either:

- Select the Docker menu Docker menu {{< inline-image src="../../images/whale-x.svg" alt="whale menu" >}} and then **Troubleshoot**.
- Select the **question mark** icon near the top-right corner of the Docker Desktop Dashboard.

The **Troubleshoot** menu contains the following options:

- **Restart Docker Desktop**

- **Support**

- **Reset Kubernetes cluster**. Select to delete all stacks and Kubernetes resources. For more information, see [Kubernetes](../../settings-and-maintenance/settings.md#kubernetes).

- **Clean up data**. This option resets all Docker data without a
  reset to factory defaults. Selecting this option results in the loss of existing settings.

- **Reset to factory defaults**: Choose this option to reset all options on
  Docker Desktop to their initial state, the same as when Docker Desktop was first installed.

If you are a Mac or Linux user, you also have the option to **Uninstall** Docker Desktop from your system.

## Diagnose

> [!NOTE]
>
> Gathering diagnostics may take several minutes. Don't close Docker Desktop while the diagnostics are being collected.

### Diagnose from the app

1. From **Troubleshoot**, select **Get support**. This opens the in-app Support page and starts collecting the diagnostics.
2. When the diagnostics collection process is complete, select **Upload to get a Diagnostic ID**.
3. When the diagnostics are uploaded, Docker Desktop prints a diagnostic ID. Copy this ID.
4. Use your diagnostics ID to get help:
   - If you have a Docker subscription and are signed in, select **Contact support**. This opens the Docker Desktop support form. Fill in the information required and add the ID you copied in step three to the **Diagnostics ID field**. Then, select **Submit ticket** to request Docker Desktop support.
   - If you don't have a Docker subscription, select **Report a Bug** to open a new Docker Desktop issue on GitHub. Complete the information required and ensure you add the diagnostic ID you copied in step three.

### Diagnose from an error message

1. When an error message appears, select **Gather diagnostics**. Gathering diagnostics may take several minutes. Don't close Docker Desktop while the diagnostics are being collected.
2. When the diagnostics are uploaded, Docker Desktop prints a diagnostic ID. Copy this ID.
3. Use your diagnostics ID to get help:
   - If you have a Docker subscription and are signed in, select **Contact support**. This opens the Docker Desktop support form. Fill in the information required and add the ID you copied in step three to the **Diagnostics ID field**. Then, select **Submit ticket** to request Docker Desktop support.
   - If you don't have a Docker subscription, you can open a new [Docker Desktop issue on GitHub](https://github.com/docker/desktop-feedback). Complete the information required and ensure you add the diagnostic ID printed in step two.

### Diagnose from the terminal

In some cases, it's useful to run the diagnostics yourself, for instance, if the Docker Desktop Dashboard cannot start.

Run the [`docker desktop diagnose`](../../features/desktop-cli.md) command:

```console
$ docker desktop diagnose
```

Gathering diagnostics may take several minutes. Wait for the process to complete before closing the terminal.

After the diagnostics have finished, the terminal displays your diagnostics ID and the path to the diagnostics file. The diagnostics ID is composed of your user ID and a timestamp. For example `BE9AFAAF-F68B-41D0-9D12-84760E6B8740/20190905152051`.

Alternatively, you can use the `com.docker.diagnose` tool:

{{< tabs group="os" >}}
{{< tab name="Windows" >}}

1. Locate the `com.docker.diagnose` tool:

   ```console
   # For all-user installations
   $ C:\Program Files\Docker\Docker\resources\com.docker.diagnose.exe

   # For per-user installations
   $ %LOCALAPPDATA%\Programs\DockerDesktop\resources\com.docker.diagnose.exe
   ```

2. Create and upload the diagnostics ID. In PowerShell, run:

   ```console
   # For all-user installations
   $ & "C:\Program Files\Docker\Docker\resources\com.docker.diagnose.exe" gather -upload

   # For per-user installations
   $ & %LOCALAPPDATA%\Programs\DockerDesktop\resources\com.docker.diagnose.exe" gather -upload
   ```

After the diagnostics have finished, the terminal displays your diagnostics ID and the path to the diagnostics file. The diagnostics ID is composed of your user ID and a timestamp. For example `BE9AFAAF-F68B-41D0-9D12-84760E6B8740/20190905152051`.

{{< /tab >}}
{{< tab name="Mac" >}}

1. Locate the `com.docker.diagnose` tool:

   ```console
   $ /Applications/Docker.app/Contents/MacOS/com.docker.diagnose
   ```

2. Create and upload the diagnostics ID. Run:

   ```console
   $ /Applications/Docker.app/Contents/MacOS/com.docker.diagnose gather -upload
   ```

After the diagnostics have finished, the terminal displays your diagnostics ID and the path to the diagnostics file. The diagnostics ID is composed of your user ID and a timestamp. For example `BE9AFAAF-F68B-41D0-9D12-84760E6B8740/20190905152051`.

{{< /tab >}}
{{< tab name="Linux" >}}

1. Locate the `com.docker.diagnose` tool:

   ```console
   $ /opt/docker-desktop/bin/com.docker.diagnose
   ```

2. Create and upload the diagnostics ID. Run:

   ```console
   $ /opt/docker-desktop/bin/com.docker.diagnose gather -upload
   ```

After the diagnostics have finished, the terminal displays your diagnostics ID and the path to the diagnostics file. The diagnostics ID is composed of your user ID and a timestamp. For example `BE9AFAAF-F68B-41D0-9D12-84760E6B8740/20190905152051`.

{{< /tab >}}
{{< /tabs >}}

To view the contents of the diagnostic file:

{{< tabs group="os" >}}
{{< tab name="Windows" >}}

1. Unzip the file. In PowerShell, copy and paste the path to the diagnostics file into the following command and then run it. It should be similar to the following example:

   ```powershell
   $ Expand-Archive -LiteralPath "C:\Users\testUser\AppData\Local\Temp\5DE9978A-3848-429E-8776-950FC869186F\20230607101602.zip" -DestinationPath "C:\Users\testuser\AppData\Local\Temp\5DE9978A-3848-429E-8776-950FC869186F\20230607101602"
   ```

2. Open the file in your preferred text editor. Run:

   ```powershell
   $ code <path-to-file>
   ```

{{< /tab >}}
{{< tab name="Mac" >}}

Run:

```console
$ open /tmp/<your-diagnostics-ID>.zip
```

{{< /tab >}}
{{< tab name="Linux" >}}

Run:

```console
$ unzip –l /tmp/<your-diagnostics-ID>.zip
```

{{< /tab >}}
{{< /tabs >}}

#### Use your diagnostics ID to get help

If you have a Docker subscription, [Contact support](https://app.docker.com/support/contact). Fill in the information required and add your diagnostics ID.

If you don't have a Docker subscription, create an issue on [GitHub](https://github.com/docker/desktop-feedback).

## Check the logs

In addition to using the diagnose option to submit logs, you can browse the logs yourself.

To access Docker Desktop logs, run:

```console
$ docker desktop diagnose
```

## View the Docker daemon logs

Refer to the [Read the daemon logs](../../../engine/daemon/logs.md) section
to learn how to view the Docker Daemon logs.

## Further resources

- View specific [troubleshoot topics](topics.md).
- View information on [known issues](known-issues.md)
- [Fix "Docker.app is damaged" on macOS](mac-damaged-dialog.md) - Resolve macOS installation issues
- [Get support for Docker products](../../../support/index.md)


---

# Known issues

*Sección: Desktop*

{{< tabs >}}
{{< tab name="For Mac with Intel chip" >}}
- The Mac Activity Monitor reports that Docker is using twice the amount of memory it's actually using. This is due to a [bug in macOS](https://docs.google.com/document/d/17ZiQC1Tp9iH320K-uqVLyiJmk4DHJ3c4zgQetJiKYQM/edit?usp=sharing).

- **"Docker.app is damaged" dialog**: If you see a "Docker.app is damaged and can't be opened" dialog during installation or updates, this is typically caused by non-atomic copy operations when other applications are using the Docker CLI. See [Fix "Docker.app is damaged" on macOS](mac-damaged-dialog.md) for resolution steps.

- Force-ejecting the `.dmg` after running `Docker.app` from it can cause the
  whale icon to become unresponsive, Docker tasks to show as not responding in the Activity Monitor, and for some processes to consume a large amount of CPU resources. Reboot and restart Docker to resolve these issues.

- Docker Desktop uses the `HyperKit` hypervisor
  (https://github.com/docker/hyperkit). If you are developing with tools that
  have conflicts with `HyperKit`, such as [Intel Hardware Accelerated Execution
  Manager
  (HAXM)](https://software.intel.com/en-us/android/articles/intel-hardware-accelerated-execution-manager/),
  the current workaround is not to run them at the same time. You can pause
  `HyperKit` by quitting Docker Desktop temporarily while you work with HAXM.
  This allows you to continue work with the other tools and prevent `HyperKit`
  from interfering.

- If you are working with applications like [Apache
  Maven](https://maven.apache.org/) that expect settings for `DOCKER_HOST` and
  `DOCKER_CERT_PATH` environment variables, specify these to connect to Docker
  instances through Unix sockets. For example:

  ```console
  $ export DOCKER_HOST=unix:///var/run/docker.sock
  ```

{{< /tab >}}
{{< tab name="For Mac with Apple silicon" >}}

- **"Docker.app is damaged" dialog**: If you see a "Docker.app is damaged and can't be opened" dialog during installation or updates, this is typically caused by non-atomic copy operations when other applications are using the Docker CLI. See [Fix "Docker.app is damaged" on macOS](mac-damaged-dialog.md) for resolution steps.

- Some images do not support the ARM64 architecture. You can add `--platform linux/amd64` to run (or build) an Intel image using emulation.

   However, attempts to run Intel-based containers on Apple silicon machines under emulation can crash as QEMU sometimes fails to run the container. In addition, filesystem change notification APIs (`inotify`) do not work under QEMU emulation. Even when the containers do run correctly under emulation, they will be slower and use more memory than the native equivalent.

   In summary, running Intel-based containers on Arm-based machines should be regarded as "best effort" only. We recommend running `arm64` containers on Apple silicon machines whenever possible, and encouraging container authors to produce `arm64`, or multi-arch, versions of their containers. This issue should become less common over time, as more and more images are rebuilt [supporting multiple architectures](https://www.docker.com/blog/multi-arch-build-and-images-the-simple-way/).

{{< /tab >}}
{{< /tabs >}}


---

# Fix "Docker.app is damaged and can't be opened" on macOS

*Sección: Desktop*

## Error message

macOS shows the following dialog when you try to open Docker Desktop:

```text
Docker.app is damaged and can't be opened. You should move it to the Trash.
```

This error prevents Docker Desktop from launching and can occur during installation or after updates.

## Possible cause

This issue occurs due to a non-atomic copy during a drag/drop installation. When you drag and drop `Docker.app` from a DMG file while another application, like VS Code, is invoking the Docker CLI through symlinks, the copy operation may be interrupted, leaving the app in a partially copied state that Gatekeeper marks as "damaged".

## Solution

Follow these steps to resolve the issue:

### Step one: Quit third-party software

Close any applications that might call Docker in the background:

- Visual Studio Code and other IDEs
- Terminal applications
- Agent apps or development tools
- Any scripts or processes that use the Docker CLI

### Step two: Remove any partial installation

1. Move `/Applications/Docker.app` to Trash and empty Trash.
2. If you used a DMG installer, eject and re-mount the Docker DMG.

### Step three: Reinstall Docker Desktop

Follow the instructions in the [macOS installation guide](../../setup/install/mac-install.md) to reinstall Docker Desktop.

### If the dialog persists

If you continue to see the "damaged" dialog after following the recovery steps:

1. Gather diagnostics using the terminal. Follow the instructions in [Diagnose from the terminal](index.md#diagnose-from-the-terminal).

   - Note down the your diagnostics ID displayed in the terminal after running diagnostics.

2. Get help:
   - If you have a paid Docker subscription, [contact support](../../../support/index.md) and include your diagnostics ID
   - For community users, [open an issue on GitHub](https://github.com/docker/desktop-feedback) and include your diagnostics ID

## Prevention

To avoid this issue in the future:

- If your organization allows, update Docker Desktop via the in-app update flow
- Always quit applications that use Docker before installing Docker Desktop via the DMG installer drag-and-drop approach
- In managed environments, use PKG installations over DMG drag-and-drop
- Keep installer volumes mounted until installation is complete

## Related information

- [Install Docker Desktop on Mac](../../setup/install/mac-install.md)
- [PKG installer documentation](../../../enterprise/enterprise-deployment/pkg-install-and-configure.md)
- [Troubleshoot Docker Desktop](index.md)
- [Known issues](known-issues.md)


---

# Troubleshoot topics for Docker Desktop

*Sección: Desktop*

> [!TIP]
>
> If you do not find a solution in troubleshooting, browse the GitHub repositories or [create a new issue](https://github.com/docker/desktop-feedback).

## Topics for all platforms

### Certificates not set up correctly 

#### Error message 

When attempting to pull from a registry using `docker run`, you may encounter the following error:

```console
Error response from daemon: Get http://192.168.203.139:5858/v2/: malformed HTTP response "\x15\x03\x01\x00\x02\x02"
```

Additionally, logs from the registry may show:

```console
2017/06/20 18:15:30 http: TLS handshake error from 192.168.203.139:52882: tls: client didn't provide a certificate
2017/06/20 18:15:30 http: TLS handshake error from 192.168.203.139:52883: tls: first record does not look like a TLS handshake
```

#### Possible causes 

- Docker Desktop ignores certificates listed under insecure registries.
- Client certificates are not sent to insecure registries, causing handshake failures.

#### Solution 

- Ensure that your registry is properly configured with valid SSL certificates.
- If your registry is self-signed, configure Docker to trust the certificate by adding it to Docker’s certificates directory (/etc/docker/certs.d/ on Linux).
- If the issue persists, check your Docker daemon configuration and enable TLS authentication.

### Docker Desktop's UI appears green, distorted, or has visual artifacts

#### Cause

Docker Desktop uses hardware-accelerated graphics by default, which may cause problems for some GPUs.

#### Solution

Disable hardware acceleration:

1. Edit Docker Desktop's `settings-store.json` file. You can find this file at:

   - Mac: `~/Library/Group Containers/group.com.docker/settings-store.json`
   - Windows: `C:\Users\[USERNAME]\AppData\Roaming\Docker\settings-store.json`
   - Linux: `~/.docker/desktop/settings-store.json.`

2. Add the following entry:

   ```JSON
   "disableHardwareAcceleration": "always"
   ```

3. Save the file and restart Docker Desktop.

### Using mounted volumes and getting runtime errors indicating an application file is not found, access to a volume mount is denied, or a service cannot start

#### Cause

If your project directory is located outside your home directory (`/home/<user>`), Docker Desktop requires file sharing permissions to access it.

#### Solution

Enable file sharing in Docker Desktop for Mac and Linux:

1. Navigate to **Settings**, select **Resources** and then **File sharing**.
2. Add the drive or folder that contains the Dockerfile and volume mount paths.

Enable file sharing in Docker Desktop for Windows:

1. From **Settings**, select **Shared Folders**. 
2. Share the folder that contains the Dockerfile and volume mount paths.

### `port already allocated` errors

#### Error message

When starting a container, you may see an error like:

```text
Bind for 0.0.0.0:8080 failed: port is already allocated
```

Or

```text
listen tcp:0.0.0.0:8080: bind: address is already in use
```

#### Cause

- Another application on your system is already using the specified port.
- A previously running container was not stopped properly and is still bound to the port.

#### Solution

To discover the identity of this software, either:
- Use the `resmon.exe` GUI, select **Network** and then **Listening Ports**
- In PowerShell, use `netstat -aon | find /i "listening "` to discover the PID of the process
currently using the port (the PID is the number in the rightmost column). 

Then, decide whether to shut the other process down, or to use a different port in your
Docker app.

## Topics for Linux and Mac

### Docker Desktop fails to start on Mac or Linux platforms

#### Error message 

Docker fails to start due to Unix domain socket path length limitations:

```console
[vpnkit-bridge][F] listen unix <HOME>/Library/Containers/com.docker.docker/Data/http-proxy-control.sock: bind: invalid argument
```

```console
[com.docker.backend][E] listen(vsock:4099) failed: listen unix <HOME>/Library/Containers/com.docker.docker/Data/vms/0/00000002.00001003: bind: invalid argument
```

#### Cause

On Mac and Linux, Docker Desktop creates Unix domain sockets used for inter-process communication. These sockets are created under the user's home directory.

Unix domain sockets have a maximum path length:
 - 104 characters on Mac
 - 108 characters on Linux

If your home directory path is too long, Docker Desktop fails to create necessary sockets.

#### Solution

Ensure your username is short enough to keep paths within the allowed limit:
 - Mac: Username should be ≤ 33 characters
 - Linux: Username should be ≤ 55 characters

## Topics for Mac

### Upgrade requires administrator privileges

#### Cause 

On macOS, users without administrator privileges cannot perform in-app upgrades from the Docker Desktop Dashboard.

#### Solution

> [!IMPORTANT]
>
> Do not uninstall the current version before upgrading. Doing so deletes all local Docker containers, images, and volumes.

To upgrade Docker Desktop:

- Ask an administrator to install the newer version over the existing one.
- Use the [`--user` install flag](../../setup/install/mac-install.md#security-and-access) if appropriate for your setup.

### Persistent notification telling me an application has changed my Desktop configurations

#### Cause 

You receive this notification because the Configuration integrity check feature has detected that a third-party application has altered your Docker Desktop configuration. This usually happens due to incorrect or missing symlinks. The notification ensures you are aware of these changes so you can review and repair any potential issues to maintain system reliability.

Opening the notification presents a pop-up window which provides detailed information about the detected integrity issues.

#### Solution

If you choose to ignore the notification, it will be shown again only at the next Docker Desktop startup. If you choose to repair your configuration, you won't be prompted again.

If you want to switch off Configuration integrity check notifications, navigate to Docker Desktop's settings and in the **General** tab, clear the **Automatically check configuration** setting. 

### `com.docker.vmnetd` is still running after I quit the app

The privileged helper process `com.docker.vmnetd` is started by `launchd` and
runs in the background. The process does not consume any resources unless
`Docker.app` connects to it, so it's safe to ignore.

### Incompatible CPU detected

#### Cause

Docker Desktop requires a processor (CPU) that supports virtualization and, more
specifically, the [Apple Hypervisor
framework](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/).

#### Solution

Check that: 

 - You've installed the correct Docker Desktop for your architecture
 - Your Mac supports Apple's Hypervisor framework. To check if your Mac supports the Hypervisor framework, run the following command in a terminal window.

   ```console
   $ sysctl kern.hv_support
   ```

   If your Mac supports the Hypervisor Framework, the command prints `kern.hv_support: 1`.

   If not, the command prints `kern.hv_support: 0`.

See also, [Hypervisor Framework
Reference](https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/Hypervisor/)
in the Apple documentation, and Docker Desktop [Mac system requirements](../../setup/install/mac-install.md#system-requirements).

## Topics for Windows

### Docker Desktop fails to start when anti-virus software is installed

#### Cause

Some anti-virus software may be incompatible with Hyper-V and Microsoft
Windows builds. The conflict
typically occurs after a Windows update and
manifests as an error response from the Docker daemon and a Docker Desktop start failure.

#### Solution

For a temporary workaround, uninstall the anti-virus software, or
add Docker to the exclusions/exceptions in your antivirus software.

Some anti-virus software, such as Avast, also has its own hardware-assisted
virtualization or hardened mode that claims exclusive access to
Hyper-V, which blocks Docker Desktop and WSL from using it. If your Docker
Desktop start failure includes an error such as
`Wsl/Service/RegisterDistro/CreateVm/HCS/ERROR_NOT_SUPPORTED`, disable this
feature in your anti-virus software. For example, in Avast, go to **Menu** >
**Settings** > **Troubleshooting** and clear **Enable hardware-assisted
virtualization**.

### Permissions errors on data directories for shared volumes

#### Cause 

When sharing files from Windows, Docker Desktop sets permissions on [shared volumes](../../settings-and-maintenance/settings.md#file-sharing)
to a default value of [0777](https://chmodcommand.com/chmod-0777/)
(`read`, `write`, `execute` permissions for `user` and for `group`).

The default permissions on shared volumes are not configurable. 

#### Solution

If you are
working with applications that require different permissions, either:
 - Use non-host-mounted volumes  
 - Find a way to make the applications work with the default file permissions

### Unexpected syntax errors, use Unix style line endings for files in containers

#### Cause 

Docker containers expect Unix-style line `\n` endings, not Windows style: `\r\n`. This includes files referenced at the command line for builds and in RUN commands in Docker files.

Keep this in mind when authoring files such as shell scripts using Windows
tools, where the default is likely to be Windows style line endings. These
commands ultimately get passed to Unix commands inside a Unix based container
(for example, a shell script passed to `/bin/sh`). If Windows style line endings
are used, `docker run` fails with syntax errors.

#### Solution 

 - Convert files to Unix-style line endings using:
   
   ```console
   $ dos2unix script.sh
   ```
- In VS Code, set line endings to `LF` (Unix) instead of `CRLF` (Windows).

### Path conversion errors on Windows

#### Cause

Unlike Linux, Windows requires explicit path conversion for volume mounting.


On Linux, the system takes care of mounting a path to another path. For example, when you run the following command on Linux:

```console
$ docker run --rm -ti -v /home/user/work:/work alpine
```

It adds a `/work` directory to the target container to mirror the specified path.

#### Solution

Update the source path. For example, if you are using 
the legacy Windows shell (`cmd.exe`), you can use the following command:

```console
$ docker run --rm -ti -v C:\Users\user\work:/work alpine
```

This starts the container and ensures the volume becomes usable. This is possible because Docker Desktop detects
the Windows-style path and provides the appropriate conversion to mount the directory.

Docker Desktop also allows you to use Unix-style path to the appropriate format. For example:

```console
$ docker run --rm -ti -v /c/Users/user/work:/work alpine ls /work
```

### Docker commands failing in Git Bash

#### Error message

```console
$ docker run --rm -ti -v C:\Users\user\work:/work alpine
docker: Error response from daemon: mkdir C:UsersUserwork: Access is denied.
```

```console
$ docker run --rm -ti -v $(pwd):/work alpine
docker: Error response from daemon: OCI runtime create failed: invalid mount {Destination:\Program Files\Git\work Type:bind Source:/run/desktop/mnt/host/c/Users/user/work;C Options:[rbind rprivate]}: mount destination \Program Files\Git\work not absolute: unknown.
```

#### Cause

Git Bash (or MSYS) provides a Unix-like environment on Windows. These tools apply their own
preprocessing on the command line. 

This affects `$(pwd)`, colon-separated paths, and tilde (`~`)

Also, the `\` character has a special meaning in Git Bash. 

#### Solution

 - Disable Git Bash path conversion temporarily. For example, run the command with MSYS path conversion disable:
    ```console
    $ MSYS_NO_PATHCONV=1 docker run --rm -ti -v $(pwd):/work alpine
    ```
 - Use proper path formatting:
    - Use double forward and backslashes (`\\` `//`) instead of single (`\` `/`).
    - If referencing `$(pwd)`, add an extra `/`:

Portability of the scripts is not affected as Linux treats multiple `/` as a single entry.

### Docker Desktop fails due to Virtualization not working

#### Error message

A typical error message is "Docker Desktop - Unexpected WSL error" mentioning the error code
`Wsl/Service/RegisterDistro/CreateVm/HCS/HCS_E_HYPERV_NOT_INSTALLED` or
`Wsl/Service/RegisterDistro/CreateVm/HCS/ERROR_NOT_SUPPORTED`. Manually executing `wsl` commands
also fails with the same error code.

#### Cause

- Virtualization settings are disabled in the BIOS.
- Windows Hyper-V or WSL 2 components are missing.

Note some third-party software such as Android emulators will disable Hyper-V on install.

#### Solutions

Your machine must have the following features for Docker Desktop to function correctly:

##### WSL 2 and Windows Home

1. Virtual Machine Platform
2. [Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
3. [Virtualization enabled in the BIOS](https://support.microsoft.com/en-gb/windows/enable-virtualization-on-windows-c5578302-6e43-4b4b-a449-8ced115f58e1)
   Note that many Windows devices already have virtualization enabled, so this may not apply.
4. Hypervisor enabled at Windows startup

![WSL 2 enabled](../../images/wsl2-enabled.png)

It must be possible to run WSL 2 commands without error, for example:

```console
PS C:\users\> wsl -l -v
  NAME              STATE           VERSION
* Ubuntu            Running         2
  docker-desktop    Stopped         2
PS C:\users\> wsl -d docker-desktop echo WSL 2 is working
WSL 2 is working
```

If the features are enabled but the commands are not working, first check [Virtualization is turned on](#virtualization-must-be-turned-on)
then [enable the Hypervisor at Windows startup](#hypervisor-enabled-at-windows-startup) if required. If running Docker
Desktop in a Virtual Machine, ensure [the hypervisor has nested virtualization enabled](#turn-on-nested-virtualization).

##### Hyper-V

On Windows 10 Pro or Enterprise, you can also use Hyper-V with the following features enabled:

1. [Hyper-V](https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/hyper-v-technology-overview)
   installed and working
2. [Virtualization enabled in the BIOS](https://support.microsoft.com/en-gb/windows/enable-virtualization-on-windows-c5578302-6e43-4b4b-a449-8ced115f58e1)
   Note that many Windows devices already have virtualization enabled, so this may not apply.
3. Hypervisor enabled at Windows startup

![Hyper-V on Windows features](../../images/hyperv-enabled.png)

Docker Desktop requires Hyper-V as well as the Hyper-V Module for Windows
PowerShell to be installed and enabled. The Docker Desktop installer enables
it for you.

Docker Desktop also needs two CPU hardware features to use Hyper-V: Virtualization and Second Level Address Translation (SLAT), which is also called Rapid Virtualization Indexing (RVI). On some systems, Virtualization must be enabled in the BIOS. The steps required are vendor-specific, but typically the BIOS option is called `Virtualization Technology (VTx)` or something similar. Run the command `systeminfo` to check all required Hyper-V features. See [Pre-requisites for Hyper-V on Windows 10](https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/hyper-v-requirements) for more details.

To install Hyper-V manually, see [Install Hyper-V on Windows 10](https://msdn.microsoft.com/en-us/virtualization/hyperv_on_windows/quick_start/walkthrough_install). A reboot is *required* after installation. If you install Hyper-V without rebooting, Docker Desktop does not work correctly.

From the start menu, type **Turn Windows features on or off** and press enter.
In the subsequent screen, verify that Hyper-V is enabled.

##### Virtualization must be turned on

In addition to [Hyper-V](#hyper-v) or [WSL 2](../../features/wsl/index.md), virtualization must be turned on. Check the
Performance tab on the Task Manager. Alternatively, you can type `systeminfo` into your terminal. If you see `Hyper-V Requirements: A hypervisor has been detected. Features required for Hyper-V will not be displayed`, then virtualization is enabled.

![Task Manager](../../images/virtualization-enabled.png)

If you manually uninstall Hyper-V, WSL 2 or turn off virtualization,
Docker Desktop cannot start. 

To turn on nested virtualization, see [Run Docker Desktop for Windows in a VM or VDI environment](../../setup/vm-vdi.md#turn-on-nested-virtualization).

##### Hypervisor enabled at Windows startup

If you have completed the previous steps and are still experiencing
Docker Desktop startup issues, this could be because the Hypervisor is installed,
but not launched during Windows startup. Some tools (such as older versions of 
Virtual Box) and video game installers turn off hypervisor on boot. To turn it back on:

1. Open an administrative console prompt.
2. Run `bcdedit /set hypervisorlaunchtype auto`.
3. Restart Windows.

You can also refer to the [Microsoft TechNet article](https://social.technet.microsoft.com/Forums/en-US/ee5b1d6b-09e2-49f3-a52c-820aafc316f9/hyperv-doesnt-work-after-upgrade-to-windows-10-1809?forum=win10itprovirt) on Code flow guard (CFG) settings.

##### Turn on nested virtualization

If you are using Hyper-V and you get the following error message when running Docker Desktop in a VDI environment:

```console
The Virtual Machine Management Service failed to start the virtual machine 'DockerDesktopVM' because one of the Hyper-V components is not running
```

Try [enabling nested virtualization](../../setup/vm-vdi.md#turn-on-nested-virtualization).

### Docker Desktop with Windows Containers fails with "The media is write protected""

#### Error message

`FSCTL_EXTEND_VOLUME \\?\Volume{GUID}: The media is write protected`

#### Cause

If you're encountering failures when running Docker Desktop with Windows Containers, it might be due to
a specific Windows configuration policy: FDVDenyWriteAccess.

This policy, when enabled, causes Windows to mount all fixed drives not encrypted by BitLocker-encrypted as read-only.
This also affects virtual machine volumes and as a result, Docker Desktop may not be able to start or run containers
correctly because it requires read-write access to these volumes.

FDVDenyWriteAccess is a Windows Group Policy setting that, when enabled, prevents write access to fixed data drives that are not protected
by BitLocker. This is often used in security-conscious environments but can interfere with development tools like Docker.
In the Windows registry it can be found at `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Policies\Microsoft\FVE\FDVDenyWriteAccess`.

#### Solutions

Docker Desktop does not support running Windows Containers on systems where FDVDenyWriteAccess is enabled. This setting interferes with the
ability of Docker to mount volumes correctly, which is critical for container functionality.

To use Docker Desktop with Windows Containers, ensure that FDVDenyWriteAccess is disabled. You can check and change this setting in the registry or through Group Policy Editor (`gpedit.msc`) under:

**Computer Configuration** > **Administrative Templates** > **Windows Components** > **BitLocker Drive Encryption** > **Fixed Data Drives** > **Deny write access to fixed drives not protected by BitLocker**

> [!NOTE]
>
> Modifying Group Policy settings may require administrator privileges and should comply with your organization's IT policies. If the setting gets reset after some time this usually means that it was overridden by the centralized configuration of your IT department. Talk to them before making any changes.

### `Docker Desktop Access Denied` error message when starting Docker Desktop

#### Error message

When starting Docker Desktop, the following error appears:

```text
Docker Desktop - Access Denied
```

#### Cause

The user is not part of the `docker-users` group, which is required for permissions.

#### Solution

If your admin account is different to your user account, add it:

1. Run **Computer Management** as an administrator.
2. Navigate to **Local Users and Groups** > **Groups** > **docker-users**.
3. Right-click to add the user to the group.
4. Sign out and sign back in for the changes to take effect


---

# Uninstall Docker Desktop

*Sección: Desktop*

> [!WARNING]
>
> Uninstalling Docker Desktop destroys Docker containers, images, volumes, and
> other Docker-related data local to the machine, and removes the files generated
> by the application. To preserve important data before uninstalling, refer to the [back up and restore data](settings-and-maintenance/backup-and-restore.md) section.

{{< tabs >}}
{{< tab name="Windows" >}}

#### From the GUI

1. From the Windows **Start** menu, select **Settings** > **Apps** > **Apps & features**.
2. Select **Docker Desktop** from the **Apps & features** list and then select **Uninstall**.
3. Select **Uninstall** to confirm your selection.

#### From the CLI

1. Locate the installer:
   ```console
   # all-user installation
   $ C:\Program Files\Docker\Docker\Docker Desktop Installer.exe

   # per-user installation (Beta)
   $ %LOCALAPPDATA%\Programs\DockerDesktop\Docker Desktop Installer.exe
   ```
2. Uninstall Docker Desktop. 
 - In PowerShell, run:
    ```console
    $ Start-Process 'Docker Desktop Installer.exe' -Wait uninstall
    ```
 - In the Command Prompt, run:
    ```console
    $ start /w "" "Docker Desktop Installer.exe" uninstall
    ```

After uninstalling Docker Desktop, some residual files may remain which you can remove manually. These are:

```console
C:\ProgramData\Docker
C:\ProgramData\DockerDesktop
C:\Program Files\Docker
C:\Users\<your user name>\AppData\Local\Docker
C:\Users\<your user name>\AppData\Roaming\Docker
C:\Users\<your user name>\AppData\Roaming\Docker Desktop
C:\Users\<your user name>\.docker
```
 
{{< /tab >}}
{{< tab name="Mac" >}}

#### From the GUI

1. Open Docker Desktop. 
2. In the top-right corner of the Docker Desktop Dashboard, select the **Troubleshoot** icon.
3. Select **Uninstall**.
4. When prompted, confirm by selecting **Uninstall** again.

You can then move the Docker application to the trash. 

#### From the CLI

Run:

```console
$ /Applications/Docker.app/Contents/MacOS/uninstall
```

You can then move the Docker application to the trash. 

> [!NOTE]
> You may encounter the following error when uninstalling Docker Desktop using the uninstall command.
>
> ```console
> $ /Applications/Docker.app/Contents/MacOS/uninstall
> Password:
> Uninstalling Docker Desktop...
> Error: unlinkat /Users/<USER_HOME>/Library/Containers/com.docker.docker/.com.apple.containermanagerd.metadata.plist: > operation not permitted
> ```
>
> The operation not permitted error is reported either on the file `.com.apple.containermanagerd.metadata.plist` or on the parent directory `/Users/<USER_HOME>/Library/Containers/com.docker.docker/`. This error can be ignored as you have successfully uninstalled Docker Desktop.
> You can remove the directory `/Users/<USER_HOME>/Library/Containers/com.docker.docker/` later by allowing **Full Disk Access** to the terminal application you are using (**System Settings** > **Privacy & Security** > **Full Disk Access**).

After uninstalling Docker Desktop, some residual files may remain which you can remove:

```console
$ rm -rf ~/Library/Group\ Containers/group.com.docker
$ rm -rf ~/.docker
```

{{< /tab >}}
{{< tab name="Ubuntu" >}}

To uninstall Docker Desktop for Ubuntu:

1. Remove the Docker Desktop application. Run:

   ```console
   $ sudo apt remove docker-desktop
   ```

   This removes the Docker Desktop package itself but doesn’t delete all of its files or settings.

2. Manually remove leftover file.

   ```console
   $ rm -r $HOME/.docker/desktop
   $ sudo rm /usr/local/bin/com.docker.cli
   $ sudo apt purge docker-desktop
   ```

   This removes configuration and data files at `$HOME/.docker/desktop`, the symlink at `/usr/local/bin/com.docker.cli`, and purges the remaining systemd service files.

3. Clean up Docker config settings. In `$HOME/.docker/config.json`, remove the `credsStore` and `currentContext` properties.

   These entries tell Docker where to store credentials and which context is active. If they remain after uninstalling Docker Desktop, they may conflict with a future Docker setup.

{{< /tab >}}
{{< tab name="Debian" >}}

To uninstall Docker Desktop for Debian, run:

1. Remove the Docker Desktop application:

   ```console
   $ sudo apt remove docker-desktop
   ```

   This removes the Docker Desktop package itself but doesn’t delete all of its files or settings.

2. Manually remove leftover file.

   ```console
   $ rm -r $HOME/.docker/desktop
   $ sudo rm /usr/local/bin/com.docker.cli
   $ sudo apt purge docker-desktop
   ```

   This removes configuration and data files at `$HOME/.docker/desktop`, the symlink at `/usr/local/bin/com.docker.cli`, and purges the remaining systemd service files.

3. Clean up Docker config settings. In `$HOME/.docker/config.json`, remove the `credsStore` and `currentContext` properties.

   These entries tell Docker where to store credentials and which context is active. If they remain after uninstalling Docker Desktop, they may conflict with a future Docker setup.

{{< /tab >}}
{{< tab name="Fedora" >}}

To uninstall Docker Desktop for Fedora:

1. Remove the Docker Desktop application. Run:

   ```console
   $ sudo dnf remove docker-desktop
   ```

   This removes the Docker Desktop package itself but doesn’t delete all of its files or settings.

2. Manually remove leftover file.

   ```console
   $ rm -r $HOME/.docker/desktop
   $ sudo rm /usr/local/bin/com.docker.cli
   $ sudo dnf remove docker-desktop
   ```

   This removes configuration and data files at `$HOME/.docker/desktop`, the symlink at `/usr/local/bin/com.docker.cli`, and purges the remaining systemd service files.

3. Clean up Docker config settings. In `$HOME/.docker/config.json`, remove the `credsStore` and `currentContext` properties.

   These entries tell Docker where to store credentials and which context is active. If they remain after uninstalling Docker Desktop, they may conflict with a future Docker setup.

{{< /tab >}}
{{< tab name="Arch" >}}

To uninstall Docker Desktop for Arch:

1. Remove the Docker Desktop application. Run:

   ```console
   $ sudo pacman -Rns docker-desktop
   ```

   This removes the Docker Desktop package along with its configuration files and dependencies not required by other packages.

2. Manually remove leftover files.

   ```console
   $ rm -r $HOME/.docker/desktop
   ```

   This removes configuration and data files at `$HOME/.docker/desktop`.

3. Clean up Docker config settings. In `$HOME/.docker/config.json`, remove the `credsStore` and `currentContext` properties.

   These entries tell Docker where to store credentials and which context is active. If they remain after uninstalling Docker Desktop, they may conflict with a future Docker setup.

{{< /tab >}}
{{< /tabs >}}


---

# Explore Docker Desktop

*Sección: Desktop*

When you open Docker Desktop, the Docker Desktop Dashboard displays.

It provides a centralized interface to manage your [containers](container.md), [images](images.md), [volumes](volumes.md), [builds](builds.md), [Kubernetes resources](kubernetes.md), and [logs](logs.md).

In addition, the Docker Desktop Dashboard lets you:

- Use [Gordon](../../ai/gordon/index.md), a personal AI assistant embedded in Docker Desktop and the Docker CLI. It's designed to streamline your workflow and help you make the most of the Docker ecosystem.
- Navigate to the **Settings** menu to configure your Docker Desktop settings. Select the **Settings** icon in the Dashboard header.
- Access the **Troubleshoot** menu to debug and perform restart operations. Select the **Troubleshoot** icon in the Dashboard header.
- Be notified of new releases, installation progress updates, and more in the **Notifications center**. Select the bell icon in the bottom-right corner of the Docker Desktop Dashboard to access the notification center.
- Access the **Learning center** from the Dashboard header. It helps you get started with quick in-app walkthroughs and provides other resources for learning about Docker. 

  For a guided introduction, see
  [Build and share a containerized application](/get-started/tutorials/run-an-app.md).
- Access [Docker Hub](../../docker-hub/index.md) to search, browse, pull, run, or view details
  of images.
- Navigate to [Docker Extensions](../../extensions/index.md) if you have enabled it.

> [!TIP]
>
> You can customize the left-hand navigation to show only the tabs that matter to you, and hide the ones that don’t. Right-click the left-hand navigation, select **Customize**, and then select, deselect, or re-order the tabs.

## Docker terminal

From the Docker Dashboard footer, you can use the integrated terminal directly within Docker Desktop. 

The integrated terminal:

- Persists your session if you navigate to another
  part of the Docker Desktop Dashboard and then return.
- Supports copy, paste, search, and clearing your session.

#### Open the integrated terminal

To open the integrated terminal, either:

- Hover over your running container and under the **Actions** column, select the **Show container actions**
  menu. From the drop-down menu, select **Open in terminal**.
- Or, select the **Terminal** icon located in the bottom-right corner, next to the version number.

To use your external terminal, navigate to the **General** tab in **Settings**
and select the **System default** option under **Choose your terminal**.

## Quick search

Use Quick Search, which is located in the Docker Dashboard header, to search for:

- Any container or Compose application on your local system. You can see an overview of associated environment variables or perform quick actions, such as start, stop, or delete.

- Public Docker Hub images, local images, and images from remote repositories (private repositories from organizations you're a part of in Hub). Depending on the type of image you select, you can either pull the image by tag, view documentation, go to Docker Hub for more details, or run a new container using the image.

- Extensions. From here, you can learn more about the extension and install it with a single click. Or, if you already have an extension installed, you can open it straight from the search results.

- Any volume. From here you can view the associated container.

- Docs. Find help from Docker's official documentation straight from Docker Desktop. 

## The Docker menu

Docker Desktop also includes a tray icon, referred to as the Docker menu {{< inline-image src="../../assets/images/whale-x.svg" alt="whale menu" >}} for quick access.

Select the {{< inline-image src="../../assets/images/whale-x.svg" alt="whale menu" >}} icon in your taskbar to open options such as:

- **Dashboard**. This takes you to the Docker Desktop Dashboard.
- **Sign in/Sign up**
- **Settings**
- **Check for updates**
- **Troubleshoot**
- **Give feedback**
- **Switch to Windows containers** (if you're on Windows)
- **About Docker Desktop**. Contains information on the versions you are running, and links to the Subscription Service Agreement for example.
- **Docker Hub**
- **Documentation**
- **Extensions**
- **Kubernetes**
- **Restart**
- **Quit Docker Desktop**


---

# Explore the Builds view in Docker Desktop

*Sección: Desktop*

The **Builds** view provides an interactive interface for inspecting build history, monitoring active builds, and managing builders directly in Docker Desktop.

By default, the **Build history** tab displays a list of completed builds, sorted by date (newest first). Switch to the **Active builds** tab to view ongoing builds.

If you're connected to a cloud builder through [Docker Build Cloud](../../build-cloud/index.md),
the Builds view also lists any active or completed cloud builds by other team members
connected to the same cloud builder.

> [!NOTE]
>
> Windows container image builds use the legacy builder and do not appear in the **Builds** view. Only BuildKit-powered builds are shown here.

## Show build list

Open the **Builds** view from the Docker Dashboard to access:

- **Build history**: Completed builds with access to logs, dependencies, traces, and more
- **Active builds**: Builds currently in progress

Only builds from active, running builders are listed. Builds from removed or stopped builders are not shown.

### Builder settings

The top-right corner shows the name of your currently selected builder, and the
**Builder settings** button lets you [manage builders](#manage-builders) in the
Docker Desktop settings.

### Import builds

The **Import builds** button lets you import build records for builds by other
people, or builds in a CI environment. When you've imported a build record, it
gives you full access to the logs, traces, and other data for that build,
directly in Docker Desktop. 

The [build summary](../../build/ci/github-actions/build-summary.md)
for the `docker/build-push-action` and `docker/bake-action` GitHub Actions
includes a link to download the build records, for inspecting CI jobs with
Docker Desktop.

## Inspect builds

To inspect a build, select the build that you want to view in the list.
The inspection view contains a number of tabs.

The **Info** tab displays details about the build.

If you're inspecting a multi-platform build, the drop-down menu in the
top-right of this tab lets you filter the information down to a specific
platform:

The **Source details** section shows information about the frontend
[frontend](../../build/buildkit/frontend.md) and, if available,
the source code repository used for the build.

### Build timing

The **Build timing** section of the Info tab contains charts
showing a breakdown of the build execution from various angles.

- **Real time** refers to the wall-clock time that it took to complete the build.
- **Accumulated time** shows the total CPU time for all steps.
- **Cache usage** shows the extent to which build operations were cached.
- **Parallel execution** shows how much of the build execution time was spent running steps in parallel.

The chart colors and legend keys describe the different build operations. Build
operations are defined as follows:

| Build operation      | Description                                                                                                                                                                     |
| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Local file transfers | Time spent transferring local files from the client to the builder.                                                                                                             |
| File operations      | Any operations that involve creating and copying files in the build. For example, the `COPY`, `WORKDIR`, `ADD` instructions in a Dockerfile frontend all incur file operations. |
| Image pulls          | Time spent pulling images.                                                                                                                                                      |
| Executions           | Container executions, for example commands defined as `RUN` instructions in a Dockerfile frontend.                                                                              |
| HTTP                 | Remote artifact downloads using `ADD`.                                                                                                                                          |
| Git                  | Same as **HTTP** but for Git URLs.                                                                                                                                              |
| Result exports       | Time spent exporting the build results.                                                                                                                                         |
| SBOM                 | Time spent generating the [SBOM attestation](../../build/metadata/attestations/sbom.md).                                                                                                 |
| Idle                 | Idle time for build workers, which can happen if you have configured a [max parallelism limit](../../build/buildkit/configure.md#max-parallelism).                              |

### Build dependencies

The **Dependencies** section shows images and remote resources used during
the build. Resources listed here include:

- Container images used during the build
- Git repositories included using the `ADD` Dockerfile instruction
- Remote HTTPS resources included using the `ADD` Dockerfile instruction

### Arguments, secrets, and other parameters

The **Configuration** section of the Info tab shows parameters passed to the build:

- Build arguments, including the resolved value
- Secrets, including their IDs (but not their values)
- SSH sockets
- Labels
- [Additional contexts](/reference/cli/docker/buildx/build/#build-context)

### Outputs and artifacts

The **Build results** section shows a summary of the generated build artifacts,
including image manifest details, attestations, and build traces.

Attestations are metadata records attached to a container image.
The metadata describes something about the image,
for example how it was built or what packages it contains.
For more information about attestations, see [Build attestations](../../build/metadata/attestations/index.md).

Build traces capture information about the build execution steps in Buildx and
BuildKit. The traces are available in two formats: OTLP and Jaeger. You can
download build traces from Docker Desktop by opening the actions menu and
selecting the format you want to download.

#### Inspect build traces with Jaeger

Using a Jaeger client, you can import and inspect build traces from Docker
Desktop. The following steps show you how to export a trace from Docker Desktop
and view it in [Jaeger](https://www.jaegertracing.io/):

1. Start Jaeger UI:

   ```console
   $ docker run -d --name jaeger -p "16686:16686" jaegertracing/all-in-one
   ```

2. Open the Builds view in Docker Desktop, and select a completed build.

3. Navigate to the **Build results** section, open the actions menu and select **Download as Jaeger format**.

   <video controls>
     <source src="/assets/video/build-jaeger-export.mp4" type="video/mp4" />
   </video>

4. Go to <http://localhost:16686> in your browser to open Jaeger UI.

5. Select the **Upload** tab and open the Jaeger build trace you just exported.

Now you can analyze the build trace using the Jaeger UI:

![Jaeger UI screenshot](../images/build-ui-jaeger-screenshot.png "Screenshot of a build trace in the Jaeger UI")

### Dockerfile source and errors

When inspecting a successful completed build or an ongoing active build,
the **Source** tab shows the [frontend](../../build/buildkit/frontend.md)
used to create the build.

If the build failed, an **Error** tab displays instead of the **Source** tab.
The error message is inlined in the Dockerfile source,
indicating where the failure happened and why.

### Build logs

The **Logs** tab displays the build logs.
For active builds, the logs are updated in real-time.

You can toggle between a **List view** and a **Plain-text view** of a build log.

- The **List view** presents all build steps in a collapsible format,
  with a timeline for navigating the log along a time axis.

- The **Plain-text view** displays the log as plain text.

The **Copy** button lets you copy the plain-text version of the log to your clipboard.

### Build history

The **History** tab displays statistics data about completed builds.

The time series chart illustrates trends in duration, build steps, and cache usage for related builds,
helping you identify patterns and shifts in build operations over time.
For instance, significant spikes in build duration or a high number of cache misses
could signal opportunities for optimizing the Dockerfile.

You can navigate to and inspect a related build by selecting it in the chart,
or using the **Past builds** list below the chart.

## Manage builders

The **Builder** tab in **Settings** lets you:

- Inspect the state and configuration of active builders
- Start and stop a builder
- Delete build history
- Add or remove builders (or connect and disconnect, in the case of cloud builders)

For more information about managing builders, see [Change settings](../settings-and-maintenance/settings.md#builders)


---

# Explore the Containers view in Docker Desktop

*Sección: Desktop*

The **Containers** view lists all running and stopped containers and applications. It provides a clean interface to manage the lifecycle of your containers, interact with running applications, and inspect Docker objects—including Docker Compose apps.

## Container actions

Use the **Search** field to find a specific container by name.

From the **Containers** view you can:
- Start, stop, pause, resume, or restart containers
- View image packages and CVEs
- Delete containers
- Open the application in VS code
- Open the port exposed by the container in a browser
- Copy the `docker run` command for reuse or modification
- Use [Docker Debug](#execdebug)

## Resource usage

From the **Containers** view you can monitor your containers' CPU and memory usage over time. This can help you understand if something is wrong with your containers or if you need to allocate additional resources. 

When you [inspect a container](#inspect-a-container), the **Stats** tab displays further information about a container's resource utilization. You can see how much CPU, memory, network and disk space your container is using over time.

## Inspect a container

You can obtain detailed information about the container when you select it.

From here, you can use the quick action buttons to perform various actions such as pause, resume, start or stop, or explore the **Logs**, **Inspect**, **Bind mounts**, **Debug**, **Files**, and **Stats** tabs. 

### Logs

Select **Logs** to view output from the container in real time. While viewing logs, you can:

- Use `Cmd + f`/`Ctrl + f` to open the search bar and find specific entries.
  Search matches are highlighted in yellow.
- Press `Enter` or `Shift + Enter` to jump to the next or previous search match
  respectively. 
- Use the **Copy** icon in the top right-hand corner to copy all the logs to
  your clipboard.
- Show timestamps
- Use the **Clear terminal** icon in the top right-hand corner to clear the
  logs terminal. 
- Select and view external links that may be in your logs. 

You can refine your view by:

- Filtering logs for specific containers, if you're running a multi-container application.
- Using regular expressions or exact match search terms

### Inspect

Select **Inspect** to view low-level information about the container. It displays the local path, version number of the image, SHA-256, port mapping, and other details.

### Exec/Debug

If you have not enabled Docker Debug in settings, the **Exec** tab displays. It lets you quickly run commands within your running container.

Using the **Exec** tab is the same as running one of the following commands:

- `docker exec -it <container-id> /bin/sh`
- `docker exec -it <container-id> cmd.exe` when accessing Windows containers

For more details, see the [`docker exec` CLI reference](/reference/cli/docker/container/exec/).

If you have enabled Docker Debug in settings, or toggled on **Debug mode** to the right of the tab options, the **Debug** tab displays. 

Debug mode has several advantages, such as:

- A customizable toolbox. The toolbox comes with many standard Linux tools
  pre-installed, such as `vim`, `nano`, `htop`, and `curl`. For more details, see the [`docker debug` CLI reference](/reference/cli/docker/debug/).
- The ability to access containers that don't have a shell, for example, slim or
  distroless containers.

To use debug mode:

- Hover over your running container and under the **Actions** column, select the **Show container actions**
menu. From the drop-down menu, select **Use Docker Debug**.
- Or, select the container and then select the **Debug** tab. 

To use debug mode by default, navigate to
the **General** tab in **Settings** and select the **Enable Docker Debug by
default** option.

### Files

Select **Files** to explore the filesystem of running or stopped containers. You
can also:

- See which files have been recently added, modified, or deleted
- Edit a file straight from the built-in editor
- Drag and drop files and folders between the host and the container
- Delete unnecessary files when you right-click on a file
- Download files and folders from the container straight to the host

## Additional resources

- [What is a container](/get-started/docker-concepts/the-basics/what-is-a-container.md)
- [Run multi-container applications](/get-started/docker-concepts/running-containers/multi-container-applications.md)


---

# Explore the Images view in Docker Desktop

*Sección: Desktop*

The **Images** view displays a list of your Docker images and allows you to run an image as a container, pull the latest version of an image from Docker Hub, and inspect images. It also displays a summary of image vulnerabilities. In addition, the **Images** view contains clean-up options to remove unwanted images from the disk to reclaim space. If you are logged in, you can also see the images you and your organization have shared on Docker Hub. For more information, see [Explore your images](images.md).

The **Images** view lets you manage Docker images without having to use the CLI. By default, it displays a list of all Docker images on your local disk. 

You can also view Hub images once you have signed in to Docker Hub. This allows you to collaborate with your team and manage your images directly through Docker Desktop.

The **Images** view lets you perform core operations such as running an image as a container, pulling the latest version of an image from Docker Hub, pushing the image to Docker Hub, and inspecting images.

It also displays metadata about the image such as the:
- Tag
- Image ID
- Date created
- Size of the image.

An **In Use** tag displays next to images used by running and stopped containers. You can choose what information you want displayed by selecting the **More options** menu to the right of the search bar, and then use the toggle switches according to your preferences. 

The **Images on disk** status bar displays the number of images and the total disk space used by the images and when this information was last refreshed.

## Manage your images

Use the **Search** field to search for any specific image.

You can sort images by:

- In use
- Unused
- Dangling

## Run an image as a container

From the **Images view**, hover over an image and select **Run**.

When prompted you can either:

- Select the **Optional settings** drop-down to specify a name, port, volumes, environment variables and select **Run**
- Select **Run** without specifying any optional settings.

## Inspect an image

To inspect an image, select the image row. Inspecting an image displays detailed information about the image such as the:

- Image history
- Image ID
- Date the image was created
- Size of the image
- Layers making up the image
- Base images used
- Vulnerabilities found
- Packages inside the image

[Docker Scout](../../scout/index.md) powers this vulnerability information.
For more information about this view, see [Image details view](../../scout/explore/image-details-view.md)

## Pull the latest image from Docker Hub

Select the image from the list, select the **More options** button and select **Pull**.

> [!NOTE]
>
> The repository must exist on Docker Hub in order to pull the latest version of an image. You must be signed in to pull private images.

## Push an image to Docker Hub

Select the image from the list, select the **More options** button and select **Push to Hub**.

> [!NOTE]
>
> You can only push an image to Docker Hub if the image belongs to your Docker ID or your organization. That is, the image must contain the correct username/organization in its tag to be able to push it to Docker Hub.

## Remove an image

> [!NOTE]
>
> To remove an image used by a running or a stopped container, you must first remove the associated container.

An unused image is an image which is not used by any running or stopped containers. An image becomes dangling when you build a new version of the image with the same tag.

To remove individual images, select the bin icon. 

## Docker Hub repositories

The **Images** view also allows you to manage and interact with images in Docker Hub repositories.
By default, when you go to **Images** in Docker Desktop, you see a list of images that exist in your local image store.
The **Local** and **Docker Hub repositories** tabs near the top toggles between viewing images in your local image store,
and images in remote Docker Hub repositories that you have access to.

Switching to the **Docker Hub repositories** tab prompts you to sign in to your Docker Hub account, if you're not already signed in.
When signed in, it shows you a list of images in Docker Hub organizations and repositories that you have access to.

Select an organization from the drop-down to view a list of repositories for that organization.

If you have enabled [Docker Scout](../../scout/index.md) on the repositories,
image analysis results appear next to the image tags.

Hovering over an image tag reveals two options:

- **Pull**: Pull the latest version of the image from Docker Hub.
- **View in Hub**: Open the Docker Hub page and display detailed information about the image.

## Additional resources

- [What is an image?](/get-started/docker-concepts/the-basics/what-is-an-image.md)


---

# Explore the Kubernetes view

*Sección: Desktop*

Docker Desktop includes a standalone Kubernetes server and client, as well as Docker CLI integration, enabling local Kubernetes development and testing directly on your machine.

The Kubernetes server runs as a single or multi-node cluster, within Docker containers. This lightweight setup helps you explore Kubernetes features, test workloads, and work with container orchestration in parallel with other Docker features.

## Enable Kubernetes

With Docker Desktop version 4.51 and later, you can manage Kubernetes directly from the **Kubernetes** view in the Docker Desktop Dashboard.

1. Open the Docker Desktop Dashboard and select the **Kubernetes** view. 
2. Select **Create cluster**.
3. Choose your cluster type:
   - **Kubeadm** creates a single-node cluster and the version is set by Docker Desktop.
   - **kind** creates a multi-node cluster and you can set the version and number of nodes.
   For more detailed information on each cluster type, see [Cluster provisioning method](#cluster-provisioning-method).
4. Optional: Select **Show system containers (advanced)** to view internal containers when using Docker commands.
5. Select **Create**. 

This sets up the images required to run the Kubernetes server as containers, and installs the `kubectl` command-line tool on your system at `/usr/local/bin/kubectl` (Mac) or `C:\Program Files\Docker\Docker\resources\bin\kubectl.exe`(all-user installations) or `%LOCALAPPDATA%\Programs\DockerDesktop\resources\bin\kubectl.exe` (per-user installations) (Windows). If you installed `kubectl` using Homebrew, or by some other method, and experience conflicts, remove `/usr/local/bin/kubectl`.

   > [!NOTE]
   >
   > Docker Desktop for Linux does not include `kubectl` by default. You can install it separately by following the [Kubernetes installation guide](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/). Ensure the `kubectl` binary is installed at `/usr/local/bin/kubectl`.

The following actions are also triggered in the Docker Desktop backend and VM:

- Generation of certificates and cluster configuration
- Download and installation of Kubernetes internal components
- Cluster boot-up
- Installation of additional controllers for networking and storage

When Kubernetes is enabled, its status is displayed in the Docker Desktop Dashboard footer and the Docker menu.

You can check which version of Kubernetes you're on with:

```console
$ kubectl version
```

### Cluster provisioning method

Docker Desktop Kubernetes can be provisioned with either the `kubeadm` or `kind`
provisioners.

`kubeadm` is the older provisioner. It supports a single-node cluster, you can't select the kubernetes
version, it's slower to provision than `kind`, and it's not supported by [Enhanced Container Isolation](../../reference/api/ai-governance/index.md) (ECI),
meaning that if ECI is enabled the cluster works but it's not protected by ECI.

`kind` is the newer provisioner. It supports multi-node clusters (for
a more realistic Kubernetes setup), you can choose the Kubernetes version, it's
faster to provision than `kubeadm`, and it's supported by ECI - when ECI is
enabled, the Kubernetes cluster runs in unprivileged Docker containers, thus
making it more secure. 

| Feature | `kubeadm` | `kind` |
| :------ | :-----: | :--: |
| Multi-node cluster support | No | Yes |
| Kubernetes version selector | No | Yes |
| Speed to provision | ~1 min | ~30 seconds |
| Supported by ECI | No | Yes |
| Works with containerd image store | Yes | Yes |
| Works with Docker image store | Yes | No |

## Dashboard view

When a Kubernetes cluster is enabled, the **Kubernetes** view displays a live dashboard view showing:

- A namespace selector at the top
- A real-time list of resources - pods, services, deployments - in the selected namespace
- Automatic updates when resources are created, deleted, or modified

## Verify installation

Confirm that your cluster is running:

```console
$ kubectl get nodes
NAME                 STATUS    ROLES            AGE       VERSION
docker-desktop       Ready     control-plane    3h        v1.29.1
```

If kubectl is pointing to another environment, switch to the Docker Desktop context:

```console
$ kubectl config use-context docker-desktop
```

>[!TIP]
>
> If no contexts appear, try:
>
> - Running the command in the Command Prompt or PowerShell.
> - Setting the `KUBECONFIG` environment variable to point to your `.kube/config` file.


For more information about `kubectl`, see the
[`kubectl` documentation](https://kubernetes.io/docs/reference/kubectl/overview/).

## Edit or stop your cluster

When Kubernetes is enabled:

- Select **Edit cluster** to modify configuration. For example, switch between **kubeadm** and **kind**, or change the number of nodes.
- Select **Stop** to disable the cluster. Progress is displayed, and the **Kubernetes** view returns to the **Create cluster** screen. This stops and removes Kubernetes containers, and also removes the `/usr/local/bin/kubectl` command.

## Upgrade your cluster

Kubernetes clusters are not automatically upgraded with Docker Desktop updates. To upgrade the cluster, you must manually select **Reset cluster** in the **Kubernetes** settings.

## Configuring a custom image registry for Kubernetes control plane images

Docker Desktop uses containers to run the Kubernetes control plane. By default, Docker Desktop pulls
the associated container images from Docker Hub. The images pulled depend on the [cluster provisioning mode](#cluster-provisioning-method).

For example, in `kind` mode it requires the following images:

```console
docker.io/kindest/node:<tag>
docker.io/envoyproxy/envoy:<tag>
docker.io/docker/desktop-cloud-provider-kind:<tag>
docker.io/docker/desktop-containerd-registry-mirror:<tag>
```

In `kubeadm` mode it requires the following images:

```console
docker.io/docker/desktop-kubernetes:<tag>
docker.io/docker/desktop-storage-provisioner:<tag>
docker.io/docker/desktop-vpnkit-controller:<tag>
docker.io/docker/desktop-kubernetes-etcd:<tag>
docker.io/docker/desktop-kubernetes-coredns:<tag>
docker.io/docker/desktop-kubernetes-pause:<tag>
docker.io/docker/desktop-kubernetes-apiserver:<tag>
docker.io/docker/desktop-kubernetes-controller-manager:<tag>
docker.io/docker/desktop-kubernetes-scheduler:<tag>
docker.io/docker/desktop-kubernetes-proxy:<tag>
```

The image tags are automatically selected by Docker Desktop based on several
factors, including the version of Kubernetes being used. The tags vary for each image and may change between Docker Desktop releases. To stay informed, monitor the Docker Desktop release notes.

> [!NOTE]
>
> In Docker Desktop versions 4.44 or later you can run `docker desktop kubernetes images list` to list Kubernetes images used by the currently installed version of Docker Desktop.
> For more information, see the [Docker Desktop CLI](/reference/cli/docker/desktop/kubernetes/images).

To accommodate scenarios where access to Docker Hub is not allowed, admins can
configure Docker Desktop to pull the above listed images from a different registry (e.g., a mirror)
using the [KubernetesImagesRepository](../../enterprise/security/hardened-desktop/settings-management/configure-json-file.md#kubernetes) setting as follows.

An image name can be broken into `[registry[:port]/][namespace/]repository[:tag]` components.
The `KubernetesImagesRepository` setting allows users to override the `[registry[:port]/][namespace]`
portion of the image's name.

For example, if Docker Desktop Kubernetes is configured in `kind` mode and
`KubernetesImagesRepository` is set to `my-registry:5000/kind-images`, then
Docker Desktop will pull the images from:

```console
my-registry:5000/kind-images/node:<tag>
my-registry:5000/kind-images/envoy:<tag>
my-registry:5000/kind-images/desktop-cloud-provider-kind:<tag>
my-registry:5000/kind-images/desktop-containerd-registry-mirror:<tag>
```

These images should be cloned/mirrored from their respective images in Docker Hub. The tags must
also match what Docker Desktop expects.

The recommended approach to set this up is the following:

1. Start Kubernetes using the desired cluster provisioning method: `kubeadm` or `kind`.
2. After Kubernetes has started, use either:
   - (Docker Desktop version 4.44 or later) `docker desktop kubernetes images list` to list the image tags that will be pulled by the current Docker Desktop installation
   - `docker ps` to view the container images used by Docker Desktop for the Kubernetes control plane
3. Clone or mirror those images (with matching tags) to your custom registry.
4. Stop the Kubernetes cluster.
5. Configure the `KubernetesImagesRepository` setting to point to your custom registry.
6. Restart Docker Desktop.
7. Verify that the Kubernetes cluster is using the custom registry images using the `docker ps` command.

> [!NOTE]
>
> The `KubernetesImagesRepository` setting only applies to control plane images used by Docker Desktop
> to set up the Kubernetes cluster. It has no effect on other Kubernetes pods.

> [!NOTE]
>
> In Docker Desktop versions 4.43 or earlier, when using `KubernetesImagesRepository` and [Enhanced Container Isolation (ECI)](../../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md)
> is enabled, add the following images to the [ECI Docker socket mount image list](../../enterprise/security/hardened-desktop/settings-management/configure-json-file.md#enhanced-container-isolation):
>
> `[imagesRepository]/desktop-cloud-provider-kind:`
> `[imagesRepository]/desktop-containerd-registry-mirror:`
>
> These containers mount the Docker socket, so you must add the images to the ECI images list. If not,
> ECI will block the mount and Kubernetes won't start.

## Troubleshooting

- If Kubernetes fails to start, make sure Docker Desktop is running with enough allocated resources. Check **Settings** > **Resources**.
- If the `kubectl` commands return errors, confirm the context is set to `docker-desktop`
   ```console
   $ kubectl config use-context docker-desktop
   ```
   You can then try checking the logs of the Kubernetes system containers if you have enabled that setting.
- If you're experiencing cluster issues after updating, reset your Kubernetes cluster. Resetting a Kubernetes cluster can help resolve issues by essentially reverting the cluster to a clean state, and clearing out misconfigurations, corrupted data, or stuck resources that may be causing problems. If the issue still persists, you may need to clean and purge data, and then restart Docker Desktop.


---

# Explore the Logs view in Docker Desktop

*Sección: Desktop*

{{< summary-bar feature_name="Desktop logs" >}}

The **Logs** view provides a unified, real-time log stream from all containers and recent builds in Docker Desktop. Unlike the logs accessible from the [**Containers** view](container.md), the **Logs** view lets you monitor and search log output (up to a maximum of 100 000 entries) across your entire environment from a single interface. 

## Log entries

Each log entry in the table view shows:

| Column        | Description                                                                    |
| ------------- | ------------------------------------------------------------------------------ |
| **Timestamp** | The date and time the log line was emitted, for example `2026-02-26 11:18:53`. |
| **Object**    | The container or build that produced the log line.                             |
| **Message**   | The full log message, including any status codes such as `[ OK ]`.             |

Selecting the expand arrow to the right of a row reveals the full message for that entry.

## Search, filter, and export logs

Use the **Search** field at the top of the Logs view to find specific entries. The search bar supports:

- Plain-text terms for exact match searches
- Regular expressions (for example, `/error|warn/`)

You can save your current filters as a preset for easy access later. Presets capture your container selection, build log visibility, and case sensitivity settings, as well as any active search terms. If no containers are selected, the preset is named all; otherwise it is named after the first selected container.

To refine the log stream further, select the **Filter** icon in the toolbar to open the container filter panel. From here you can:

- Check individual containers to show only their output
- Check Compose stacks to show or hide entire groups
- Toggle off **View build logs** to exclude build-related log output in the stream
- Use **Select all** or **Clear container filters** to quickly toggle every container at once

Use the **Export** button in the top-right corner (available with Docker Desktop version 4.77 and later) to export all logs or only the logs that match your filters.

## Display settings

Select the **Display settings** icon in the toolbar to toggle the following:
- **Wrap lines**
- **Show timestamps**

You can also choose **Clear logs** to remove log entries from the view (available with Docker Desktop 4.79 and later). A dialog lets you choose between two options:

- **Clear all logs**: Immediately hides all current log entries.
- **Clear logs before**: Activates a date and time picker. Only entries at or before the selected timestamp are hidden.

The cleared state persists across Docker Desktop restarts. Once entries are cleared, they cannot be restored.

## Feedback

Select **Give feedback** at the top of the view to share suggestions or report issues.


---

# Pause Docker Desktop

*Sección: Desktop*

Pausing Docker Desktop temporarily suspends the Linux VM running Docker Engine. This saves the current state of all containers in memory and freezes all running processes, significantly reducing CPU and memory usage which is helpful for conserving battery on laptops.

To pause Docker Desktop, select the **Pause** icon to the left of the footer in the Docker Dashboard. To manually resume Docker Desktop, select the **Resume** option in the Docker menu, or run any Docker CLI command.

When you manually pause Docker Desktop, a paused status displays on the Docker menu and on the Docker Desktop Dashboard. You can still access the **Settings** and the **Troubleshoot** menu.

> [!TIP]
>
> The Resource Saver feature is enabled by default and provides better CPU and memory savings than the manual Pause feature. See [Resource Saver mode](resource-saver.md) for more info.


---

# Docker Desktop's Resource Saver mode

*Sección: Desktop*

Resource Saver mode significantly reduces Docker
Desktop's CPU and memory utilization on the host by 2 GBs or more, by
automatically stopping the Docker Desktop Linux VM when no containers are
running for a period of time. The default time is set to 5 minutes, but this can be adjusted to suit your needs.

With Resource Saver mode, Docker Desktop uses minimal system resources when it's idle, thereby
allowing you to save battery life on your laptop and improve your multi-tasking
experience.

## Configure Resource Saver 

Resource Saver is enabled by default but can be disabled by navigating to the **Resources** tab, in **Settings**. You can also configure the idle
timer as shown below.

![Resource Saver Settings](../images/resource-saver-settings.webp) 

If the values available aren't sufficient for your
needs, you can reconfigure it to any value, as long as the value is larger than 30 seconds, by
changing `autoPauseTimeoutSeconds` in the Docker Desktop `settings-store.json` file (or `settings.json` for Docker Desktop versions 4.34 and earlier): 

  - Mac: `~/Library/Group Containers/group.com.docker/settings-store.json`
  - Windows: `C:\Users\[USERNAME]\AppData\Roaming\Docker\settings-store.json`
  - Linux: `~/.docker/desktop/settings-store.json`

There's no need to restart Docker Desktop after reconfiguring. 

When Docker Desktop enters Resource Saver mode: 
- A moon icon displays on the
Docker Desktop status bar as well as on the Docker icon in
the system tray. 
- Docker commands that don't run containers, for example listing container images or volumes, don't necessarily trigger an exit from Resource Saver mode as Docker Desktop can serve such commands without unnecessarily waking up the Linux VM.

> [!NOTE]
>
> Docker Desktop exits the Resource Saver mode automatically when it needs to.
> Commands that cause an exit from Resource Saver take a little longer to execute
> (about 3 to 10 seconds) as Docker Desktop restarts the Linux VM.
> It's generally faster on Mac and Linux, and slower on Windows with Hyper-V.
> Once the Linux VM is restarted, subsequent container runs occur immediately as usual.

## Resource Saver mode versus Pause

Resource Saver has higher precedence than the older [Pause](pause.md) feature,
meaning that while Docker Desktop is in Resource Saver mode, manually pausing
Docker Desktop is not possible (nor does it make sense since Resource Saver
actually stops the Docker Desktop Linux VM). In general, we recommend keeping
Resource Saver enabled as opposed to disabling it and using the manual Pause
feature, as it results in much better CPU and memory savings.

## Resource Saver mode on Windows

Resource Saver works a bit differently on Windows with WSL. Instead of
stopping the WSL VM, it only pauses the Docker Engine inside the
`docker-desktop` WSL distribution. That's because in WSL there's a single Linux VM
shared by all WSL distributions, so Docker Desktop can't stop the Linux VM (i.e.,
the WSL Linux VM is not owned by Docker Desktop). As a result, Resource Saver
reduces CPU utilization on WSL, but it does not reduce Docker's memory
utilization. 

To reduce memory utilization on WSL, we instead recommend that
users enable WSL's `autoMemoryReclaim` feature as described in the
[Docker  Desktop WSL docs](../features/wsl/index.md). Finally, since Docker Desktop does not
stop the Linux VM on WSL, exit from Resource Saver mode is immediate (there's
no exit delay).


---

# Explore the Volumes view in Docker Desktop

*Sección: Desktop*

The **Volumes** view in Docker Desktop lets you create, inspect, delete, clone, empty, export, and import [Docker volumes](../../engine/storage/volumes.md). You can also browse files and folders in volumes and see which containers are using them.

## View your volumes

You can view the following information about your volumes:

- Name: The name of the volume.
- Status: Whether the volume is in-use by a container or not.
- Created: How long ago the volume was created.
- Size: The size of the volume.
- Scheduled exports: Whether a scheduled export is active or not.

By default, the **Volumes** view displays a list of all the volumes.

You can filter and sort volumes as well as modify which columns are displayed by
doing the following:

- Filter volumes by name: Use the **Search** field.
- Filter volumes by status: To the right of the search bar, filter volumes by
  **In use** or **Unused**.
- Sort volumes: Select a column name to sort the volumes.
- Customize columns: To the right of the search bar, choose what volume
  information to display.

## Create a volume

You use the following steps to create an empty volume. Alternatively, if you
[start a container with a volume](../../engine/storage/volumes.md#start-a-container-with-a-volume)
that doesn't yet exist, Docker creates the volume for you.

To create a volume:

1. In the **Volumes** view, select the **Create** button.
2. In the **New Volume** modal, specify a volume name, and then select
   **Create**.

To use the volume with a container, see [Use volumes](../../engine/storage/volumes.md#start-a-container-with-a-volume).

## Inspect a volume

To explore the details of a specific volume, select a volume from the list. This
opens the detailed view.

The **Container in-use** tab displays the name of the container using the
volume, the image name, the port number used by the container, and the target. A
target is a path inside a container that gives access to the files in the
volume.

The **Stored data** tab displays the files and folders in the volume and the
file size. To save a file or a folder, right-click on the file or folder to
display the options menu, select **Save as...**, and then specify a location to
download the file.

To delete a file or a folder from the volume, right-click on the file or folder
to display the options menu, select **Delete**, and then select **Delete** again
to confirm.

The **Exports** tab lets you [export the volume](#export-a-volume).

## Clone a volume

Cloning a volume creates a new volume with a copy of all of the data from the
cloned volume. When cloning a volume used by one or more running containers, the
containers are temporarily stopped while Docker clones the data, and then
restarted when the cloning process is completed.

To clone a volume:

1. Sign in to Docker Desktop. You must be signed in to clone a volume.
2. In the **Volumes** view, select the **Clone** icon in the **Actions** column
   for the volume you want to clone.
3. In the **Clone a volume** modal, specify a **Volume name**, and then select
   **Clone**.

## Delete one or more volumes

Deleting a volume deletes the volume and all its data. When a container is using
a volume, you can't delete the volume, even if the container is stopped.
You must first stop and remove any containers
using the volume before you can delete the volume.

To delete a volume:

1. In the **Volumes** view, select **Delete** icon in the **Actions** column for
   the volume you want to delete.
2. In the **Delete volume?** modal, select **Delete forever**.

To delete multiple volumes:

1. In the **Volumes** view, select the checkbox next to all the volumes you want
   to delete.
2. Select **Delete**.
3. In the **Delete volumes?** modal, select **Delete forever**.

## Empty a volume

Emptying a volume deletes all a volume's data, but doesn't delete the volume.
When emptying a volume used by one or more running containers, the containers
are temporarily stopped while Docker empties the data, and then restarted when
the emptying process is completed.

To empty a volume:

1. Sign in to Docker Desktop. You must be signed in to empty a volume.
2. In the **Volumes** view, select the volume you want to empty.
3. Next to **Import**, select the **More volume actions** icon, and then select **Empty volume**.
4. In the **Empty a volume?** modal, select **Empty**.

## Export a volume

You can export the content of a volume to a local file, a local image, and to an
image in Docker Hub, or to a supported cloud provider. When exporting content
from a volume used by one or more running containers, the containers are
temporarily stopped while Docker exports the content, and then restarted when
the export process is completed.

You can either [export a volume now](#export-a-volume-now) or [schedule a recurring export](#schedule-a-volume-export).

### Export a volume now

1. Sign in to Docker Desktop. You must be signed in to export a volume.
2. In the **Volumes** view, select the volume you want to export.
3. Select the **Exports** tab.
4. Select **Quick export**.
5. Select whether to export the volume to **Local or Hub storage** or **External
   cloud storage**, then specify the following additional details depending on
   your selection.

   {{< tabs >}}
   {{< tab name="Local or Hub storage" >}}
   
   - **Local file**: Specify a file name and select a folder.
   - **Local image**: Select a local image to export the content to. Any
    existing data in the image will be replaced by the exported content.
   - **New image**: Specify a name for the new image.
   - **Registry**: Specify a Docker Hub repository.

   {{< /tab >}}
   {{< tab name="External cloud storage" >}}

   You must have a [Docker Business subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopVolumes) to export to an external cloud provider.

   Select your cloud provider and then specify the URL to upload to the storage.
   Refer to the following documentation for your cloud provider to learn how to
   obtain a URL.

   - Amazon Web Services: [Create a presigned URL of Amazon S3 using an AWS SDK](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example_s3_Scenario_PresignedUrl_section.html)
   - Microsoft Azure: [Generate a SAS token and URL](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/api/connection-strings/generate-sas-token)
   - Google Cloud: [Create a signed URL to upload an object](https://cloud.google.com/storage/docs/access-control/signing-urls-with-helpers#upload-object)

   {{< /tab >}}
   {{< /tabs >}}

6. Select **Save**.

### Schedule a volume export

1. Sign in to Docker Desktop. You must be signed in and have a paid [Docker subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopVolumes) to schedule a volume export.
2. In the **Volumes** view, select the volume you want to export.
3. Select the **Exports** tab.
4. Select **Schedule export**.
5. In **Recurrence**, select how often the export occurs, and then specify the
   following additional details based on your selection.

   - **Daily**: Specify the time that the backup occurs each day.
   - **Weekly**: Specify one or more days, and the time that the backup occurs
     each week.
   - **Monthly**: Specify which day of the month and the time that the backup
     occurs each month.

6. Select whether to export the volume to **Local or Hub storage** or **External
   cloud storage**, then specify the following additional details depending on
   your selection.
   
   {{< tabs >}}
   {{< tab name="Local or Hub storage" >}}
   
   - **Local file**: Specify a file name and select a folder.
   - **Local image**: Select a local image to export the content to. Any
    existing data in the image will be replaced by the exported content.
   - **New image**: Specify a name for the new image.
   - **Registry**: Specify a Docker Hub repository.

   {{< /tab >}}
   {{< tab name="External cloud storage" >}}

   You must have a [Docker Business subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsDesktopVolumes) to export to an external cloud provider.

   Select your cloud provider and then specify the URL to upload to the storage.
   Refer to the following documentation for your cloud provider to learn how to
   obtain a URL.

   - Amazon Web Services: [Create a presigned URL of Amazon S3 using an AWS SDK](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example_s3_Scenario_PresignedUrl_section.html)
   - Microsoft Azure: [Generate a SAS token and URL](https://learn.microsoft.com/en-us/azure/data-explorer/kusto/api/connection-strings/generate-sas-token)
   - Google Cloud: [Create a signed URL to upload an object](https://cloud.google.com/storage/docs/access-control/signing-urls-with-helpers#upload-object)

   {{< /tab >}}
   {{< /tabs >}}

7. Select **Save**.

## Import a volume

You can import a local file, a local image, or an image from Docker Hub. Any
existing data in the volume is replaced by the imported content. When importing
content to a volume used by one or more running containers, the containers are
temporarily stopped while Docker imports the content, and then restarted when
the import process is completed.

To import a volume:

1. Sign in to Docker Desktop. You must be signed in to import a volume.
2. Optionally, [create](#create-a-volume) a new volume to import the content
   into.
3. Select the volume you want to import content in to.
4. Select **Import**.
5. Select where the content is coming from and then specify the following
   additional details depending on your selection:

   - **Local file**: Select the file that contains the content.
   - **Local image**: Select the local image that contains the content.
   - **Registry**: Specify the image from Docker Hub that contains the content.

6. Select **Import**.

## Additional resources

- [Persisting container data](/get-started/docker-concepts/running-containers/persisting-container-data.md)
- [Use volumes](../../engine/storage/volumes.md)


---

# Docker Hardened Images

*Sección: Dhi*

Docker Hardened Images (DHI) provide minimal, secure, and production-ready
container images, Helm charts, and system packages maintained by Docker.
Designed to reduce vulnerabilities and simplify compliance, DHI integrates
easily into your existing Docker-based workflows with little to no retooling
required.

DHI is available in the following three subscriptions.

| Feature | Community | Select | Enterprise |
|---|---|---|---|
| Hardened, minimal images | ✅ | ✅ | ✅ |
| Near-zero CVEs | ✅ | ✅ | ✅ |
| Verifiable SBOMs & SLSA Build L3 provenance | ✅ | ✅ | ✅ |
| Full, unsuppressed CVE visibility | ✅ | ✅ | ✅ |
| Drop-in adoption, no workflow changes | ✅ | ✅ | ✅ |
| Full catalog of open source images under Apache 2.0 | ✅ | ✅ | ✅ |
| Built with Docker Hardened System Packages | ✅ | ✅ | ✅ |
| Upstream cadence for Docker-released patches | ✅ | ✅ | ✅ |
| FIPS/STIG variants | ❌ | ✅ | ✅ |
| Critical CVE fixes < 7 days with SLA-backed continuous patching | ❌ | ✅ | ✅ |
| Customizations | ❌ | ✅ Up to 5 | ✅ Unlimited |
| Access to Hardened System Packages repository | ❌ | ❌ | ✅ |
| Full catalog access available | ❌ | ❌ | ✅ |
| Extended Lifecycle Support add-on available | ❌ | ❌ | ✅ +5 years of hardened updates |

For pricing and more details, see the [Docker Hardened Images subscription
comparison](https://www.docker.com/products/hardened-images/#compare).

## Community features

DHI's core features are free to use, share, and build on under Apache 2.0.

- [Near-zero CVEs](/dhi/explore/security-concepts/cves/): continuously scanned and patched
  to maintain minimal known vulnerabilities
- [Distroless variants](/dhi/explore/security-concepts/distroless/): remove unnecessary
  components, reducing attack surface by up to 95%
- Non-root execution: containers run as non-root by default
- [Hardened system packages](/dhi/how-to/hardened-packages/): system packages
  built from source, cryptographically signed, and verified by Docker
- [SLSA Build Level 3 provenance](/dhi/explore/security-concepts/slsa/), [signed
  SBOMs](/dhi/explore/security-concepts/sbom/), [VEX statements](/dhi/explore/security-concepts/vex/),
  and [cryptographic signatures](/dhi/explore/security-concepts/signatures/) on every image
- Built on Alpine and Debian with [glibc and musl
  variants](/dhi/explore/security-concepts/glibc-musl/); dev and runtime image variants
  available
- Works with existing Docker workflows, CI/CD pipelines, and tools with no
  retooling required
- [Helm charts](/dhi/how-to/helm/): Docker-provided charts built from upstream
  sources, tested for compatibility with DHI, and available as OCI artifacts in
  the DHI catalog; include SLSA Level 3 provenance, SBOMs, and cryptographic
  signing

## Select and Enterprise features

For organizations with strict security or compliance requirements:

- [7-day SLA](https://docs.docker.com/go/dhi-sla/) for critical and high
  severity CVE remediation
- [FIPS-enabled](/dhi/explore/security-concepts/fips/) and
  [STIG-ready](/dhi/explore/security-concepts/stig/) compliance variants
- [Customization](/dhi/how-to/customize/): add packages, tools, certificates,
  and configurations (up to 5 with Select, unlimited with Enterprise)
- [Enterprise package repository](/dhi/how-to/hardened-packages/) access and
  full catalog access (Enterprise)
- Extended Lifecycle Support: post-EOL security patches, updated SBOMs,
  provenance, and signing (Enterprise add-on)

## Get started

Explore the sections below to get started with Docker Hardened Images, integrate
them into your workflow, and learn what makes them secure and enterprise-ready.

{{< grid items="grid_sections" >}}


---

# Explore Docker Hardened Images

*Sección: Dhi*

Docker Hardened Images (DHI) are minimal, secure, and production-ready container
base and application images maintained by Docker. Designed to reduce
vulnerabilities and simplify compliance, DHI integrates easily into your
existing Docker-based workflows with little to no retooling required.

This section helps you understand what Docker Hardened Images are, how they're
built and tested, the different types available, and how responsibility is
shared between Docker and you as a user.

## Learn more about Docker Hardened Images

{{< grid
  items="grid_about"
>}}


---

# Available types of Docker Hardened Images

*Sección: Dhi*

Docker Hardened Images (DHI) is a comprehensive catalog of
security-hardened container images built to meet diverse
development and production needs.

You can explore the DHI catalog on [Docker Hub](https://hub.docker.com/hardened-images/catalog) or use the [DHI CLI](../tools/cli.md) to browse
available images, tags, and metadata from the command line.

## Framework and application images

DHI includes a selection of popular frameworks and application images, each
hardened and maintained to ensure security and compliance. These images
integrate seamlessly into existing workflows, allowing developers to focus on
building applications without compromising on security.

For example, you might find repositories like the following in the DHI catalog:

- `node`: framework for Node.js applications
- `python`: framework for Python applications
- `nginx`: web server image

## Base image distributions

Docker Hardened Images are available in different base image options, giving you
flexibility to choose the best match for your environment and workload
requirements:

- Debian-based images: A good fit if you're already working in glibc-based
  environments. Debian is widely used and offers strong compatibility across
  many language ecosystems and enterprise systems.

- Alpine-based images: A smaller and more lightweight option using musl libc.
  These images tend to be small and are therefore faster to pull and have a
  reduced footprint.

Each image maintains a minimal and secure runtime layer by removing
non-essential components like shells, package managers, and debugging tools.
This helps reduce the attack surface while retaining compatibility with common
runtime environments. To maintain this lean, secure foundation, DHI standardizes
on Debian for glibc-based images, which provides broad compatibility while
minimizing complexity and maintenance overhead.

Example tags include:

- `3.9.23-alpine3.21`: Alpine-based image for Python 3.9.23
- `3.9.23-debian12`: Debian-based image for Python 3.9.23

If you're not sure which to choose, start with the base you're already familiar
with. Debian tends to offer the broadest compatibility.

## Development and runtime variants

To accommodate different stages of the application lifecycle, DHI offers all
language framework images and select application images in two variants:

- Development (dev) images: Equipped with necessary development tools and
libraries, these images facilitate the building and testing of applications in a
secure environment. They include a shell, package manager, a root user, and
other tools needed for development.

- Runtime images: Stripped of development tools, these images contain only the
essential components needed to run applications, ensuring a minimal attack
surface in production.

This separation supports multi-stage builds, enabling developers to compile code
in a secure build environment and deploy it using a lean runtime image.

For example, you might find tags like the following in a DHI repository:

- `3.9.23-debian12`: runtime image for Python 3.9.23
- `3.9.23-debian12-dev`: development image for Python 3.9.23

## FIPs and STIG variants

{{< summary-bar feature_name="Docker Hardened Images" >}}

Some Docker Hardened Images include a `-fips` variant. These variants use
cryptographic modules that have been validated under [FIPS
140](security-concepts/fips.md), a U.S. government standard for secure
cryptographic operations.

FIPS variants are designed to help organizations meet regulatory and compliance
requirements related to cryptographic use in sensitive or regulated
environments.

You can recognize FIPS variants by their tag that includes `-fips`.

For example:
- `3.13-fips`: FIPS variant of the Python 3.13 image
- `3.9.23-debian12-fips`: FIPS variant of the Debian-based Python 3.9.23 image

FIPS variants can be used in the same way as any other Docker Hardened Image and
are ideal for teams operating in regulated industries or under compliance
frameworks that require cryptographic validation.

In addition to FIPS variants, some Docker Hardened Images also include
STIG-ready variants. These images are scanned against custom STIG-based
profiles and come with signed STIG scan attestations to support audits and
compliance reporting. To identify STIG-ready variants, look for the **STIG**
in the **Compliance** column of the image tags list in the Docker Hub catalog.

## Compatibility variants

Some Docker Hardened Images include a compatibility variant. These variants
provide additional tools and configurations for specific use cases without
bloating the minimal base images.

Compatibility variants are created to support:

- Helm chart compatibility: Applications deployed via Helm charts and
  Kubernetes that require specific runtime configurations or utilities for
  seamless integration with popular Helm charts.

- Special application use-cases: Applications that need optional tools not
  included in the minimal image.

By offering these as separate image flavors, DHI ensures that the minimal images
remain lean and secure, while providing the tools you need in dedicated
variants. This approach maintains a minimal attack surface for standard
deployments while supporting specialized requirements when needed.

You can recognize compatibility variants by their tag that includes `-compat`.

Use compatibility variants when your deployment requires additional tools beyond
the minimal runtime, such as when using Helm charts or applications with
specific tooling requirements.

## Socket Firewall variants

Some Docker Hardened Images include Socket Firewall variants. These are `dev`
variants that come with [Socket](https://socket.dev/) preinstalled to monitor
package manager activity and block malicious packages during development and CI
builds.

Two tiers are available, identified by their tag suffix:

- `-sfw-dev`: Socket Firewall Free. No API key required.
- `-sfw-ent-dev`: Socket Firewall Enterprise. Requires an API key from Socket.

Not all images offer both tiers.

## Image-specific variants

Some images include variants that go beyond the general `dev`, `compat`, and
`sfw` patterns. These represent distinct editions, bundled tooling, or
runtime configurations specific to that image. Examples include a PHP-FPM variant
for web server integration, a native binary build for faster startup, or a
specific edition of a database.

You can identify these variants by their tag suffix. The image name in the tag
suffix typically reflects what's included or different.


---

# How Docker Hardened Images are built

*Sección: Dhi*

Docker Hardened Images are built through an automated pipeline that monitors
upstream sources, applies security updates, and publishes signed artifacts.
This page explains the build process for both base DHI images and customized
images available with DHI Select and DHI Enterprise subscriptions.

With DHI Select or DHI Enterprise subscriptions, the automated security update pipeline for
both base and customized images is backed by [SLA commitments](https://docs.docker.com/go/dhi-sla/), including a 7-day
SLA for critical and high severity vulnerabilities. DHI Community offers a secure baseline
but no guaranteed remediation timelines.

## Build transparency

Docker Hardened Images provide transparency into how images are built through
publicly available definitions and verifiable attestations.

### Image definitions

All image definitions are publicly available in the [catalog
repository](https://github.com/docker-hardened-images/catalog).

Each image definition is a declarative YAML specification that includes metadata,
contents, build pipeline steps, security configurations, and runtime settings.

### SLSA attestations

Every Docker Hardened Image includes a SLSA Build Level 3 attestation that
provides verifiable build provenance. For details on SLSA attestations and how to
verify them, see [SLSA](security-concepts/slsa.md).

## Build triggers

Builds start automatically. You don't trigger them manually. The system monitors
for changes and starts builds in two scenarios:

- [Upstream updates](#upstream-updates)
- [Customization changes](#customization-changes)

### Upstream updates

New releases, package updates, or CVE fixes from upstream projects trigger base
image rebuilds. These builds go through quality checks to ensure security and
reliability.

#### Monitoring for updates

Docker continuously monitors upstream projects for new releases, package
updates, and security advisories. When changes are detected, the system
automatically queues affected images for rebuild using a SLSA Build Level
3-compliant build system.

Docker uses three strategies to track updates:

- GitHub releases: Monitors specific GitHub repositories for new releases and
  automatically updates the image definition when a new version is published.
- GitHub tags: Tracks tags in GitHub repositories to detect new versions.
- Package repositories: Monitors Alpine Linux, Debian, and Ubuntu package
  repositories through Docker Scout's package database to detect updated
  packages.

In addition to explicit upstream tracking, Docker also monitors transitive
dependencies. When a package update is detected (for example, a security patch
for a library), Docker automatically identifies and rebuilds all images within
the support window that use that package.

### Customization changes

{{< summary-bar feature_name="Docker Hardened Images" >}}

Updates to your OCI artifact customizations trigger rebuilds of your customized
images.

When you customize a DHI image with DHI Select or DHI Enterprise, your changes are packaged as
OCI artifacts that layer on top of the base image. Docker monitors your artifact
repositories and automatically rebuilds your customized images whenever you push
updates.

The rebuild process fetches the current base image, applies your OCI artifacts,
signs the result, and publishes it automatically. You don't need to manage
builds or maintain CI pipelines for your customized images.

Customized images are also rebuilt automatically when the base DHI image they
depend on receives updates, ensuring your images always include the latest
security patches.

## Build pipeline

The following sections describe the build pipeline architecture and workflow for
Docker Hardened Images based on:

- [Base image pipeline](#base-image-pipeline)
- [Customized image pipeline](#customized-image-pipeline)

### Base image pipeline

Each Docker Hardened Image is built through an automated pipeline:

1. Monitoring: Docker monitors upstream sources for updates (new releases,
   package updates, security advisories).
2. Rebuild trigger: When changes are detected, an automated rebuild starts.
3. AI guardrail: An AI system fetches upstream diffs and scans them with
   language-aware checks. The guardrail focuses on high-leverage issues that can
   cause significant problems, such as inverted error checks, ignored failures,
   resource mishandling, or suspicious contributor activity. When it spots
   potential risks, it blocks the PR from auto-merging.
4. Human review: If the AI identifies risks with high confidence,
   Docker engineers review the flagged code, reproduce the issue, and decide on
   the appropriate action. Engineers often contribute fixes back to upstream
   projects, improving the code for the entire community. When fixes are accepted
   upstream, the DHI build pipeline applies the patch immediately to protect
   customers while the fix moves through the upstream release process.
5. Testing and scanning: Images undergo comprehensive
   [testing](test.md) for compatibility and functionality, and are
   [scanned for malware](malware-scanning.md), secrets, and
   vulnerabilities.
6. Signing and attestations: Docker signs each image and generates
   attestations (SBOMs, VEX documents, build provenance).
7. Publishing: The signed image is published to the DHI registry and the
   attestations are published to the Docker Scout registry.
8. Cascade rebuilds: If any customized images use this base, their rebuilds
   are automatically triggered.

Docker responds quickly to critical vulnerabilities. By building essential
components from source rather than waiting for packaged updates, Docker can
patch critical and high severity CVEs within days of upstream fixes and publish
updated images with new attestations. For DHI Enterprise subscriptions, this
rapid response is backed by a [7-day SLA for critical and high severity
vulnerabilities](https://docs.docker.com/go/dhi-sla/).

The following diagram shows the base image build flow:

```goat {class="text-sm"}
.-------------------.      .-------------------.      .-------------------.      .-------------------.
| Docker monitors   |----->| Trigger rebuild   |----->| AI guardrail      |----->| Human review      |
| upstream sources  |      |                   |      | scans changes     |      |                   |
'-------------------'      '-------------------'      '-------------------'      '-------------------'
                                                                                           |
                                                                                           v
.-------------------.      .-------------------.      .-------------------.      .-------------------.
| Cascade rebuilds  |<-----| Publish to        |<-----| Sign & generate   |<-----| Testing &         |
| (if needed)       |      | DHI registry      |      | attestations      |      | scanning          |
'-------------------'      '-------------------'      '-------------------'      '-------------------'
```

### Customized image pipeline

{{< summary-bar feature_name="Docker Hardened Images" >}}

When you customize a DHI image with DHI Select or DHI Enterprise, the build process is simplified:

1. Monitoring: Docker monitors your OCI artifact repositories for changes.
2. Rebuild trigger: When you push updates to your OCI artifacts, or when the base
   DHI image is updated, an automated rebuild starts.
3. Fetch base image: The latest base DHI image is fetched.
4. Apply customizations: Your OCI artifacts are applied to the base image.
5. Scanning: The customized image is [scanned for
   malware](malware-scanning.md), secrets, and vulnerabilities.
6. Signing and attestations: Docker signs the customized image and generates
   attestations (SBOMs, VEX documents, build provenance).
7. Publishing: The signed customized image is published to Docker Hub and the
   attestations are published to the Docker Scout registry.

Docker handles the entire process automatically, so you don't need to manage
builds for your customized images. However, you're responsible for testing your
customized images and managing any CVEs introduced by your OCI artifacts.

The following diagram shows the customized image build flow:

```goat {class="text-sm"}
.-------------------.      .-------------------.      .-------------------.      .-------------------.
| Docker monitors   |----->| Trigger rebuild   |----->| Fetch base        |----->| Apply             |
| OCI artifacts     |      |                   |      | DHI image         |      | customizations    |
'-------------------'      '-------------------'      '-------------------'      '-------------------'
                                                                                           |
                                                                                           v
                           .-------------------.      .-------------------.      .-------------------.
                           | Publish to        |<-----| Sign & generate   |<-----| Scanning          |
                           | Docker Hub        |      | attestations      |      |                   |
                           '-------------------'      '-------------------'      '-------------------'
```


---

# Malware scanning

*Sección: Dhi*

The Docker Hardened Image (DHI) pipeline scans for viruses and malware as part
of the build process. The scan results are embedded as a signed attestation,
which you can independently retrieve and verify.

## How it works

Docker uses [ClamAV](https://www.clamav.net/), an open source antivirus engine,
to scan every layer of each image. The scan runs automatically during the build
process and checks all files in the image, including files inside archives, for
known viruses and malware signatures.

The scan results are published as a signed attestation attached to the image.
The attestation includes the full ClamAV scan report, including the number of
files scanned, the virus signature database version, and whether any infected
files were detected.

## View the malware scan attestation

You can retrieve the malware scan attestation using the Docker Scout CLI.

1. Use the `docker scout attest get` command with the virus scan predicate type:

   ```console
   $ docker scout attest get \
     --predicate-type https://scout.docker.com/virus/v0.1 \
     --predicate \
     dhi.io/<image>:<tag>
   ```

   > [!NOTE]
   >
   > If the image exists locally on your device, you must prefix the image name
   > with `registry://`. For example, use `registry://dhi.io/python` instead of
   > `dhi.io/python`.

   For example:

   ```console
   $ docker scout attest get \
     --predicate-type https://scout.docker.com/virus/v0.1 \
     --predicate \
     dhi.io/python:3.13
   ```

   The output is a JSON object containing the scanner used and the base64-encoded
   scan report:

   ```json
   {
     "scanner": {
       "report": "<base64-encoded ClamAV report>",
       "uri": "clamav/clamav:stable"
     }
   }
   ```

   Decoding the report shows the full ClamAV output, ending with a scan summary:

   ```text
   ----------- SCAN SUMMARY -----------
   Known viruses: 3627833
   Engine version: 1.5.2
   Scanned directories: 4
   Scanned files: 21
   Infected files: 0
   Data scanned: 44.90 MiB
   Data read: 23.88 MiB (ratio 1.88:1)
   Time: 11.473 sec (0 m 11 s)
   Start Date: 2026:04:12 02:36:19
   End Date:   2026:04:12 02:36:30
   ```

2. Verify the attestation signature. To ensure the attestation is authentic and
   signed by Docker, run:

   ```console
   $ docker scout attest get \
     --predicate-type https://scout.docker.com/virus/v0.1 \
     --verify \
     dhi.io/<image>:<tag> --platform <platform>
   ```

   If the attestation is valid, Docker Scout confirms the signature and shows
   the matching `cosign verify` command.

To view other attestations, such as SBOMs or test results, see [Verify
an image](../how-to/verify.md).


---

# Understanding roles and responsibilities for Docker Hardened Images

*Sección: Dhi*

Docker Hardened Images (DHIs) are curated and maintained by Docker, and built
using upstream open source components. To deliver security, reliability, and
compliance, responsibilities are shared among three groups:

- Upstream maintainers: the developers and communities responsible for the
  open source software included in each image.
- Docker: the provider of hardened, signed, and maintained container images.
- You (the customer): the consumer who runs and, optionally, customizes DHIs
  in your environment.

This topic outlines who handles what, so you can use DHIs effectively and
securely.

## Releases

- Upstream: Publishes and maintains official releases of the software
  components included in DHIs. This includes versioning, changelogs, and
  deprecation notices.
- Docker: Builds, hardens, and signs Docker Hardened Images based on
  upstream versions. Docker maintains these images in line with upstream release
  timelines and internal policies.
- You: Ensure you're staying on supported versions of DHIs and upstream
  projects. Using outdated or unsupported components can introduce security
  risk.

## Patching

- Upstream: Maintains and updates the source code for each component,
  including fixing vulnerabilities in libraries and dependencies.
- Docker: Rebuilds and re-releases images with upstream patches applied. Docker
  monitors for vulnerabilities and publishes updates to affected images. DHI Select
  and DHI Enterprise include [SLA commitments](https://docs.docker.com/go/dhi-sla/). DHI Community offers a secure baseline but no
  guaranteed remediation timelines.
- You: Apply DHI updates in your environments and patch any software or
  dependencies you install on top of the base image.

## Testing

- Upstream: Defines the behavior and functionality of the original software,
  and is responsible for validating core features.
- Docker: Validates that DHIs start, run, and behave consistently with
  upstream expectations. Docker also runs security scans and includes a [testing
  attestation](security-concepts/attestations.md) with each image.
- You: Test your application on top of DHIs and validate that any changes or
  customizations function as expected in your environment.

## Security and compliance

- Docker: Publishes signed SBOMs, VEX documents, provenance data, and CVE
  scan results with each image to support compliance and supply chain security.
  - For DHI Community users: All security metadata and transparency features are
    included at no cost.
  - For DHI Select and Enterprise users: Additional compliance variants (like FIPS and
    STIG) and customization capabilities are available, with automatic rebuilds
    when base images are patched.
- You: Integrate DHIs into your security and compliance workflows, including
  vulnerability management and auditing.

## Support

- Docker:
  - For DHI Community users: Community support and public documentation are available.
  - For DHI Select and DHI Enterprise users: Access to Docker's enterprise
    support team for mission-critical applications.
- You: Monitor Docker's release notes, security advisories, and documentation
  for updates and best practices.

## Summary

Docker Hardened Images give you a secure foundation, complete with signed
metadata and upstream transparency. Your role is to make informed use of these
images, apply updates promptly, and validate that your configurations and
applications meet your internal requirements.


---

# Scanner integrations

*Sección: Dhi*

Docker Hardened Images (DHI) work with various vulnerability scanners. However, to get
accurate results that reflect the actual security posture of these images, your
scanner needs to understand the VEX (Vulnerability Exploitability eXchange)
attestations included with each image.

## Scanners with VEX support

The following scanners can read and apply VEX attestations included with Docker
Hardened Images:

| Scanner | VEX application |
|---------|-----------------|
| [Docker Scout](/scout/) | Automatic, zero configuration |
| [Trivy](https://trivy.dev/) | VEX Hub (recommended) or local VEX file |
| [Grype](https://github.com/anchore/grype) | Via `--vex` flag with local VEX file |
| [Wiz](https://docs.wiz.io/) | Automatic, zero configuration |
| [Mend.io](https://docs.mend.io/platform/latest/docker-hardened-images) | Automatic, zero configuration |
| [Black Duck](https://documentation.blackduck.com/bundle/bd-hub/page/Reporting/vexReport_global.html) | Automatic, zero configuration |
| [Aikido](https://help.aikido.dev/container-image-scanning/standalone-registries/docker-hub-images) | Automatic, zero configuration |
| [AWS Inspector](https://docs.aws.amazon.com/inspector/latest/user/supported.html) | Automatic, zero configuration |

For step-by-step instructions for Docker Scout, Trivy, and Grype, see [Scan Docker Hardened Images](../how-to/scan.md). For Wiz, Mend.io, Black Duck, Aikido, and AWS Inspector, refer to their respective documentation.

## Choosing a scanner for Docker Hardened Images

When selecting a scanner for use with Docker Hardened Images, whether it
supports open standards like OpenVEX is the key differentiator.

Docker Hardened Images include signed VEX attestations that follow the
[OpenVEX standard](https://openvex.dev/). OpenVEX is an open standard that meets
the minimum requirements for VEX defined by CISA (Cybersecurity and
Infrastructure Security Agency), the U.S. government agency responsible for
cybersecurity guidance. These attestations document which vulnerabilities don't
apply to the image and why, helping you focus on real risks. To understand what
VEX is and how it works, see the [VEX core concept](security-concepts/vex.md).

Because OpenVEX is an open standard with government backing, it has strong
industry momentum and any tool can implement it without vendor-specific
integrations. This matters when you bring in third-party auditors with their own
scanning tools, or when you want to use multiple security tools in your
pipeline. With VEX, these tools can all read and verify the same vulnerability
data directly from your images.

Without open standards like VEX, vendors make exploitability decisions using
proprietary methods, making it difficult to verify claims or compare results
across tools. This fragments your security toolchain and creates inconsistent
vulnerability assessments across different scanning tools.

### Benefits of scanners with VEX support

Scanners that support open standards like OpenVEX and can interpret VEX attestations
from Docker Hardened Images offer the following benefits:

- Accurate vulnerability counts: Automatically filter out vulnerabilities
  that don't apply to your specific image, often reducing false positives
  dramatically.
- Transparency and auditability: Verify exactly why vulnerabilities are or
  aren't flagged; security teams and compliance officers can review the reasoning
  rather than trusting a vendor's black box.
- Scanner flexibility: Switch between any VEX-enabled scanner (Docker Scout,
  Trivy, Grype, etc.) without losing vulnerability context or rebuilding exclusion lists.
- Consistent results: VEX-enabled scanners interpret the same data the
  same way, eliminating discrepancies between tools.
- Faster workflows: Focus on real risks rather than researching why reported
  CVEs don't actually affect your deployment.

### Scanners without VEX support

Scanners that can't read VEX attestations will report vulnerabilities that don't
apply to Docker Hardened Images. This creates operational challenges:

- Manual filtering required: You'll need to maintain scanner-specific ignore
  lists to replicate what VEX statements already document.
- Higher false positive rates: Expect to see more reported vulnerabilities
  that don't represent real risks.
- Increased investigation time: Security teams spend time researching why
  CVEs don't apply instead of addressing actual vulnerabilities. With Docker
  Hardened Images, security experts at Docker manage this investigation for
  you, thoroughly vetting each justification before adding it to a VEX statement.
- CI/CD friction: Build pipelines may fail on vulnerabilities that aren't
  exploitable in your images.

### VEX-based vulnerability handling versus proprietary approaches

Docker Hardened Images use VEX attestations based on the OpenVEX open standard to document vulnerability exploitability. OpenVEX is an open standard that is recognized by government agencies such as CISA. This open standards approach differs from how some other image vendors handle vulnerabilities using proprietary methods.

#### Docker Hardened Images with VEX

The image includes signed attestations that explain which vulnerabilities don't
apply and why. Any VEX-enabled scanner can read these attestations, giving you:

- Tool flexibility: Use any scanner that supports OpenVEX (Docker Scout,
  Trivy, Grype, etc.)
- Complete transparency: Review the exact reasoning for each vulnerability
  assessment
- Full auditability: Security teams and compliance officers can independently
  verify all vulnerability assessments and reasoning
- Historical visibility: VEX statements remain with the image, so you can
  always check vulnerability status, even for older versions

#### Proprietary vulnerability handling

Some image vendors use proprietary advisory feeds or internal databases instead
of VEX. While this may result in fewer reported vulnerabilities, it creates
significant limitations:

- Tool dependency: You must use the vendor's preferred scanning tools to see
  their vulnerability filtering, while standard scanners will still report all
  CVEs; scanners must implement proprietary feeds rather than using open
  standards that work with all images
- No transparency: Proprietary feeds act as "black boxes" - vulnerabilities
  simply disappear from vendor tools with no explanation
- Limited verifiability: Security teams have no way to independently verify
  why vulnerabilities are excluded or whether the reasoning is sound
- Maintenance challenges: If you scan older image versions with standard
  tools, you can't determine which vulnerabilities actually applied at that
  time, making long-term security tracking difficult
- Ecosystem incompatibility: Your existing security tools (SCA, policy
  engines, compliance scanners) can't access or verify the vendor's proprietary
  vulnerability data

The fundamental difference: VEX-based approaches explain vulnerability
assessments using open standards that any tool can verify and audit. Proprietary
approaches hide vulnerabilities in vendor-specific systems where the reasoning
can't be independently validated.

For Docker Hardened Images, use VEX-enabled scanners to get accurate results
that work across your entire security toolchain.

## What to expect from different scanners

When scanning Docker Hardened Images with different tools, you'll see
significant differences in reported vulnerability counts.

### What VEX-enabled scanners filter automatically

When you scan Docker Hardened Images with VEX-enabled scanners, they
automatically exclude vulnerabilities that don't apply:

- Hardware-specific vulnerabilities: Issues that only affect specific
  hardware architectures (for example, Power10 processors) that are irrelevant to
  containerized workloads.
- Unreachable code paths: CVEs in code that exists in the package but isn't
  executed in the image's runtime configuration.
- Build-time only issues: Vulnerabilities in build tools or dependencies
  that don't exist in the final runtime image.
- Temporary identifiers: Placeholder vulnerability IDs (like Debian's
  `TEMP-xxxxxxx`) that aren't intended for external tracking.

### Using scanners without VEX support

If your scanner doesn't support VEX, you'll need to manually exclude
vulnerabilities through scanner-specific mechanisms like ignore lists or policy
exceptions. This requires:

- Reviewing VEX statements from Docker Hardened Images
- Translating VEX justifications into your scanner's format
- Maintaining these exclusions as new vulnerabilities are discovered
- Repeating this process if you switch scanners or add additional scanning tools

## What's next

Learn how to [scan Docker Hardened Images](../how-to/scan.md) with
VEX-compliant scanners.


---

# Security concepts

*Sección: Dhi*

Docker Hardened Images (DHIs) are built on a foundation of secure software
supply chain practices. This section explains the core concepts behind that
foundation, from signed attestations and immutable digests to standards like SLSA
and VEX.

Start here if you want to understand how Docker Hardened Images support compliance,
transparency, and security.


## Security metadata and attestations

{{< grid items="grid_concepts_metadata" >}}

## Compliance standards

{{< grid items="grid_concepts_compliance" >}}

## Vulnerability and risk management

{{< grid items="grid_concepts_risk" >}}

## Image structure and behavior

{{< grid items="grid_concepts_structure" >}}

## Verification and traceability

{{< grid items="grid_concepts_verification" >}}


---

# Attestations

*Sección: Dhi*

Docker Hardened Images (DHIs) and charts include comprehensive, signed security
attestations that verify the image's build process, contents, and security
posture. These attestations are a core part of secure software supply chain
practices and help users validate that an image is trustworthy and
policy-compliant.

## What is an attestation?

An attestation is a signed statement that provides verifiable information
about an image or chart, such as how it was built, what's inside it, and what security
checks it has passed. Attestations are typically signed using Sigstore tooling
(such as Cosign), making them tamper-evident and cryptographically verifiable.

Attestations follow standardized formats (like [in-toto](https://in-toto.io/),
[CycloneDX](https://cyclonedx.org/), and [SLSA](https://slsa.dev/)) and are
attached to the image or chart as OCI-compliant metadata. They can be generated
automatically during image builds or added manually to document extra tests,
scan results, or custom provenance.

## Why are attestations important?

Attestations provide critical visibility into the software supply chain by:

- Documenting *what* went into an image (e.g., SBOMs)
- Verifying *how* it was built (e.g., build provenance)
- Capturing *what security scans* it has passed or failed (e.g., CVE reports,
  secrets scans, test results)
- Helping organizations enforce compliance and security policies
- Supporting runtime trust decisions and CI/CD policy gates

They are essential for meeting industry standards such as SLSA,
and help teams reduce the risk of supply chain attacks by making build and
security data transparent and verifiable.

## How Docker Hardened Images and charts use attestations

All DHIs and charts are built using [SLSA Build Level
3](https://slsa.dev/spec/latest/levels) practices, and each image variant is
published with a full set of signed attestations. These attestations allow users
to:

- Verify that the image or chart was built from trusted sources in a secure environment
- View SBOMs in multiple formats to understand component-level details
- Review scan results to check for vulnerabilities or embedded secrets
- Confirm the build and deployment history of each image

Attestations are automatically published and associated with each  DHI
and chart. They can be inspected using tools like [Docker
Scout](../../how-to/verify.md) or
[Cosign](https://docs.sigstore.dev/cosign/overview), and are consumable by CI/CD
tooling or security platforms.

## Image attestations

While every DHI variant includes a set of attestations, the attestations may
vary based on the image variant. For example, some images may include a STIG
scan attestation. The following table lists attestations that may be included with a DHI; the
actual set varies by image variant. To see which attestations are available
for a specific image variant, including the specific predicate type URIs, use
Docker Scout:

```console
$ docker scout attest list dhi.io/<image>:<tag>
```

For more details, see [Verify image attestations](../../how-to/verify.md#verify-image-attestations).

| Attestation type           | Description                                                                                                                                                                                                                     |
|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| CycloneDX SBOM             | A software bill of materials in [CycloneDX](https://cyclonedx.org/) format, listing components, libraries, and versions.                                                                                                      |
| STIG scan                  | Results of a STIG scan, with output in HTML and XCCDF formats.                                                                                                                           |
| CVEs (In-Toto format)      | A list of known vulnerabilities (CVEs) affecting the image's components, based on package and distribution scanning.                                                                           |
| VEX                        | A [Vulnerability Exploitability eXchange (VEX)](https://openvex.dev/) document that identifies vulnerabilities that do not apply to the image and explains why (e.g., not reachable or not present).                         |
| Scout provenance           | Provenance metadata generated by Docker Scout, including the source Git commit, build parameters, and environment details.                                                               |
| Scout SBOM                 | An SBOM generated and signed by Docker Scout, including additional Docker-specific metadata.                                                                                             |
| Secrets scan               | Results of a scan for accidentally included secrets, such as credentials, tokens, or private keys.                                                                                       |
| Tests                      | A record of automated tests run against the image, such as functional checks or validation scripts.                                                                                      |
| Virus scan                 | Results of antivirus scans performed on the image layers. For details, see [Malware scanning](../malware-scanning.md).                                                            |
| CVEs (Scout format)        | A vulnerability report generated by Docker Scout, listing known CVEs and severity data.                                                                                                  |
| SLSA provenance            | A standard [SLSA](https://slsa.dev/) provenance statement describing how the image was built, including build tool, parameters, and source.                                               |
| SLSA verification summary  | A summary attestation indicating the image's compliance with SLSA requirements.                                                                                                          |
| SPDX SBOM                  | An SBOM in [SPDX](https://spdx.dev/) format, widely adopted in open-source ecosystems.                                                                                                   |
| FIPS compliance            | An attestation that verifies the image uses FIPS 140-validated cryptographic modules.                              |
| DHI Changelog              | A record of changes made to the image across versions. |
| DHI Image Sources          | Links to a corresponding source image containing all materials used to build the image, including package source code, Git repositories, and local files, ensuring compliance with open source license requirements. |

## Package attestations

In addition to image-level attestations, Docker hardened packages also include
their own attestations. These package-level attestations provide provenance and
build information for individual packages within an image, allowing you to
trace the supply chain at a granular level.

Package attestations include similar information as image attestations, such as
SLSA provenance, showing how each package was built and what materials were
used. You can extract package information from an image's attestations and then
retrieve the package's own attestations recursively.

For detailed instructions on how to access and verify package attestations, see
[Package attestations](../../how-to/hardened-packages.md#package-attestations).

## Helm chart attestations

Docker Hardened Image (DHI) charts also include comprehensive signed attestations
that provide transparency and verification for your Kubernetes deployments. Like
DHI container images, these charts are built following SLSA Build Level 3
practices and include extensive security metadata.

DHI Helm charts include the following attestations. To view the specific predicate
type URIs for these attestations, use Docker Scout:

```console
$ docker scout attest list dhi.io/<chart>:<version>
```

For more details, see [Verify Helm chart attestations](../../how-to/verify.md#verify-helm-chart-attestations-with-docker-scout).

| Attestation type           | Description                                                                                                                                                                                                                     |
|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| CycloneDX SBOM             | A software bill of materials in [CycloneDX](https://cyclonedx.org/) format, listing the chart itself and all container images and tools referenced by the chart.                                                              |
| CVEs (In-Toto format)      | A list of known vulnerabilities (CVEs) affecting the container images and components referenced by the chart.                                                                                                                   |
| Scout provenance           | Provenance metadata generated by Docker Scout, including the chart source repository, build images used, and build parameters.                                                                                                  |
| Scout SBOM                 | An SBOM generated and signed by Docker Scout, including the chart and container images it references, with additional Docker-specific metadata.                                                                                |
| Secrets scan               | Results of a scan for accidentally included secrets, such as credentials, tokens, or private keys, in the chart package.                                                                                                       |
| Tests                      | A record of automated tests run against the chart to validate functionality and compatibility with referenced images.                                                                                                          |
| Virus scan                 | Results of antivirus scans performed on the chart package. For details, see [Malware scanning](../malware-scanning.md).                                                                                                |
| CVEs (Scout format)        | A vulnerability report generated by Docker Scout, listing known CVEs and severity data for the chart's referenced images.                                                                                                      |
| SLSA provenance            | A standard [SLSA](https://slsa.dev/) provenance statement describing how the chart was built, including build tool, source repository, referenced images, and build materials.                                                 |
| SPDX SBOM                  | An SBOM in [SPDX](https://spdx.dev/) format, listing the chart and all container images and tools it references.                                                                                                              |

## View and verify attestations

To view and verify attestations, see [Verify a Docker Hardened
Image](../../how-to/verify.md).

## Add your own attestations

In addition to the comprehensive attestations provided by Docker Hardened
Images, you can add your own signed attestations when building derivative
images. This is especially useful if you’re building new applications on top of
a DHI and want to maintain transparency, traceability, and trust in your
software supply chain.

By attaching attestations such as SBOMs, build provenance, or custom metadata,
you can meet compliance requirements, pass security audits, and support policy
evaluation tools like Docker Scout.

These attestations can then be verified downstream using tools
like Cosign or Docker Scout.

To learn how to attach custom attestations during the build process, see [Build
attestations](/manuals/build/metadata/attestations.md).


---

# CIS Benchmark

*Sección: Dhi*

## What is the CIS Docker Benchmark?

The [CIS Docker Benchmark](https://www.cisecurity.org/benchmark/docker) is part
of the globally recognized CIS Benchmarks, developed by the [Center for
Internet Security (CIS)](https://www.cisecurity.org/). It defines recommended secure
configurations for all aspects of the Docker container ecosystem, including the
container host, Docker daemon, container images, and the container runtime.

## Why CIS Benchmark compliance matters

Following the CIS Docker Benchmark helps organizations:

- Reduce security risk with widely recognized hardening guidance.
- Meet regulatory or contractual requirements that reference CIS controls.
- Standardize image and Dockerfile practices across teams.
- Demonstrate audit readiness with configuration decisions grounded in a public standard.

## How Docker Hardened Images comply with the CIS Benchmark

Docker Hardened Images (DHIs) are designed with security in mind and are
verified to be compliant with the relevant controls from the CIS Docker
Benchmark for the scope that applies to container images and Dockerfile
configuration.

CIS-compliant DHIs are compliant with all controls in Section 4, with the sole
exception of the control requiring Docker Content Trust (DCT), which [Docker
officially retired](https://www.docker.com/blog/retiring-docker-content-trust/).
Instead, DHIs are [signed](signatures.md) using
Cosign, providing an even higher level of authenticity and integrity. By
starting from a CIS-compliant DHI, teams can adopt image-level best practices
from the benchmark more quickly and confidently.

> [!NOTE]
>
> The CIS Docker Benchmark also includes controls for the host, daemon, and
> runtime. CIS-compliant DHIs address only the image and Dockerfile scope (Section
> 4). Overall compliance still depends on how you configure and operate the
> broader environment.

## Identify CIS-compliant images

CIS-compliant images are labeled as **CIS** in the Docker Hardened Images catalog.
To find them, [search the catalog](../../how-to/search-evaluate.md) and look for the **CIS**
designation on individual listings.

## Get the benchmark

Download the latest CIS Docker Benchmark directly from CIS:
https://www.cisecurity.org/benchmark/docker


---

# Common Vulnerabilities and Exposures (CVEs)

*Sección: Dhi*

## What are CVEs?

CVEs are publicly disclosed cybersecurity flaws in software or hardware. Each
CVE is assigned a unique identifier (e.g., CVE-2024-12345) and includes a
standardized description, allowing organizations to track and address
vulnerabilities consistently.

In the context of Docker, CVEs often pertain to issues within base images, or
application dependencies. These vulnerabilities can range from minor bugs to
critical security risks, such as remote code execution or privilege escalation.

## Why are CVEs important?

Regularly scanning and updating Docker images to mitigate CVEs is crucial for
maintaining a secure and compliant environment. Ignoring CVEs can lead to severe
security breaches, including:

- Unauthorized access: Exploits can grant attackers unauthorized access to
  systems.
- Data breaches: Sensitive information can be exposed or stolen.
- Service disruptions: Vulnerabilities can be leveraged to disrupt services or
  cause downtime.
- Compliance violations: Failure to address known vulnerabilities can lead to
  non-compliance with industry regulations and standards.

## How Docker Hardened Images help mitigate CVEs

Docker Hardened Images (DHIs) are crafted to minimize the risk of CVEs from the
outset. By adopting a security-first approach, DHIs offer several advantages in
CVE mitigation:

- Reduced attack surface: DHIs are built using a distroless approach, stripping
  away unnecessary components and packages. This reduction in image size, up to
  95% smaller than traditional images, limits the number of potential
  vulnerabilities, making it harder for attackers to exploit unneeded software.

- Faster CVE remediation: Maintained by Docker with an [enterprise-grade SLA](https://docs.docker.com/go/dhi-sla/),
  DHIs are continuously updated to address known vulnerabilities. Critical and
  high-severity CVEs are patched quickly, ensuring that your containers remain
  secure without manual intervention.

- Proactive vulnerability management: By utilizing DHIs, organizations can
  proactively manage vulnerabilities. The images come with CVE and Vulnerability
  Exposure (VEX) feeds, enabling teams to stay informed about potential threats
  and take necessary actions promptly.

## Scan images for CVEs

Regularly scanning Docker images for CVEs is essential for maintaining a secure
containerized environment. While Docker Scout is integrated into Docker Desktop
and the Docker CLI, tools like Grype and Trivy offer alternative scanning
capabilities. The following are instructions for using each tool to scan Docker
images for CVEs.

### Docker Scout

Docker Scout is integrated into Docker Desktop and the Docker CLI. It provides
vulnerability insights, CVE summaries, and direct links to remediation guidance.

#### Scan a DHI using Docker Scout

To scan a Docker Hardened Image using Docker Scout, run the following
command:

```console
$ docker scout cves dhi.io/<image>:<tag> --platform <platform>
```

Example output:

```plaintext
    v SBOM obtained from attestation, 101 packages found
    v Provenance obtained from attestation
    v VEX statements obtained from attestation
    v No vulnerable package detected
    ...
```

For more detailed filtering and JSON output, see [Docker Scout CLI reference](/reference/cli/docker/scout/).

### Grype

[Grype](https://github.com/anchore/grype) is an open-source scanner that checks
container images against vulnerability databases like the NVD and distro
advisories.

#### Scan a DHI using Grype

After installing Grype, you can scan a Docker Hardened Image by pulling
the image and running the scan command. Grype requires you to export the VEX
attestation to a file first:

```console
$ docker pull dhi.io/<image>:<tag>
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
$ grype dhi.io/<image>:<tag> --vex vex.json
```

Example output:

```plaintext
NAME               INSTALLED              FIXED-IN     TYPE  VULNERABILITY     SEVERITY    EPSS%  RISK
libperl5.36        5.36.0-7+deb12u2       (won't fix)  deb   CVE-2023-31484    High        79.45    1.1
perl               5.36.0-7+deb12u2       (won't fix)  deb   CVE-2023-31484    High        79.45    1.1
perl-base          5.36.0-7+deb12u2       (won't fix)  deb   CVE-2023-31484    High        79.45    1.1
...
```

### Trivy

[Trivy](https://github.com/aquasecurity/trivy) is an open-source vulnerability
scanner for containers and other artifacts. It detects vulnerabilities in OS
packages and application dependencies.

#### Scan a DHI using Trivy

After installing Trivy, you can scan a Docker Hardened Image by pulling
the image and running the scan command:

```console
$ docker pull dhi.io/<image>:<tag>
$ trivy image --scanners vuln --vex repo dhi.io/<image>:<tag>
```

Example output:

```plaintext
Report Summary

┌──────────────────────────────────────────────────────────────────────────────┬────────────┬─────────────────┬─────────┐
│                                    Target                                    │    Type    │ Vulnerabilities │ Secrets │
├──────────────────────────────────────────────────────────────────────────────┼────────────┼─────────────────┼─────────┤
│ dhi.io/<image>:<tag> (debian 12.11)                                          │   debian   │       66        │    -    │
├──────────────────────────────────────────────────────────────────────────────┼────────────┼─────────────────┼─────────┤
│ opt/python-3.13.4/lib/python3.13/site-packages/pip-25.1.1.dist-info/METADATA │ python-pkg │        0        │    -    │
└──────────────────────────────────────────────────────────────────────────────┴────────────┴─────────────────┴─────────┘
```

## Use VEX to filter known non-exploitable CVEs

Docker Hardened Images include signed [VEX (Vulnerability Exploitability
eXchange)](vex.md) attestations that identify vulnerabilities not relevant to the image’s
runtime behavior.

When using Docker Scout or Trivy, these VEX statements are automatically
applied using the previous examples, and no manual configuration needed.

To manually retrieve the VEX attestation for tools that support it:

```console
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
```

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python:3.13` instead of `dhi.io/python:3.13`.

For example:

```console
$ docker scout vex get dhi.io/python:3.13 --output vex.json
```

This creates a `vex.json` file containing the VEX statements for the specified
image. You can then use this file with tools that support VEX to filter out known non-exploitable CVEs.


---

# Image digests

*Sección: Dhi*

## What are Docker image digests?

A Docker image digest is a unique, cryptographic identifier (SHA-256 hash)
representing the content of a Docker image. Unlike tags, which can be reused or
changed, a digest is immutable and ensures that the exact same image is pulled
every time. This guarantees consistency across different environments and
deployments.

For example, the digest for the `nginx:latest` image might look like:

```text
sha256:94a00394bc5a8ef503fb59db0a7d0ae9e1110866e8aee8ba40cd864cea69ea1a
```

This digest uniquely identifies the specific version of the `nginx:latest` image,
ensuring that any changes to the image content result in a different digest.

## Why are image digests important?

Using image digests instead of tags offers several advantages:

- Immutability: Once an image is built and its digest is generated, the content
  tied to that digest cannot change. This means that if you pull an image using
  its digest, you can be confident that you are retrieving exactly the same
  image that was originally built.

- Security: Digests help prevent supply chain attacks by ensuring that the image
  content has not been tampered with. Even a small change in the image content
  will result in a completely different digest.

- Consistency: Using digests ensures that the same image is used across
  different environments, reducing the risk of discrepancies between
  development, staging, and production environments.

## Docker Hardened Image digests

By using image digests to reference DHIs, you can ensure that your applications are
always using the exact same secure image version, enhancing security and
compliance

## View an image digest

### Use the Docker CLI

To view the image digest of a Docker image, you can use the following command. Replace
`<image-name>:<tag>` with the image name and tag.

```console
$ docker buildx imagetools inspect <image-name>:<tag>
```

### Use the Docker Hub UI

1. Go to [Docker Hub](https://hub.docker.com/) and sign in.
2. Navigate to your organization's namespace and open the mirrored DHI repository.
3. Select the **Tags** tab to view image variants.
4. Each tag in the list includes a **Digest** field showing the image's SHA-256 value.

## Pull an image by digest

Pulling an image by digest ensures that you are pulling the exact image version
identified by the specified digest.

To pull a Docker image using its digest, use the following command. Replace
`<image-name>` with the image name and `<digest>` with the image digest.

```console
$ docker pull <image-name>@sha256:<digest>
```

For example, to pull a `docs/dhi-python:3.13` image using its digest of
`94a00394bc5a8ef503fb59db0a7d0ae9e1110866e8aee8ba40cd864cea69ea1a`, you would
run:

```console
$ docker pull docs/dhi-python@sha256:94a00394bc5a8ef503fb59db0a7d0ae9e1110866e8aee8ba40cd864cea69ea1a
```

## Multi-platform images and manifests

Docker Hardened Images are published as multi-platform images, which means
a single image tag (like `docs/dhi-python:3.13`) can support multiple operating
systems and CPU architectures, such as `linux/amd64`, `linux/arm64`, and more.

Instead of pointing to a single image, a multi-platform tag points to a manifest
list (also called an index), which is a higher-level object that references
multiple image digests, one for each supported platform.

When you inspect a multi-platform image using `docker buildx imagetools inspect`, you'll see something like this:

```text
Name:      docs/dhi-python:3.13
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:6e05...d231

Manifests:
  Name:        docs/dhi-python:3.13@sha256:94a0...ea1a
  Platform:    linux/amd64
  ...

  Name:        docs/dhi-python:3.13@sha256:7f1d...bc43
  Platform:    linux/arm64
  ...
```

- The manifest list digest (`sha256:6e05...d231`) identifies the overall
  multi-platform image.
- Each platform-specific image has its own digest (e.g., `sha256:94a0...ea1a`
  for `linux/amd64`).

### Why this matters

- Reproducibility: If you're building or running containers on different
  architectures, using a tag alone will resolve to the appropriate image digest
  for your platform.
- Verification: You can pull and verify a specific image digest for your
  platform to ensure you're using the exact image version, not just the manifest
  list.
- Policy enforcement: When enforcing digest-based policies with Docker Scout,
  each platform variant is evaluated individually using its digest.


---

# Minimal or distroless images

*Sección: Dhi*

Minimal images, sometimes called distroless images, are container images
stripped of unnecessary components such as package managers, shells, or even the
underlying operating system distribution. Docker Hardened Images (DHI) embrace
this minimal approach to reduce vulnerabilities and enforce secure software
delivery. [Docker Official
Images](../../../docker-hub/image-library/trusted-content.md#docker-official-images)
and [Docker Verified Publisher
Images](../../../docker-hub/image-library/trusted-content.md#verified-publisher-images)
follow similar best practices for minimalism and security but may not be as
stripped down to ensure compatibility with a wider range of use cases.

## What are minimal or distroless images?

Traditional container images include a full OS, often more than what is needed
to run an application. In contrast, minimal or distroless images include only:

- The application binary
- Its runtime dependencies (e.g., libc, Java, Python)
- Any explicitly required configuration or metadata

They typically exclude:

- OS tools (e.g., `ls`, `ps`, `cat`)
- Shells (e.g., `sh`, `bash`)
- Package managers (e.g., `apt`, `apk`)
- Debugging utilities (e.g., `curl`, `wget`, `strace`)

Docker Hardened Images are based on this model, ensuring a smaller and more
secure runtime surface.

## What you gain

| Benefit                | Description                                                                   |
|------------------------|-------------------------------------------------------------------------------|
| Smaller attack surface | Fewer components mean fewer vulnerabilities and less exposure to CVEs         |
| Faster startup         | Smaller image sizes result in faster pull and start times                     |
| Improved security      | Lack of shell and package manager limits what attackers can do if compromised |
| Better compliance      | Easier to audit and verify, especially with SBOMs and attestations            |

## Addressing common tradeoffs

Minimal and distroless images offer strong security benefits, but they can
change how you work with containers. Docker Hardened Images are designed to
maintain productivity while enhancing security.

| Concern           | How Docker Hardened Images help                                                                                                                                                                                         |
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Debuggability | Hardened images exclude shells and CLI tools by default. Use [Docker Debug](/reference/cli/docker/debug/) to temporarily attach a debug sidecar for troubleshooting without modifying the original container. |
| Familiarity   | DHI supports multiple base images, including Alpine and Debian variants, so you can choose a familiar environment while still benefiting from hardening practices.                                                        |
| Flexibility   | Runtime immutability helps secure your containers. Use multi-stage builds and CI/CD to control changes, and optionally use dev-focused base images during development.                                                  |

By balancing minimalism with practical tooling, Docker Hardened Images support
modern development workflows without compromising on security or reliability.

## Best practices for using minimal images

- Use multi-stage builds to separate build-time and runtime environments
- Validate image behavior using CI pipelines, not interactive inspection
- Include runtime-specific dependencies explicitly in your Dockerfile
- Use Docker Scout to continuously monitor for CVEs, even in minimal images

By adopting minimal or distroless images through Docker Hardened Images, you
gain a more secure, predictable, and production-ready container environment
that's designed for automation, clarity, and reduced risk.


---

# FIPS

*Sección: Dhi*

{{< summary-bar feature_name="Docker Hardened Images" >}}

## What is FIPS 140?

[FIPS 140](https://csrc.nist.gov/publications/detail/fips/140/3/final) is a U.S.
government standard that defines security requirements for cryptographic modules
that protect sensitive information. It is widely used in regulated environments
such as government, healthcare, and financial services.

FIPS certification is managed by the [NIST Cryptographic Module Validation
Program
(CMVP)](https://csrc.nist.gov/projects/cryptographic-module-validation-program),
which ensures cryptographic modules meet rigorous security standards.

## Why FIPS compliance matters

FIPS 140 compliance is required or strongly recommended in many regulated
environments where sensitive data must be protected, such as government,
healthcare, finance, and defense. These standards ensure that cryptographic
operations are performed using vetted, trusted algorithms implemented in secure
modules.

Using software components that rely on validated cryptographic modules can help organizations:

- Satisfy federal and industry mandates, such as FedRAMP, which require or
  strongly recommend FIPS 140-validated cryptography.
- Demonstrate audit readiness, with verifiable evidence of secure,
  standards-based cryptographic practices.
- Reduce security risk, by blocking unapproved or unsafe algorithms (e.g., MD5)
  and ensuring consistent behavior across environments.

## How Docker Hardened Images support FIPS compliance

While Docker Hardened Images are available to all, the FIPS variant requires a
paid Docker Hardened Images subscription.

Docker Hardened Images (DHIs) include variants that use cryptographic modules
validated under FIPS 140. These images are intended to help organizations meet
compliance requirements by incorporating components that meet the standard.

- FIPS image variants use cryptographic modules that are already validated under
  FIPS 140.
- These variants are built and maintained by Docker to support environments with
  regulatory or compliance needs.
- Docker provides signed test attestations that document the use of validated
  cryptographic modules. These attestations can support internal audits and
  compliance reporting.
- Entropy sources (random number generation for cryptographic operations) vary
  by base image. Debian-based images use the OpenSSL entropy source, while
  Alpine-based images source entropy from the host kernel.

> [!NOTE]
>
> Using a FIPS image variant helps meet compliance requirements but does not
> make an application or system fully compliant. Compliance depends on how the
> image is integrated and used within the broader system.

## Identify images that support FIPS

Docker Hardened Images that support FIPS are marked as **FIPS** compliant
in the Docker Hardened Images catalog.

To find DHI repositories with FIPS image variants, [search the catalog](../../how-to/search-evaluate.md) and:

- Use the **FIPS** filter on the catalog page
- Look for **FIPS** compliant on individual image listings

These indicators help you quickly locate repositories that support FIPS-based
compliance needs. Image variants that include FIPS support will have a tag
ending with `-fips`, such as `3.13-fips`.

## Use a FIPS variant

To use a FIPS variant, you must [mirror](../../how-to/mirror.md) the repository
and then pull the FIPS image from your mirrored repository.

## View the FIPS attestation

The FIPS variants of Docker Hardened Images contain a FIPS attestation that
lists the actual cryptographic modules included in the image.

You can retrieve and inspect the FIPS attestation using the Docker Scout CLI:

```console
$ docker scout attest get \
  --predicate-type https://docker.com/dhi/fips/v0.1 \
  --predicate \
  dhi.io/<image>:<tag>
```

For example:

```console
$ docker scout attest get \
  --predicate-type https://docker.com/dhi/fips/v0.1 \
  --predicate \
  dhi.io/python:3.13-fips
```

The attestation output is a JSON array describing the cryptographic modules
included in the image and their compliance status. For example:

```json
[
  {
    "certification": "CMVP #4985",
    "certificationUrl": "https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4985",
    "name": "OpenSSL FIPS Provider",
    "package": "pkg:dhi/openssl-provider-fips@3.1.2",
    "standard": "FIPS 140-3",
    "status": "active",
    "sunsetDate": "2030-03-10",
    "version": "3.1.2"
  }
]
```


---

# glibc and musl support in Docker Hardened Images

*Sección: Dhi*

Docker Hardened Images (DHI) are built to prioritize security without
sacrificing compatibility with the broader open source and enterprise software
ecosystem. A key aspect of this compatibility is support for common Linux
standard libraries: `glibc` and `musl`.

## What are glibc and musl?

When you run Linux-based containers, the image's C library plays a key role in
how applications interact with the operating system. Most modern Linux
distributions rely on one of the following standard C libraries:

- `glibc` (GNU C Library): The standard C library on mainstream distributions
  like Debian, Ubuntu, and Red Hat Enterprise Linux. It is widely supported and
  typically considered the most compatible option across languages, frameworks,
  and enterprise software.

- `musl`: A lightweight alternative to `glibc`, commonly used in minimal
  distributions like Alpine Linux. While it offers smaller image sizes and
  performance benefits, `musl` is not always fully compatible with software that
  expects `glibc`.

## DHI compatibility

DHI images are available in both `glibc`-based (e.g., Debian) and `musl`-based
(e.g., Alpine) variants. For enterprise applications and language runtimes where
compatibility is critical, we recommend using DHI images based on glibc.

## What to choose, glibc or musl?

Docker Hardened Images are available in both glibc-based (Debian) and musl-based
(Alpine) variants, allowing you to choose the best fit for your workload.

Choose Debian-based (`glibc`) images if:

- You need broad compatibility with enterprise workloads, language runtimes, or
  proprietary software.
- You're using ecosystems like .NET, Java, or Python with native extensions that
  depend on `glibc`.
- You want to minimize the risk of runtime errors due to library
  incompatibilities.

Choose Alpine-based (`musl`) images if:

- You want a minimal footprint with smaller image sizes and reduced surface
  area.
- You're building a custom or tightly controlled application stack where
  dependencies are known and tested.
- You prioritize startup speed and lean deployments over maximum compatibility.

If you're unsure, start with a Debian-based image to ensure compatibility, and
evaluate Alpine once you're confident in your application's dependencies.


---

# Base image hardening

*Sección: Dhi*

## What is base image hardening?

Base image hardening is the process of securing the foundational layers of a
container image by minimizing what they include and configuring them with
security-first defaults. A hardened base image removes unnecessary components,
like shells, compilers, and package managers, which limits the available attack
surface, making it more difficult for an attacker to gain control or escalate
privileges inside the container.

Hardening also involves applying best practices like running as a non-root user,
reducing writable surfaces, and ensuring consistency through immutability. While
[Docker Official
Images](../../../docker-hub/image-library/trusted-content.md#docker-official-images)
and [Docker Verified Publisher
Images](../../../docker-hub/image-library/trusted-content.md#verified-publisher-images)
follow best practices for security, they may not be as hardened as Docker
Hardened Images, as they are designed to support a broader range of use cases.

## Why is it important?

Most containers inherit their security posture from the base image they use. If
the base image includes unnecessary tools or runs with elevated privileges,
every container built on top of it is exposed to those risks.

Hardening the base image:

- Reduces the attack surface by removing tools and libraries that could be exploited
- Enforces least privilege by dropping root access and restricting what the container can do
- Improves reliability and consistency by avoiding runtime changes and drift
- Aligns with secure software supply chain practices and helps meet compliance standards

Using hardened base images is a critical first step in securing the software you
build and run in containers.

## What's removed and why

Hardened images typically exclude common components that are risky or unnecessary in secure production environments:

| Removed component                                | Reason                                                                           |
|--------------------------------------------------|----------------------------------------------------------------------------------|
| Shells (e.g., `sh`, `bash`)                      | Prevents users or attackers from executing arbitrary commands inside containers  |
| Package managers (e.g., `apt`, `apk`)            | Disables the ability to install software post-build, reducing drift and exposure |
| Compilers and interpreters                       | Avoids introducing tools that could be used to run or inject malicious code      |
| Debugging tools (e.g., `strace`, `curl`, `wget`) | Reduces risk of exploitation or information leakage                              |
| Unused libraries or locales                      | Shrinks image size and minimizes attack vectors                                  |

## How Docker Hardened Images apply base image hardening

Docker Hardened Images (DHIs) apply base image hardening principles by design.
Each image is constructed to include only what is necessary for its specific
purpose, whether that’s building applications (with `-dev` or `-sdk` tags) or
running them in production.

### Docker Hardened Image traits

Docker Hardened Images are built to be:

- Minimal: Only essential libraries and binaries are included
- Immutable: Images are fixed at build time—no runtime installations
- Non-root by default: Containers run as an unprivileged user unless configured otherwise
- Purpose-scoped: Different tags are available for development (`-dev`), SDK-based builds (`-sdk`), and production runtime

These characteristics help enforce consistent, secure behavior across development, testing, and production environments.

### Docker Hardened Image compatibility considerations

Because Docker Hardened Images strip out many common tools, they may not work out of the box for all use cases. You may need to:

- Use multi-stage builds to compile code or install dependencies in a `-dev` image and copy the output into a hardened runtime image
- Replace shell scripts with equivalent entrypoint binaries or explicitly include a shell if needed
- Use [Docker Debug](/reference/cli/docker/debug/) to temporarily inspect or troubleshoot containers without altering the base image

These trade-offs are intentional and help support best practices for building secure, reproducible, and production-ready containers.


---

# Immutable infrastructure

*Sección: Dhi*

Immutable infrastructure is a security and operations model where components
such as servers, containers, and images are never modified after deployment.
Instead of patching or reconfiguring live systems, you replace them entirely
with new versions.

When using Docker Hardened Images, immutability is a best practice that
reinforces the security posture of your software supply chain.

## Why immutability matters

Mutable systems are harder to secure and audit. Live patching or manual updates
introduce risks such as:

- Configuration drift
- Untracked changes
- Inconsistent environments
- Increased attack surface

Immutable infrastructure solves this by making changes only through controlled,
repeatable builds and deployments.

## How Docker Hardened Images support immutability

Docker Hardened Images are built to be minimal, locked-down, and
non-interactive, which discourages in-place modification. For example:

- Many DHI images exclude shells, package managers, and debugging tools
- DHI images are designed to be scanned and signed before deployment
- DHI users are encouraged to rebuild and redeploy images rather than patch running containers

This design aligns with immutable practices and ensures that:

- Updates go through the CI/CD pipeline
- All changes are versioned and auditable
- Systems can be rolled back or reproduced consistently

## Immutable patterns in practice

Some common patterns that leverage immutability include:

- Container replacement: Instead of logging into a container to fix a bug or
  apply a patch, rebuild the image and redeploy it.
- Infrastructure as Code (IaC): Define your infrastructure and image
  configurations in version-controlled files.
- Blue/Green or Canary deployments: Roll out new images alongside old ones and
  gradually shift traffic to the new version.

By combining immutable infrastructure principles with hardened images, you
create a predictable and secure deployment workflow that resists tampering and
minimizes long-term risk.


---

# Image provenance

*Sección: Dhi*

## What is image provenance?

Image provenance refers to metadata that traces the origin, authorship, and
integrity of a container image. It answers critical questions such as:

- Where did this image come from?
- Who built it?
- Has it been tampered with?

Provenance establishes a chain of custody, helping you verify that the image
you're using is the result of a trusted and verifiable build process.

## Why image provenance matters

Provenance is foundational to securing your software supply chain. Without it, you risk:

- Running unverified or malicious images
- Failing to meet internal or regulatory compliance requirements
- Losing visibility into the components and workflows that produce your containers

With reliable provenance, you gain:

- Trust: Know that your images are authentic and unchanged.
- Traceability: Understand the full build process and source inputs.
- Auditability: Provide verifiable evidence of compliance and build integrity.

Provenance also supports automated policy enforcement and is a key requirement
for frameworks like SLSA (Supply-chain Levels for Software Artifacts).

## How Docker Hardened Images support provenance

Docker Hardened Images (DHIs) are designed with built-in provenance to help you
adopt secure-by-default practices and meet supply chain security standards.

### Attestations

DHIs include [attestations](attestations.md)—machine-readable metadata that
describe how, when, and where the image was built. These are generated using
industry standards such as [in-toto](https://in-toto.io/) and align with [SLSA
provenance](https://slsa.dev/spec/v1.0/provenance/).

Attestations allow you to:

- Validate that builds followed the expected steps
- Confirm that inputs and environments meet policy
- Trace the build process across systems and stages

### Code signing

Each Docker Hardened Image is cryptographically [signed](signatures.md) and
stored in the registry alongside its digest. These signatures are verifiable
proofs of authenticity and are compatible with tools like `cosign`, Docker
Scout, and Kubernetes admission controllers.

With image signatures, you can:

- Confirm that the image was published by Docker
- Detect if an image has been modified or republished
- Enforce signature validation in CI/CD or production deployments

## Additional resources

- [Provenance attestations](/build/metadata/attestations/slsa-provenance/)
- [Image signatures](signatures.md)
- [Attestations overview](attestations.md)


---

# Software Bill of Materials (SBOMs)

*Sección: Dhi*

## What is an SBOM?

An SBOM is a detailed inventory that lists all components, libraries, and
dependencies used in building a software application. It provides transparency
into the software supply chain by documenting each component's version, origin,
and relationship to other components. Think of it as a "recipe" for your
software, detailing every ingredient and how they come together.

Metadata included in an SBOM for describing software artifacts may include:

- Name of the artifact
- Version
- License type
- Authors
- Unique package identifier

## Why are SBOMs important?

In today's software landscape, applications often comprise numerous components
from various sources, including open-source libraries, third-party services, and
proprietary code. This complexity can obscure visibility into potential
vulnerabilities and complicate compliance efforts. SBOMs address these
challenges by providing a detailed inventory of all components within an
application.


The significance of SBOMs is underscored by several key factors:

- Enhanced transparency: SBOMs offer a comprehensive view of all components that
  constitute an application, enabling organizations to identify and assess risks
  associated with third-party libraries and dependencies.

- Proactive vulnerability management: By maintaining an up-to-date SBOM,
  organizations can swiftly identify and address vulnerabilities in software
  components, reducing the window of exposure to potential exploits.

- Regulatory compliance: Many regulations and industry standards now require
  organizations to maintain control over the software components they use. An
  SBOM facilitates compliance by providing a clear and accessible record.

- Improved incident response: In the event of a security breach, an SBOM
  enables organizations to quickly identify affected components and take
  appropriate action, minimizing potential damage.

## Docker Hardened Image SBOMs

Docker Hardened Images have SBOMs, ensuring that every component
in the image is documented and verifiable. These SBOMs are cryptographically
signed, providing a tamper-evident record of the image's contents. This
integration simplifies audits and enhances trust in the software supply chain.

## View SBOMs in Docker Hardened Images

To view the SBOM of a Docker Hardened Image, you can use the `docker scout sbom`
command. Replace `<image-name>:<tag>` with the image name and tag.

```console
$ docker scout sbom dhi.io/<image-name>:<tag>
```

## Verify the SBOM of a Docker Hardened Image

Since Docker Hardened Images come with signed SBOMs, you can use Docker Scout to
verify the authenticity and integrity of the SBOM attached to the image. This
ensures that the SBOM has not been tampered with and that the image's contents
are trustworthy.

To verify the SBOM of a Docker Hardened Image using Docker Scout, use the following command:

```console
$ docker scout attest get dhi.io/<image-name>:<tag> \
   --predicate-type https://scout.docker.com/sbom/v0.1 --verify --platform <platform>
```

For example, to verify the SBOM attestation for the `node:20.19-debian12` image:

```console
$ docker scout attest get dhi.io/node:20.19-debian12 \
   --predicate-type https://scout.docker.com/sbom/v0.1 --verify --platform linux/amd64
```

## Resources

For more details about SBOM attestations and Docker Build, see [SBOM
attestations](/build/metadata/attestations/sbom/).

To learn more about Docker Scout and working with SBOMs, see [Docker Scout SBOMs](../../../scout/how-tos/view-create-sboms.md).


---

# Code signing

*Sección: Dhi*

## What is code signing?

Code signing is the process of applying a cryptographic signature to software
artifacts, such as Docker images, to verify their integrity and authenticity. By
signing an image, you ensure that it has not been altered since it was signed
and that it originates from a trusted source.

In the context of Docker Hardened Images (DHIs), code signing is achieved using
[Cosign](https://docs.sigstore.dev/), a tool developed by the Sigstore project.
Cosign enables secure and verifiable signing of container images, enhancing
trust and security in the software supply chain.

## Why is code signing important?

Code signing plays a crucial role in modern software development and
cybersecurity:

- Authenticity: Verifies that the image was created by a trusted source.
- Integrity: Ensures that the image has not been tampered with since it was
  signed.
- Compliance: Helps meet regulatory and organizational security requirements.

## Docker Hardened Image code signing

Each DHI is cryptographically signed using Cosign, ensuring that the images have
not been tampered with and originate from a trusted source.

## Why sign your own images?

Docker Hardened Images are signed by Docker to prove their origin and integrity,
but if you're building application images that extend or use DHIs as a base, you
should sign your own images as well.

By signing your own images, you can:

- Prove the image was built by your team or pipeline
- Ensure your build hasn't been tampered with after it's pushed
- Support software supply chain frameworks like SLSA
- Enable image verification in deployment workflows

This is especially important in CI/CD environments where you build and push
images frequently, or in any scenario where image provenance must be auditable.

## How to view and use code signatures

### View signatures

You can verify that a Docker Hardened Image is signed and trusted using either Docker Scout or Cosign.

To lists all attestations, including signature metadata, attached to the image, use the following command:

```console
$ docker scout attest list <image-name>:<tag>
```

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python` instead of `dhi.io/python`.

To verify a specific signed attestation (e.g., SBOM, VEX, provenance):

```console
$ docker scout attest get \
  --predicate-type <predicate-uri> \
  --verify \
  <image-name>:<tag>
```

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python:3.13` instead of `dhi.io/python:3.13`.

For example:

```console
$ docker scout attest get \
  --predicate-type https://openvex.dev/ns/v0.2.0 \
  --verify \
  dhi.io/python:3.13
```

If valid, Docker Scout will confirm the signature and display signature payload, as well as the equivalent Cosign command to verify the image.

### Sign images

To sign a Docker image, use [Cosign](https://docs.sigstore.dev/). Replace
`<image-name>:<tag>` with the image name and tag.

```console
$ cosign sign <image-name>:<tag>
```

This command will prompt you to authenticate via an OIDC provider (such as
GitHub, Google, or Microsoft). Upon successful authentication, Cosign will
generate a short-lived certificate and sign the image. The signature will be
stored in a transparency log and associated with the image in the registry.


---

# Supply-chain Levels for Software Artifacts (SLSA)

*Sección: Dhi*

## What is SLSA?

Supply-chain Levels for Software Artifacts (SLSA) is a security framework
designed to enhance the integrity and security of software supply chains.
Developed by Google and maintained by the Open Source Security Foundation
(OpenSSF), SLSA provides a set of guidelines and best practices to prevent
tampering, improve integrity, and secure packages and infrastructure in software
projects.

SLSA defines [four build levels (0–3)](https://slsa.dev/spec/latest/build-track-basics) of
increasing security rigor, focusing on areas such as build provenance, source
integrity, and build environment security. Each level builds upon the previous
one, offering a structured approach to achieving higher levels of software
supply chain security.

## Why is SLSA important?

SLSA is crucial for modern software development due to the increasing complexity
and interconnectedness of software supply chains. Supply chain attacks, such as
the SolarWinds breach, have highlighted the vulnerabilities in software
development processes. By implementing SLSA, organizations can:

- Ensure artifact integrity: Verify that software artifacts have not been
  tampered with during the build and deployment processes.

- Enhance build provenance: Maintain verifiable records of how and when software
  artifacts were produced, providing transparency and accountability.

- Secure build environments: Implement controls to protect build systems from
  unauthorized access and modifications.

- Mitigate supply chain risks: Reduce the risk of introducing vulnerabilities or
  malicious code into the software supply chain.

## What is SLSA Build Level 3?

SLSA Build Level 3, Hardened Builds, is the highest of four progressive levels in
the SLSA framework. It introduces strict requirements to ensure that software
artifacts are built securely and traceably. To meet Level 3, a build must:

- Be fully automated and scripted to prevent manual tampering
- Use a trusted build service that enforces source and builder authentication
- Generate a signed, tamper-resistant provenance record describing how the artifact was built
- Capture metadata about the build environment, source repository, and build steps

This level provides strong guarantees that the software was built from the
expected source in a controlled, auditable environment, which significantly
reduces the risk of supply chain attacks.

## Docker Hardened Images and SLSA

Docker Hardened Images (DHIs) are secure-by-default container images
purpose-built for modern production environments. Each DHI is cryptographically
signed and complies with the [SLSA Build Level 3
standard](https://slsa.dev/spec/latest/build-track-basics#build-l3), ensuring
verifiable build provenance and integrity.

By integrating SLSA-compliant DHIs into your development and deployment processes, you can:

- Achieve higher security levels: Utilize images that meet stringent security
  standards, reducing the risk of vulnerabilities and attacks.

- Simplify compliance: Leverage built-in features like signed Software Bills of
  Materials (SBOMs) and vulnerability exception (VEX) statements to facilitate
  compliance with regulations such as FedRAMP.

- Enhance transparency: Access detailed information about the components and
  build process of each image, promoting transparency and trust.

- Streamline audits: Utilize verifiable build records and signatures to simplify
  security audits and assessments.

## Get and verify SLSA provenance for Docker Hardened Images

Each Docker Hardened Image (DHI) is cryptographically signed and includes
attestations. These attestations provide verifiable build provenance and
demonstrate adherence to SLSA Build Level 3 standards.

To get and verify SLSA provenance for a DHI, you can use Docker Scout.

```console
$ docker scout attest get dhi.io/<image>:<tag> \
  --predicate-type https://slsa.dev/provenance/v0.2 \
  --verify
```

For example:

```console
$ docker scout attest get dhi.io/node:20.19-debian12 \
  --predicate-type https://slsa.dev/provenance/v0.2 \
  --verify
```

## Resources

For more details about SLSA definitions and Docker Build, see [SLSA
definitions](/build/metadata/attestations/slsa-definitions/).


---

# Software Supply Chain Security

*Sección: Dhi*

## What is Software Supply Chain Security (SSCS)?

SSCS encompasses practices and strategies designed to safeguard the entire
lifecycle of software development from initial code creation to deployment and
maintenance. It focuses on securing all components. This includes code,
dependencies, build processes, and distribution channels in order to prevent
malicious actors from compromising the software supply chain. Given the
increasing reliance on open-source libraries and third-party components,
ensuring the integrity and security of these elements is paramount

## Why is SSCS important?

The significance of SSCS has escalated due to sophisticated cyberattacks
targeting software supply chains. High-profile supply chain attacks and the
exploitation of vulnerabilities in open-source components underscore the
critical need for robust supply chain security measures. Compromises at any
stage of the software lifecycle can lead to widespread vulnerabilities, data
breaches, and significant financial losses.

## How Docker Hardened Images contribute to SSCS

Docker Hardened Images (DHI) are purpose-built container images designed with
security at their core, addressing the challenges of modern software supply
chain security. By integrating DHI into your development and deployment
pipelines, you can enhance your organization's SSCS posture through the
following features:

- Minimal attack surface: DHIs are engineered to be ultra-minimal, stripping
  away unnecessary components and reducing the attack surface by up to 95%. This
  distroless approach minimizes potential entry points for malicious actors.

- Cryptographic signing and provenance: Each DHI is cryptographically signed,
  ensuring authenticity and integrity. Build provenance is maintained, providing
  verifiable evidence of the image's origin and build process, aligning with
  standards like SLSA (Supply-chain Levels for Software Artifacts).

- Software Bill of Materials (SBOM): DHIs include a comprehensive SBOM,
  detailing all components and dependencies within the image. This transparency
  aids in vulnerability management and compliance tracking, enabling teams to
  assess and mitigate risks effectively.

- Continuous maintenance and rapid CVE remediation: Docker maintains DHIs with
  regular updates and security patches, backed by an [SLA for addressing critical
  and high-severity vulnerabilities](https://docs.docker.com/go/dhi-sla/). This proactive approach helps ensure that
  images remain secure and compliant with enterprise standards.


---

# Secure Software Development Lifecycle

*Sección: Dhi*

## What is a Secure Software Development Lifecycle?

A Secure Software Development Lifecycle (SSDLC) integrates security practices
into every phase of software delivery, from design and development to deployment
and monitoring. It’s not just about writing secure code, but about embedding
security throughout the tools, environments, and workflows used to build and
ship software.

SSDLC practices are often guided by compliance frameworks, organizational
policies, and supply chain security standards such as SLSA (Supply-chain Levels
for Software Artifacts) or NIST SSDF.

## Why SSDLC matters

Modern applications depend on fast, iterative development, but rapid delivery
often introduces security risks if protections aren’t built in early. An SSDLC
helps:

- Prevent vulnerabilities before they reach production
- Ensure compliance through traceable and auditable workflows
- Reduce operational risk by maintaining consistent security standards
- Enable secure automation in CI/CD pipelines and cloud-native environments

By making security a first-class citizen in each stage of software delivery,
organizations can shift left and reduce both cost and complexity.

## How Docker supports a secure SDLC

Docker provides tools and secure content that make SSDLC practices easier to
adopt across the container lifecycle. With [Docker Hardened
Images](../index.md) (DHIs), [Docker
Debug](/reference/cli/docker/debug/), and [Docker
Scout](../../../scout/index.md), teams can add security without losing
velocity.

### Plan and design

During planning, teams define architectural constraints, compliance goals, and
threat models. Docker Hardened Images help at this stage by providing:

- Secure-by-default base images for common languages and runtimes
- Verified metadata including SBOMs, provenance, and VEX documents
- Support for both glibc and musl across multiple Linux distributions

You can use DHI metadata and attestations to support design reviews, threat
modeling, or architecture sign-offs.

### Develop

In development, security should be transparent and easy to apply. Docker
Hardened Images support secure-by-default development:

- Dev variants include shells, package managers, and compilers for convenience
- Minimal runtime variants reduce attack surface in final images
- Multi-stage builds let you separate build-time tools from runtime environments

[Docker Debug](/reference/cli/docker/debug/) helps developers:

- Temporarily inject debugging tools into minimal containers
- Avoid modifying base images during troubleshooting
- Investigate issues securely, even in production-like environments

### Build and test

Build pipelines are an ideal place to catch issues early. Docker Scout
integrates with Docker Hub and the CLI to:

- Scan for known CVEs using multiple vulnerability databases
- Trace vulnerabilities to specific layers and dependencies
- Interpret signed VEX data to suppress known-irrelevant issues
- Export JSON scan reports for CI/CD workflows

Build pipelines that use Docker Hardened Images benefit from:

- Reproducible, signed images
- Minimal build surfaces to reduce exposure
- Built-in compliance with SLSA Build Level 3 standards

### Release and deploy

Security automation is critical as you release software at scale. Docker
supports this phase by enabling:

- Signature verification and provenance validation before deployment
- Policy enforcement gates using Docker Scout
- Safe, non-invasive container inspection using Docker Debug

DHIs ship with the metadata and signatures required to automate image
verification during deployment.

### Monitor and improve

Security continues after release. With Docker tools, you can:

- Continuously monitor image vulnerabilities through Docker Hub
- Get CVE remediation guidance and patch visibility using Docker Scout
- Receive updated DHI images with rebuilt and re-signed secure layers
- Debug running workloads with Docker Debug without modifying the image

## Summary

Docker helps teams embed security throughout the SSDLC by combining secure
content (DHIs) with developer-friendly tooling (Docker Scout and Docker Debug).
These integrations promote secure practices without introducing friction, making
it easier to adopt compliance and supply chain security across your software
delivery lifecycle.


---

# STIG

*Sección: Dhi*

{{< summary-bar feature_name="Docker Hardened Images" >}}

## What is STIG?

[Security Technical Implementation Guides
(STIGs)](https://public.cyber.mil/stigs/) are configuration standards published
by the U.S. Defense Information Systems Agency (DISA). They define security
requirements for operating systems, applications, databases, and other
technologies used in U.S. Department of Defense (DoD) environments.

STIGs help ensure that systems are configured securely and consistently to
reduce vulnerabilities. They are often based on broader requirements like the
DoD's General Purpose Operating System Security Requirements Guide (GPOS SRG).

## Why STIG guidance matters

Following STIG guidance is critical for organizations that work with or support
U.S. government systems. It demonstrates alignment with DoD security standards
and helps:

- Accelerate Authority to Operate (ATO) processes for DoD systems
- Reduce the risk of misconfiguration and exploitable weaknesses
- Simplify audits and reporting through standardized baselines

Even outside of federal environments, STIGs are used by security-conscious
organizations as a benchmark for hardened system configurations.

STIGs are derived from broader NIST guidance, particularly [NIST Special
Publication 800-53](https://csrc.nist.gov/publications/sp800), which defines a
catalog of security and privacy controls for federal systems. Organizations
pursuing compliance with 800-53 or related frameworks (such as FedRAMP) can use
STIGs as implementation guides that help meet applicable control requirements.

## How Docker Hardened Images help apply STIG guidance

Docker Hardened Images (DHIs) include STIG variants that are scanned against
custom STIG-based profiles and include signed STIG scan attestations. These
attestations can support audits and compliance reporting.

While Docker Hardened Images are available to all, the STIG variant requires a
Docker subscription.

Docker creates custom STIG-based profiles for images based on the GPOS SRG and
DoD Container Hardening Process Guide. Because DISA has not published a STIG
specifically for containers, these profiles help apply STIG-like guidance to
container environments in a consistent, reviewable way and are designed to
reduce false positives common in container images.

## Identify images that include STIG scan results

Docker Hardened Images that include STIG scan results are labeled as **STIG** in
the Docker Hardened Images catalog.

To find DHI repositories with STIG image variants, [explore
images](../../tools/hub.md#images-page) and:

- Use the **STIG** filter on the catalog page
- Look for **STIG** labels on individual image listings

To find a STIG image variant within a repository, go to the **Tags** tab in the
repository, and find images labeled with **STIG** in the **Compliance** column.

## Use a STIG variant

To use a STIG variant, you must [mirror](../../how-to/mirror.md) the repository
and then pull the STIG image from your mirrored repository.

## View and verify STIG scan results

Docker provides a signed [STIG scan
attestation](attestations.md) for each STIG-ready image.
These attestations include:

- A summary of the scan results, including the number of passed, failed, and not
  applicable checks
- The name and version of the STIG profile used
- Full output in both HTML and XCCDF (XML) formats

### View STIG scan attestations

You can retrieve and inspect a STIG scan attestation using the Docker Scout CLI:

```console
$ docker scout attest get \
  --predicate-type https://docker.com/dhi/stig/v0.1 \
  --verify \
  --predicate \
  dhi.io/<image>:<tag>
```

### Extract HTML report

To extract and view the human-readable HTML report:

```console
$ docker scout attest get dhi.io/<image>:<tag> \
  --predicate-type https://docker.com/dhi/stig/v0.1 \
  --verify \
  --predicate \
  | jq -r '.[0].output[] | select(.format == "html").content | @base64d' > stig_report.html
```

### Extract XCCDF report

To extract the XML (XCCDF) report for integration with other tools:

```console
$ docker scout attest get dhi.io/<image>:<tag> \
  --predicate-type https://docker.com/dhi/stig/v0.1 \
  --verify \
  --predicate \
  | jq -r '.[0].output[] | select(.format == "xccdf").content | @base64d' > stig_report.xml
```

### View STIG scan summary

To view just the scan summary without the full reports:

```console
$ docker scout attest get dhi.io/<image>:<tag> \
  --predicate-type https://docker.com/dhi/stig/v0.1 \
  --verify \
  --predicate \
  | jq -r '.[0] | del(.output)'
```


---

# Vulnerability Exploitability eXchange (VEX)

*Sección: Dhi*

## What is VEX?

Vulnerability Exploitability eXchange (VEX) is a specification for documenting
the exploitability status of vulnerabilities within software components. VEX is
primarily defined through industry standards such as CSAF (OASIS) and CycloneDX
VEX, with the U.S. Cybersecurity and Infrastructure Security Agency (CISA)
encouraging its adoption. VEX complements CVE (Common Vulnerabilities and
Exposures) identifiers by adding producer-asserted status information,
indicating whether a vulnerability is exploitable in the product as shipped.
This helps organizations prioritize remediation efforts by identifying
vulnerabilities that do not affect their specific product configurations.

For how VEX affects vulnerability counts and scanner selection, see [Scanner
integrations](../scanner-integrations.md). To scan a DHI with
VEX support, see [Scan Docker Hardened Images](../../how-to/scan.md).

## VEX status reference

Each VEX statement includes a `status` field that records Docker's
exploitability assessment for a given CVE and image. OpenVEX defines four
status values. DHI uses three of them:

| Status | Meaning |
|---|---|
| `not_affected` | The CVE was reported against a package in the image, but Docker has assessed it is not exploitable as shipped |
| `under_investigation` | Docker is aware of the CVE and is actively evaluating whether it affects the image |
| `affected` | Docker has confirmed the CVE is exploitable in the image and a fix is not yet available |
| `fixed` | The vulnerability has been remediated in this version. DHI does not use this status (see below). |

You can view the VEX statements for any DHI using Docker Scout. See [Scan Docker
Hardened Images](../../how-to/scan.md). To query suppressed CVEs
programmatically by image digest, see [Query suppressed CVEs for a DHI by
digest](../../how-to/vex-api.md).

### `not_affected` justification codes

`not_affected` statements include a machine-readable `justification` field
explaining why the vulnerability does not apply:

| Justification | Meaning |
|---|---|
| `component_not_present` | The vulnerable component is not present in this image; the CVE matched by name against a different package |
| `vulnerable_code_not_present` | The vulnerable code path was not compiled into this build |
| `vulnerable_code_not_in_execute_path` | The vulnerable code exists in the package but is not called in this image's runtime configuration |
| `vulnerable_code_cannot_be_controlled_by_adversary` | The vulnerable code exists but an attacker cannot trigger it in this configuration |
| `inline_mitigations_already_exist` | Docker has applied a backport or patch that addresses the CVE |

### Why DHI does not use `fixed`

DHI does not use `fixed`. VEX-enabled scanners may not handle `fixed`
consistently, so when Docker backports an upstream patch where the version
number alone would not reflect the fix, it uses `not_affected` with
`inline_mitigations_already_exist` justification instead.


---

# How Docker Hardened Images are tested

*Sección: Dhi*

Docker Hardened Images (DHIs) are designed to be secure, minimal, and
production-ready. To ensure their reliability and security, Docker employs a
comprehensive testing strategy, which you can independently verify using signed
attestations and open tooling.

Every image is tested for standards compliance, functionality, and security. The
results of this testing are embedded as signed attestations, which can be
[inspected and verified](#view-and-verify-the-test-attestation) programmatically
using the Docker Scout CLI.

## Testing strategy overview

The testing process for DHIs focuses on two main areas:

- Image standards compliance: Ensuring that each image adheres to strict size,
  security, and compatibility standards.
- Application functionality: Verifying that applications within the images
  function correctly.

## Image standards compliance

Each DHI undergoes rigorous checks to meet the following standards:

- Minimal attack surface: Images are built to be as small as possible, removing
  unnecessary components to reduce potential vulnerabilities.
- Near-zero known CVEs: Images are scanned using tools like Docker Scout to
  ensure they are free from known Common Vulnerabilities and Exposures (CVEs).
- Multi-architecture support: DHIs are built for multiple architectures
  (`linux/amd64` and `linux/arm64`) to ensure broad compatibility.
- Kubernetes compatibility: Images are tested to run seamlessly within
  Kubernetes clusters, ensuring they meet the requirements for container
  orchestration environments.

## Application functionality testing

Docker tests Docker Hardened Images to ensure they behave as expected in typical
usage scenarios. This includes verifying that:

- Applications start and run successfully in containerized environments.
- Runtime behavior aligns with upstream expectations.
- Build variants (like `-dev` images) support common development and build tasks.

The goal is to ensure that DHIs work out of the box for the most common use
cases while maintaining the hardened, minimal design.

## Automated testing and CI/CD integration

Docker integrates automated testing into its Continuous Integration/Continuous
Deployment (CI/CD) pipelines:

- Automated scans: Each image build triggers automated scans for vulnerabilities
  and compliance checks.
- Reproducible builds: Build processes are designed to be reproducible, ensuring
  consistency across different environments.
- Continuous monitoring: Docker continuously monitors for new vulnerabilities
  and updates images accordingly to maintain security standards.

## Testing attestation

Docker provides a test attestation that details the testing and validation
processes each DHI has undergone.

### View and verify the test attestation

You can view and verify this attestation using the Docker Scout CLI.

1. Use the `docker scout attest get` command with the test predicate type:

   ```console
   $ docker scout attest get \
     --predicate-type https://scout.docker.com/tests/v0.1 \
     --predicate \
     dhi.io/<image>:<tag>
   ```

   > [!NOTE]
   >
   > If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
   > `registry://dhi.io/python` instead of `dhi.io/python`.

   For example:

   ```console
   $ docker scout attest get \
     --predicate-type https://scout.docker.com/tests/v0.1 \
     --predicate \
     dhi.io/python:3.13
   ```

   This contains a list of tests and their results.

   Example output:

    ```console
        v SBOM obtained from attestation, 101 packages found
        v Provenance obtained from attestation
        {
          "reportFormat": "CTRF",
          "results": {
            "summary": {
              "failed": 0,
              "passed": 1,
              "skipped": 0,
              "start": 1749216533,
              "stop": 1749216574,
              "tests": 1
            },
            "tests": [
              {
                ...
   ```

2. Verify the test attestation signature. To ensure the attestation is authentic
   and signed by Docker, run:

   ```console
   docker scout attest get \
     --predicate-type https://scout.docker.com/tests/v0.1 \
     --verify \
     dhi.io/<image>:<tag> --platform <platform>
   ```

   Example output:
   
   ```console
    v SBOM obtained from attestation, 101 packages found
    v Provenance obtained from attestation
    v cosign verify registry.scout.docker.com/docker/dhi-python@sha256:70c8299c4d3cb4d5432734773c45ae58d8acc2f2f07803435c65515f662136d5 \
        --key https://registry.scout.docker.com/keyring/dhi/latest.pub --experimental-oci11

      Verification for registry.scout.docker.com/docker/dhi-python@sha256:70c8299c4d3cb4d5432734773c45ae58d8acc2f2f07803435c65515f662136d5 --
      The following checks were performed on each of these signatures:
        - The cosign claims were validated
        - Existence of the claims in the transparency log was verified offline
        - The signatures were verified against the specified public key

    i Signature payload
    ...
    ```

If the attestation is valid, Docker Scout will confirm the signature and show
the matching `cosign verify` command.

To view other attestations, such as SBOMs or vulnerability reports, see [Verify
an image](../how-to/verify.md).


---

# What are hardened images and why use them?

*Sección: Dhi*

In today’s diverse software environments, container images are often designed
for flexibility and broad compatibility. While that makes them ideal for many
use cases, it can also result in images that include more components than needed
for specific workloads. Docker Hardened Images take a minimal-by-design approach
to help reduce image size, limit the attack surface, and streamline security and
compliance workflows.

Hardened images solve this by minimizing what's in the container image. Less
software means fewer vulnerabilities, faster deployments, and fewer red
dashboards to chase down every week.

For platform engineers and security teams, hardened images offer a way out of
the CVE triage cycle, letting you focus on delivering secure, compliant
infrastructure without constant firefighting.

## What is a hardened image?

A hardened image is a container image that has been deliberately minimized and
secured to reduce vulnerabilities and meet stringent security and compliance
requirements. Unlike standard images, which may include non-essential components
that increase risk, hardened images are streamlined to include only what’s
needed to run your application securely. For a deeper look at the techniques
involved, see [Base image hardening](security-concepts/hardening.md).

## Benefits of hardened images

- Reduced attack surface: By removing non-essential components, hardened images
  limit potential entry points for attackers.
- Improved security posture: Regular updates and vulnerability scans help ensure
  hardened images remain secure over time.
- Compliance facilitation: Inclusion of signed metadata like SBOMs supports
  meeting regulatory and organizational compliance standards.
- Operational efficiency: Smaller image sizes lead to faster pulls, lower runtime overhead, and reduced cloud resource costs.

## What is a Docker Hardened Image?

Docker Hardened Images (DHIs) take hardened images even further by combining
minimal, secure design with enterprise-grade support and tooling. Built with
security at the core, these images are continuously maintained, tested, and
validated to meet today’s toughest software supply chain and compliance
standards.

Docker Hardened Images are secure by default, minimal by design, and maintained
so you don’t have to.

## How Docker Hardened Images differ from generic hardened images

- SLSA-compliant builds: Docker Hardened Images are built to meet [SLSA Build
  Level 3](security-concepts/slsa.md), ensuring a tamper-resistant, verifiable,
  and auditable build process that protects against supply chain threats.

-  Distroless approach: Unlike traditional base images that bundle an entire OS
   with shells, package managers, and debugging tools, [distroless
   images](security-concepts/distroless.md) retain only the minimal OS components
   required to run your application. By excluding unnecessary tooling and
   libraries, they reduce the attack surface by up to 95% and can improve
   performance and image size.

- Continuous maintenance: All DHIs are continuously monitored and updated to
  maintain near-zero known exploitable [CVEs](security-concepts/cves.md), helping
  your teams avoid patch fatigue and surprise alerts.

- Compliance-ready: Each image includes cryptographically signed metadata:
  - [SBOMs](security-concepts/sbom.md) that show what's in the image
  - [VEX documents](security-concepts/vex.md) to identify which vulnerabilities
    are actually exploitable
  - [Build provenance](security-concepts/provenance.md) that proves how and where
    the image was built

- Compatibility-focused design: Docker Hardened Images provide a minimal runtime
  environment while maintaining compatibility with common Linux distributions.
  They remove non-essential components like shells and package managers to
  enhance security, yet retain a small base layer built on familiar distribution
  standards. Images are typically available with musl libc (Alpine-based) and
  glibc (Debian-based), supporting a broad range of application compatibility
  needs.

## Why use Docker Hardened Images?

Docker Hardened Images (DHIs) are secure by default, minimal by design, and
maintained so you don't have to. They offer:


- Images built for peace of mind: Ultra-minimal and distroless, DHIs eliminate up to 95% of the traditional container attack surface.
- No more patch panic: With continuous CVE scanning and [SLA-backed remediation](https://docs.docker.com/go/dhi-sla/), Docker helps you stay ahead of threats.
- Audit-ready images: All DHIs include signed SBOMs, VEX, and provenance that support security and compliance workflows.
- Images that work with your stack: Available in Alpine and Debian flavors, DHIs drop into your existing Dockerfiles and pipelines.
- Images backed by enterprise support: Get peace of mind with Docker's support and rapid response to critical vulnerabilities.


---

# Docker Hardened Images quickstart

*Sección: Dhi*

This guide shows you how to go from zero to running a Docker Hardened Image
(DHI) using a real example. At the end, you'll compare the DHI to a standard
Docker image to better understand the differences. While the steps use a
specific image as an example, they can be applied to any DHI.

This quickstart uses DHI Community images from `dhi.io`. You sign in with your
Docker account, pull and run an image, and compare it with a Docker Official Image.

> [!NOTE]
>
> If you have a DHI Select or Enterprise subscription, see [Get started with DHI
> Select and Enterprise](how-to/select-enterprise.md) instead. Select and
> Enterprise use mirrored repositories in your organization namespace on Docker
> Hub to enable customization, SLA-backed security updates, and access to
> compliance variants.

## Step 1: Find an image to use

1. Go to the Hardened Images catalog in [Docker
   Hub](https://hub.docker.com/hardened-images/catalog).
2. Use the search bar or filters to find an image (for example, `python`,
   `node`, or `golang`). For this example, search for `python`.
3. Select the Python repository to view its details.

Continue to the next step to pull and run the image. To dive deeper into searching
and evaluating images, see [Search and evaluate Docker Hardened Images](how-to/search-evaluate.md).

## Step 2: Pull and run the image

You can pull and run a DHI like any other Docker image. Note that Docker Hardened
Images are designed to be minimal and secure, so they may not include all the
tools or libraries you expect in a typical image. You can view the typical
differences in [Considerations when adopting
DHIs](how-to/use.md#considerations-when-adopting-dhis).

The following example demonstrates that you can run the Python image and execute
a simple Python command just like you would with any other Docker image:

1. Open a terminal and sign in to the Docker Hardened Images registry using your
   Docker account credentials.

   ```console
   $ docker login dhi.io
   ```

   > [!TIP]
   >
   > If you don't have a Docker account, [create a free
   > account](https://hub.docker.com/signup) to get started.

2. Pull the image:

   ```console
   $ docker pull dhi.io/python:3.13
   ```

3. Run the image to confirm everything works:

    ```console
    $ docker run --rm dhi.io/python:3.13 python -c "print('Hello from DHI')"
    ```

    This starts a container from the `python:3.13` image and runs a simple
    Python script that prints `Hello from DHI`.

To dive deeper into using images, see:

- [Use a Docker Hardened Image](how-to/use.md) for general usage
- [Use a Helm chart](how-to/helm.md) for deploying with Helm

## Step 3: Compare with other images

You can quickly compare DHIs with other images to see the security
improvements and differences. This comparison helps you understand the value of
using hardened images.

Run the following command to compare the Docker Hardened Image for Python with
the non-hardened Docker Official Image for Python from Docker Hub. Look for the
`## Overview` section in the output for a summary comparison.

```console
$ docker scout compare dhi.io/python:3.13 \
    --to python:3.13 \
    --platform linux/amd64 \
    --ignore-unchanged
```

The `## Overview` section of the output looks similar to the following:

```plaintext
  ## Overview

                      │                    Analyzed Image                     │               Comparison Image
  ────────────────────┼───────────────────────────────────────────────────────┼───────────────────────────────────────────────
    Target            │  dhi.io/python:3.13                                   │  python:3.13
      digest          │  c215e9da9f84                                         │  7f48e892134c
      tag             │  3.13                                                 │  3.13
      platform        │ linux/amd64                                           │ linux/amd64
      provenance      │ https://github.com/docker-hardened-images/definitions │ https://github.com/docker-library/python.git
                      │  77a629b3d0db035700206c2a4e7ed904e5902ea8             │  3f2d7e4c339ab883455b81a873519f1d0f2cd80a
      vulnerabilities │    0C     0H     0M     0L                            │    0C     1H     5M   141L     2?
                      │           -1     -5   -141     -2                     │
      size            │ 35 MB (-377 MB)                                       │ 412 MB
      packages        │ 80 (-530)                                             │ 610
                      │                                                       │
```

> [!NOTE]
>
> This is example output. Your results may vary depending on newly discovered
> CVEs and image updates.

Docker maintains near-zero CVEs in Docker Hardened Images. For DHI Select and
Enterprise subscriptions, when new CVEs are discovered, the CVEs are remediated
within the industry-leading SLA time frame. Learn more about the [SLA-backed
security features](index.md#sla-backed-security).

This comparison shows that the Docker Hardened Image:

- Removes vulnerabilities: 1 high, 5 medium, 141 low, and 2 unspecified severity CVEs removed
- Reduces size: From 412 MB down to 35 MB (91% reduction)
- Minimizes packages: From 610 packages down to 80 (87% reduction)

To dive deeper into comparing images see [Search and evaluate Docker Hardened Images](how-to/search-evaluate.md#compare-and-evaluate-images).

## What's next

You've pulled and run your first Docker Hardened Image. Here are a few ways to keep going:

- [Migrate existing applications to DHIs](migration/migrate-with-ai.md): Use
  Gordon to update your Dockerfiles to use Docker Hardened Images as the base.

- [Start a trial](https://hub.docker.com/hardened-images/start-free-trial) to
  explore the benefits of a DHI subscription, such as access to FIPS and STIG
  variants, customized images, and SLA-backed updates.

- [Get started with DHI Select and Enterprise](how-to/select-enterprise.md):
  After subscribing to a DHI subscription or starting a trial, learn how to
  mirror repositories, customize images, and access compliance variants.

- [Verify DHIs](how-to/verify.md): Use tools like [Docker Scout](/scout/) or
  Cosign to inspect and verify signed attestations, like SBOMs and provenance.

- [Scan DHIs](how-to/scan.md): Analyze the image with Docker Scout or other
  scanners to identify known CVEs.


---

# How-tos

*Sección: Dhi*

This section provides practical, task-based guidance for working with Docker
Hardened Images (DHIs). Whether you're evaluating DHIs for the first time or
integrating them into a production CI/CD pipeline, these topics cover the key
tasks across the adoption journey: discover, adopt, verify, and govern.

The topics are organized around the typical lifecycle of working with DHIs, but
you can use them as needed based on your specific workflow.

Explore the topics below that match your current needs.

## Discover

Explore available images and metadata in the DHI catalog.

{{< grid
  items="grid_discover"
>}}

## Adopt

Mirror trusted images, customize as needed, and integrate into your workflows.

{{< grid
  items="grid_adopt"
>}}

## Verify

Check signatures, SBOMs, and provenance, and scan for vulnerabilities.

{{< grid
  items="grid_verify"
>}}

## Govern

Enforce policies to maintain security and compliance.

{{< grid
  items="grid_govern"
>}}

## Troubleshoot

{{< grid
  items="grid_troubleshoot"
>}}


---

# Create and build a Docker Hardened Image

*Sección: Dhi*

Docker Hardened Images (DHI) are built from declarative YAML definition files
instead of traditional Dockerfiles. A single YAML file describes exactly what
goes into an image: packages, users, environment variables, entrypoint, and
metadata. The DHI build system produces a signed image containing only the required
packages, with a Software Bill of Materials (SBOM) and SLSA Build Level 3
provenance.

This page explains how to write a DHI definition file, build images locally, and
use advanced patterns such as build stages, third-party repositories, file
paths, and dev variants.

> [!IMPORTANT]
>
> The DHI build system pulls base images and build tools from `dhi.io`, so you
> must authenticate to that registry before building a definition file. Use your
> Docker ID credentials (the same username and password you use for Docker Hub)
> when signing in.
>
> Run `docker login dhi.io` to authenticate.

## How DHI builds differ from Dockerfiles

A Dockerfile is a sequence of imperative instructions: `RUN`, `COPY`, `FROM`.
A DHI definition file is a declarative specification. You describe the desired
state of the image, and the build system figures out how to produce it.

Every DHI definition starts with a syntax directive that tells BuildKit which
DHI build frontend to use. The frontend is the component that parses and
processes YAML definitions instead of the default Dockerfile parser:

```yaml
# syntax=dhi.io/build:2-alpine3.23
```

The frontend version corresponds to the base distribution:

| Distribution        | Syntax directive                       |
|---------------------|----------------------------------------|
| Alpine 3.22         | `# syntax=dhi.io/build:2-alpine3.22`  |
| Alpine 3.23         | `# syntax=dhi.io/build:2-alpine3.23`  |
| Alpine 3.24         | `# syntax=dhi.io/build:2-alpine3.24`  |
| Debian 12 (Bookworm)| `# syntax=dhi.io/build:2-debian12`    |
| Debian 13 (Trixie)  | `# syntax=dhi.io/build:2-debian13`    |

The DHI build system reads the YAML, resolves packages from the specified
repositories, assembles the filesystem, creates user accounts, sets metadata,
and produces a signed OCI image.

## Explore the catalog for reference

The [DHI catalog repository](https://github.com/docker-hardened-images/catalog)
is open source under Apache 2.0 and contains every official image definition.
Studying existing definitions is the best way to learn the YAML patterns for
different image types.

The catalog follows this directory structure:

```text
catalog/
├── image/
│   ├── alpine-base/
│   │   ├── alpine-3.23/
│   │   │   ├── 3.23.yaml            # runtime variant
│   │   │   └── 3.23-dev.yaml        # dev variant
│   │   ├── guides.md
│   │   ├── info.yaml
│   │   ├── logo.svg
│   │   └── overview.md
│   ├── nginx/
│   │   ├── alpine-3.22/
│   │   ├── alpine-3.23/
│   │   │   ├── mainline.yaml
│   │   │   ├── mainline-dev.yaml
│   │   │   ├── stable.yaml
│   │   │   └── stable-dev.yaml
│   │   ├── debian-12/
│   │   ├── debian-13/
│   │   ├── bin/
│   │   ├── guides.md
│   │   ├── info.yaml
│   │   ├── logo.svg
│   │   └── overview.md
│   └── redis/
│       ├── debian-13/
│       │   ├── 8.0.yaml              # runtime
│       │   ├── 8.0-dev.yaml          # dev
│       │   ├── 8.0-compat.yaml       # compat runtime
│       │   └── 8.0-compat-dev.yaml   # compat dev
│       ├── guides.md
│       ├── info.yaml
│       ├── logo.svg
│       └── overview.md
├── chart/
└── package/
```

Each image organizes its variants by distribution. Images support multiple
variant types:

- A `runtime` variant is minimal and typically runs as a non-root user.
- A `dev` variant adds a shell, package manager, and development tools.
- A compatibility variant adds common shell utilities such as `bash`,
  `coreutils`, `grep`, and `sed` for use with existing workflows. Compatibility
  images use the `flavor: compat` field alongside a `runtime` or `dev` variant.
- A compatibility-dev variant combines the compatibility packages with dev
  tools.

Some images also support additional flavors such as `sfw` (software framework)
variants. Refer to the catalog for the full list of available variants for each
image.

## Try it: build a catalog image

Before writing your own definition, try building an existing catalog image
directly from GitHub:

```console
$ docker buildx build \
    https://raw.githubusercontent.com/docker-hardened-images/catalog/refs/heads/main/image/alpine-base/alpine-3.23/3.23.yaml \
    --sbom=generator=dhi.io/scout-sbom-indexer:1 \
    --provenance=1 \
    --tag my-alpine-base:3.23 \
    --load
```

This downloads the definition file directly from GitHub and builds it locally.
After the build completes, verify the image:

```console
$ docker images my-alpine-base
```

To modify an image, clone the catalog and edit the YAML files locally:

```console
$ git clone https://github.com/docker-hardened-images/catalog.git
$ cd catalog
```

## YAML schema reference

The following sections describe the fields available in a DHI definition file.

### Required fields

Every definition must include these top-level fields:

| Field       | Description                                                         |
|-------------|---------------------------------------------------------------------|
| `name`      | Human-readable name for the image.                                  |
| `image`     | Full registry path, such as `dhi.io/my-image`.                      |
| `variant`   | Image variant type: `runtime` or `dev`.                             |
| `tags`      | List of image tags.                                                 |
| `platforms`  | Target architectures, such as `linux/amd64` and `linux/arm64`.     |
| `contents`  | Package repositories and packages to install.                       |

### Image metadata

These fields add metadata to the image:

| Field         | Description                                                       |
|---------------|-------------------------------------------------------------------|
| `os-release`  | Defines the `/etc/os-release` contents inside the image.          |
| `annotations` | OCI image annotations such as description and license.            |
| `dates`       | Release date and end-of-life date.                                |
| `vars`        | Build-time variables for templating.                              |
| `flavor`      | Image flavor modifier, such as `compat` for compatibility images.|

### Container configuration

These fields control how the container runs:

| Field         | Description                                                       |
|---------------|-------------------------------------------------------------------|
| `accounts`    | Users, groups, and the `run-as` user.                             |
| `environment` | Environment variables.                                            |
| `entrypoint`  | Container entrypoint command.                                     |
| `cmd`         | Default command arguments.                                        |
| `work-dir`    | Working directory inside the container.                           |
| `volumes`     | Volume mount points.                                              |
| `ports`       | Exposed network ports.                                            |
| `paths`       | Directories, files, and symlinks to create.                       |

### Advanced fields

These fields support more complex build patterns:

| Field                | Description                                                  |
|----------------------|--------------------------------------------------------------|
| `contents.builds`    | Build stages with shell pipelines.                           |
| `contents.keyring`   | Signing keys for third-party package repositories.           |
| `contents.artifacts` | Pre-built OCI artifacts to include.                          |
| `contents.mappings`  | Package URL (purl) mappings for SBOM accuracy.               |
| `contents.files`     | Source files fetched from Git URLs with checksums.            |

## Create a minimal image

Start with the simplest possible definition: an Alpine base image with a
non-root user.

Create a directory for your project and add a file called `base.yaml`:

```yaml
# syntax=dhi.io/build:2-alpine3.23

name: My Base Image
image: my-registry/my-base
variant: runtime
tags:
  - "1.0.0"
  - "1.0"
platforms:
  - linux/amd64
  - linux/arm64

contents:
  repositories:
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/main
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/community
  packages:
    - alpine-baselayout-data
    - busybox
    - ca-certificates-bundle

accounts:
  run-as: nonroot
  users:
    - name: nonroot
      uid: 65532
      gid: 65532
  groups:
    - name: nonroot
      gid: 65532
      members:
        - nonroot

os-release:
  name: Docker Hardened Images (Alpine)
  id: alpine
  version-id: "3.23"
  pretty-name: My Hardened Image
  home-url: https://docker.com/products/hardened-images/
  bug-report-url: https://docker.com/support/

environment:
  SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt

annotations:
  org.opencontainers.image.description: A minimal Alpine base image

cmd:
  - /bin/sh
```

In this definition:

- `contents.repositories` uses full URLs to Alpine package mirrors.
- `contents.packages` lists exact Alpine package names.
- The `accounts` block creates a `nonroot` user (UID 65532) and sets it as the
  default user for the container.
- The `os-release` block defines what appears in `/etc/os-release`. Always
  include `bug-report-url` alongside `home-url`.
- The `annotations` block adds OCI metadata visible in registries and Docker
  Scout reports.

Build the image:

```console
$ docker buildx build . -f base.yaml \
    --sbom=generator=dhi.io/scout-sbom-indexer:1 \
    --provenance=1 \
    --tag my-base:latest \
    --load
```
> [!NOTE]
>
> The `tags` field in the spec file defines the image metadata (variant and
> version labels embedded in the image manifest). The `--tag` flag on the CLI
> sets the OCI image reference used to push or load the image. These serve
> different purposes - the spec file tags describe *what the image is*, while
> the CLI tag determines *where it's stored*.

## Use a Debian base with third-party repositories

For applications that require Debian packages or third-party APT repositories,
use the Debian syntax directive. The following example builds a Redis image
from the official Redis APT repository.

Create a file called `redis.yaml`:

```yaml
# syntax=dhi.io/build:2-debian13

name: Redis 8.0.x
image: my-registry/my-redis
variant: runtime
tags:
  - "8.0"
  - "8.0.5"
platforms:
  - linux/amd64
  - linux/arm64

contents:
  repositories:
    - deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb trixie main
  keyring:
    - https://packages.redis.io/gpg
  packages:
    - '!libelogind0'
    - '!mawk'
    - '!original-awk'
    - base-files
    - libpcre2-8-0
    - libssl3t64
    - libstdc++6
    - libsystemd0
    - redis=6:8.0.5-1rl1~trixie1
    - redis-server=6:8.0.5-1rl1~trixie1
    - redis-tools=6:8.0.5-1rl1~trixie1
    - tini
  mappings:
    redis: pkg:deb/redis/redis@6:8.0.5-1rl1~trixie1?os_name=debian&os_version=13
    redis-server: pkg:deb/redis/redis-server@6:8.0.5-1rl1~trixie1?os_name=debian&os_version=13
    redis-tools: pkg:deb/redis/redis-tools@6:8.0.5-1rl1~trixie1?os_name=debian&os_version=13

accounts:
  run-as: nonroot
  users:
    - name: nonroot
      uid: 65532
      gid: 65532
  groups:
    - name: nonroot
      gid: 65532
      members:
        - nonroot

os-release:
  name: Docker Hardened Images (Debian)
  id: debian
  version-id: "13"
  version-codename: trixie
  pretty-name: Docker Hardened Images/Debian GNU/Linux 13 (trixie)
  home-url: https://docker.com/products/hardened-images/
  bug-report-url: https://docker.com/support/

work-dir: /data

environment:
  REDIS_VERSION: 8.0.5

annotations:
  org.opencontainers.image.description: A minimal Redis image
  org.opencontainers.image.licenses: AGPL-3.0-only

entrypoint:
  - /usr/bin/tini
  - --

cmd:
  - redis-server
  - /etc/redis/redis.conf
  - --include
  - /etc/redis/conf.d/*.conf
```

This example introduces several patterns:

- **Third-party repositories**: The `repositories` field uses the Debian
  `deb [signed-by=...] URL suite component` format for APT sources.
- **Keyring**: The `keyring` field downloads the GPG key used to verify packages
  from the third-party repository.
- **Package exclusions**: Prefix a package name with `!` to explicitly exclude
  it. This prevents unwanted dependencies from being installed. In this case,
  `!libelogind0`, `!mawk`, and `!original-awk` are excluded.
- **Debian version pinning**: Use the full epoch format,
  `redis-server=6:8.0.5-1rl1~trixie1`, to pin exact package versions.
- **SBOM mappings**: The `mappings` field provides Package URL (purl) metadata
  so that Docker Scout can accurately identify the software in the SBOM.
- **Init process**: The `entrypoint` uses `tini` as a lightweight init process
  (PID 1) to handle signal forwarding and zombie process reaping.
- **Config includes**: The `cmd` uses `--include /etc/redis/conf.d/*.conf` so
  that configuration files created in the `paths` section are loaded at startup.

## Create paths

Use the `paths` field to create directories, files with inline content, and
symlinks inside the image. The following example extends the Redis definition
with the paths required for operation:

```yaml
paths:
  - type: directory
    path: /var/lib/redis
    uid: 65532
    gid: 65532
    mode: "0755"
  - type: directory
    path: /var/log/redis
    uid: 65532
    gid: 65532
    mode: "0755"
  - type: directory
    path: /run/redis/
    uid: 65532
    gid: 65532
    mode: "0755"
  - type: directory
    path: /data
    uid: 65532
    gid: 65532
    mode: "0755"
  - type: file
    path: /etc/redis/conf.d/docker.conf
    content: |
      daemonize no
      bind 0.0.0.0 -::1
      logfile ""
    uid: 0
    gid: 0
    mode: "0555"
  - type: symlink
    path: /usr/bin/redis-sentinel
    uid: 0
    gid: 0
    source: /usr/bin/redis-check-rdb
```

Three path types are available:

| Type        | Required fields                  | Description                          |
|-------------|----------------------------------|--------------------------------------|
| `directory` | `path`, `uid`, `gid`, `mode`     | Creates an empty directory.          |
| `file`      | `path`, `content`, `uid`, `gid`, `mode` | Creates a file with inline content. |
| `symlink`   | `path`, `source`, `uid`, `gid`   | Creates a symbolic link.             |

The `mode` field uses a string representation of the octal permission bits,
such as `"0755"` for read-write-execute by owner or `"0555"` for read-execute
by all. Note that the `file` type supports inline `content` using a YAML
multi-line string.

## Add build stages

For images that need to run shell commands during the build, such as
configuring files, creating symlinks, or adjusting permissions, use the
`contents.builds` field. Each build stage has its own packages, a pipeline
of named steps, and output mappings.

The following example configures Nginx during the build to run on an
unprivileged port and disable server tokens:

```yaml
# syntax=dhi.io/build:2-alpine3.23

name: Nginx mainline
image: my-registry/my-nginx
variant: runtime
tags:
  - "1.29"
platforms:
  - linux/amd64
  - linux/arm64

contents:
  repositories:
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/main
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/community
    - http://nginx.org/packages/mainline/alpine/v3.23/main
  keyring:
    - https://nginx.org/keys/nginx_signing.rsa.pub
  packages:
    - alpine-baselayout-data
    - busybox
    - musl-utils
    - nginx=1.29.5-r1
  builds:
    - name: nginx
      contents:
        repositories:
          - https://dl-cdn.alpinelinux.org/alpine/v3.23/main
          - https://dl-cdn.alpinelinux.org/alpine/v3.23/community
          - http://nginx.org/packages/mainline/alpine/v3.23/main
        keyring:
          - https://nginx.org/keys/nginx_signing.rsa.pub
        packages:
          - alpine-baselayout-data
          - bash
          - musl-utils
          - nginx=1.29.5-r1
      pipeline:
        - name: install
          runs: |
            set -eux -o pipefail

            ln -sf /dev/stdout /var/log/nginx/access.log
            ln -sf /dev/stderr /var/log/nginx/error.log

            sed -i "s,listen       80;,listen       8080;," /etc/nginx/conf.d/default.conf
            sed -i "/user  nginx;/d" /etc/nginx/nginx.conf
            sed -i "s,pid        /run/nginx.pid;,pid        /var/run/nginx.pid;," /etc/nginx/nginx.conf
            sed -i '/^http {$/a\    server_tokens off;' /etc/nginx/nginx.conf

            chown -R 65532:65532 /var/cache/nginx
            chmod -R g+w /var/cache/nginx
            chown -R 65532:65532 /etc/nginx
            chmod -R g+w /etc/nginx
            chown -R 65532:65532 /run
            chown -R 65532:65532 /run/lock
            chown -R 65532:65532 /var/run
            chown -R 65532:65532 /var/log/nginx
      outputs:
        - source: /
          target: /
          uid: 0
          gid: 0
          diff: true

accounts:
  run-as: nginx
  users:
    - name: nginx
      uid: 65532
      gid: 65532
  groups:
    - name: nginx
      gid: 65532
      members:
        - nginx
    - name: www-data
      gid: 82

os-release:
  name: Docker Hardened Images (Alpine)
  id: alpine
  version-id: "3.23"
  pretty-name: Docker Hardened Images/Alpine Linux v3.23
  home-url: https://docker.com/products/hardened-images/
  bug-report-url: https://docker.com/support/

environment:
  NGINX_VERSION: 1.29.5-r1

annotations:
  org.opencontainers.image.description: A minimal Nginx image
  org.opencontainers.image.licenses: BSD-2-Clause

entrypoint:
  - nginx

cmd:
  - -g
  - daemon off;

ports:
  - 8080/tcp
```

Key patterns in this definition:

| Element     | Description                                                                |
|-------------|----------------------------------------------------------------------------|
| `contents`  | Each build stage has its own `contents` section. Include packages needed only during the build, such as `bash`. |
| `pipeline`  | Contains named steps that run shell commands. Always start scripts with `set -eux -o pipefail`. |
| `outputs`   | Copies results from the build stage into the final image. Setting `diff: true` copies only files that changed, keeping the image minimal. |
| `accounts`  | Nginx uses a dedicated `nginx` user (UID 65532) instead of `nonroot`. The `www-data` group (GID 82) is also created for web server compatibility. |
| `musl-utils` | Required in both the main and build packages for Alpine-based Nginx images. |

## Use OCI artifacts as package sources

Instead of installing packages from Alpine or Debian repositories, you can pull
pre-built binaries from DHI package artifacts. This is how the catalog builds
images like Python and Node.js — the runtime is compiled separately and
published as an OCI artifact, then referenced by digest in the image definition.

Add the `artifacts` field under `contents`:

```yaml
contents:
  repositories:
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/main
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/community
  packages:
    - alpine-baselayout-data
    - bzip2
    - ca-certificates-bundle
    - expat
    - gdbm
    - libffi
    - mpdecimal
    - musl
    - ncurses
    - openssl
    - readline
    - sqlite-libs
    - tzdata
    - zlib
  artifacts:
    - name: dhi.io/pkg-python:3.13.12-alpine3.23@sha256:052b3b915055006a27c42470eed5c65d7ee92d2c3de47ecaedcc6bbd36077b95
      includes:
        - opt/**
      uid: 0
      gid: 0
```

| Field      | Description                                                                  |
|------------|------------------------------------------------------------------------------|
| `name`     | Full OCI reference with digest pin. Always use `@sha256:` for reproducibility. |
| `includes` | Glob patterns for files to extract from the artifact. Paths are resolved from the filesystem root; `opt/**` includes everything under the `/opt` path. |
| `excludes` | Glob patterns for files to skip. Useful for removing headers, docs, or unused binaries. |
| `uid`, `gid` | Ownership for extracted files.                                             |

Available DHI packages are in the
[`package/`](https://github.com/docker-hardened-images/catalog/tree/main/package)
directory of the catalog repository.

## Create a dev variant

A dev variant of an image adds a shell, package manager, and development tools.
This is useful for debugging and for use as a build stage in multi-stage
workflows.

To create a dev variant, change the `variant` field and enable root access:

```yaml
# syntax=dhi.io/build:2-alpine3.23

name: Alpine 3.23 Base (dev)
image: my-registry/my-base
variant: dev
tags:
  - "1.0-dev"
platforms:
  - linux/amd64
  - linux/arm64

contents:
  repositories:
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/main
    - https://dl-cdn.alpinelinux.org/alpine/v3.23/community
  packages:
    - alpine-baselayout-data
    - apk-tools
    - busybox
    - ca-certificates-bundle

accounts:
  root: true
  run-as: root
  users:
    - name: nonroot
      uid: 65532
      gid: 65532
  groups:
    - name: nonroot
      gid: 65532
      members:
        - nonroot

os-release:
  name: Docker Hardened Images (Alpine)
  id: alpine
  version-id: "3.23"
  pretty-name: Docker Hardened Images/Alpine Linux v3.23
  home-url: https://docker.com/products/hardened-images/
  bug-report-url: https://docker.com/support/

environment:
  SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt

annotations:
  org.opencontainers.image.description: A minimal Alpine base image

cmd:
  - /bin/sh
```

The key differences from a runtime variant:

- `variant: dev` instead of `variant: runtime`.
- `accounts.root: true` enables the root account.
- `run-as: root` sets root as the default user.
- `apk-tools` is added to packages, giving the image a package manager.
- The `nonroot` user is still defined so that applications can switch to an
  unprivileged user at runtime.

For Debian-based dev variants, add `apt` instead of `apk-tools` and include the
`DEBIAN_FRONTEND: noninteractive` environment variable.

## Create a compatibility variant

A compatibility variant includes common shell utilities for use with
scripts and automation tools that expect a standard Linux userland. Compatibility
images use the `flavor` field:

```yaml
variant: runtime
flavor: compat
```

A compatibility variant adds packages such as `bash`, `coreutils`, `findutils`,
`grep`, `hostname`, `openssl`, `procps`, and `sed` alongside the application
packages. A compatibility-dev variant combines both the compatibility packages
and the dev tools:

```yaml
variant: dev
flavor: compat
```

Refer to the Redis compatibility images in the catalog for a complete example of
the compatibility pattern.

## Set ports and volumes

Use the `ports` field to declare which ports the container exposes. Always use
unprivileged ports (higher than 1024) when the container runs as a non-root
user.

```yaml
ports:
  - 8080/tcp
```

Use the `volumes` field to declare volume mount points:

```yaml
volumes:
  - /data
```

## Set annotations

OCI annotations add machine-readable metadata to the image. Use the
`annotations` field:

```yaml
annotations:
  org.opencontainers.image.description: A minimal hardened application image
  org.opencontainers.image.licenses: Apache-2.0
```

These annotations appear in Docker Scout reports and container registry
interfaces.

## Build and verify

### Build the image

Build a single-platform image for local testing:

```console
$ docker buildx build . -f my-image.yaml \
    --sbom=generator=dhi.io/scout-sbom-indexer:1 \
    --provenance=1 \
    --tag my-image:latest \
    --load
```

### Inspect the SBOM

View the generated Software Bill of Materials:

```console
$ docker scout sbom my-image:latest
```

### Scan for vulnerabilities

Check the image against known CVE databases:

```console
$ docker scout cves my-image:latest
```

### Compare with a non-hardened image

Measure the security improvement against an equivalent non-hardened image:

```console
$ docker scout compare my-image:latest \
    --to <non-hardened-equivalent>:<tag> \
    --platform linux/amd64
```

Replace `<non-hardened-equivalent>` with the Docker Official Image or
community image you're comparing against.

### Inspect with Docker Debug

Verify the os-release and entrypoint configuration:

```console
$ docker debug my-image:latest
```

The output shows the detected distribution name from your `os-release`
configuration and runs an entrypoint lint check.

## Push to a registry

Tag and push the image to your container registry:

```console
$ docker tag my-image:latest <your-namespace>/my-image:latest
```

```console
$ docker push <your-namespace>/my-image:latest
```

Replace `<your-namespace>` with your Docker Hub username or organization
namespace.

## Contribute to the catalog

Docker Hardened Images is an open source project. You can contribute new image
definitions or improve existing ones by submitting a pull request to the
[catalog repository](https://github.com/docker-hardened-images/catalog).

To contribute a new image:

1. Fork the catalog repository.
2. Create a directory under `image/` following the naming convention:
   `image/<image-name>/<distribution>/`.
3. Add your YAML definition files (one per variant).
4. Add an `info.yaml` with display name, description, and categories.
5. Add an `overview.md` describing the image.
6. Add a `logo.svg` for the image icon.
7. Add a `guides.md` with usage documentation.
8. Open a pull request against the `main` branch.

For more details, read the
[contributing guide](https://github.com/docker-hardened-images/catalog/blob/main/CONTRIBUTING.md)
in the catalog repository.


---

# Customize a Docker Hardened Image or chart

*Sección: Dhi*

{{< summary-bar feature_name="Docker Hardened Images" >}}

When you have a DHI Select or DHI Enterprise subscription, you can customize Docker
Hardened Images (DHI) and charts to suit your specific needs using the Docker
Hub web interface. For images, this lets you select a base image, add packages,
add OCI artifacts (such as custom certificates or additional tools), and
configure settings. For charts, this lets you customize the image references.

Your customizations stay secure automatically. When the base Docker Hardened
Image or chart receives a security patch or your OCI artifacts are updated,
Docker automatically rebuilds your customizations in the background. This
ensures continuous compliance and protection by default, with no manual work
required. The rebuilt artifacts are signed and attested to the same SLSA Build
Level 3 standard as the base images and charts, ensuring a secure and verifiable
supply chain.

## Customize a Docker Hardened Image

To add a customized Docker Hardened Image to your organization, an organization
owner must first [mirror](mirror.md) the DHI repository to your organization
on Docker Hub. Once the repository is mirrored, any user with access to the
mirrored DHI repository can create a customized image.

You can create customizations using either the DHI CLI or the Docker Hub web interface.

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Sign in to [Docker Hub](https://hub.docker.com).
1. Select **My Hub**.
1. In the namespace drop-down, select your organization that has a mirrored DHI
   repository.
1. Select **Hardened Images** > **Manage** > **Mirrored Images**.
1. For the mirrored DHI repository you want to customize, select the menu icon in the far right column.
1. Select **Customize**.

   At this point, the on-screen instructions will guide you through the
   customization process. You can continue with the following steps for more
   details.

1. Select one or more images or Helm charts and versions you want to customize.

   When selecting multiple images and versions, all selections must share the
   same distribution and distribution version. For example, you can select
   `dhi-node:22_alpine3.23` and `dhi-python:3.13_alpine3.23` together (both
   Alpine 3.23), but you cannot mix `dhi-node:22_debian` with Alpine images, or
   mix different Alpine versions like `alpine3.23` and `alpine3.22`.

   Alternatively, you can select multiple Helm chart versions to apply the same
   customization to all of them. You cannot mix images and Helm charts in the
   same customization.

1. Select **Next**.
1. Optional. Add packages.

   1. In the packages drop-down, select the packages you want to add to the
      image.

      The packages available in the drop-down are OS system packages for the
      selected image variant. For version 3.23 and later Alpine-based images,
      these are hardened packages that have been built from source by Docker with
      cryptographic signatures and full supply chain security. For version 3.22
      Alpine-based images and Debian-based images, these are standard system
      packages.

   1. In the **OCI artifacts** drop-down, first, select the repository that
      contains the OCI artifact image. Then, select the tag you want to use from
      that repository. Finally, specify the specific paths you want to include
      from the OCI artifact image.

      The OCI artifacts are images that you have previously
      built and pushed to a repository in the same namespace as the mirrored
      DHI. For example, you can add a custom root CA certificate or another
      image that contains a tool you need, like adding Python to a Node.js
      image.

      You can add multiple OCI artifact images to a single customization. When
      you add more than one, they're applied in the order you add them in the
      **OCI artifacts** drop-down. If multiple images contain directories or
      files with the same path, images added later overwrite files from images
      added earlier. To manage this, you must select paths to include and
      optionally exclude from each OCI artifact image. This allows you to
      control which files are included in the final customized image.

      By default, no files are included from the OCI artifact image. You must
      explicitly include the paths you want. After including a path, you can
      then explicitly exclude files or directories underneath it.

      > [!NOTE]
      >
      > When files necessary for runtime are overwritten by OCI artifacts, the
      > image build still succeeds, but you may have issues when running the
      > image.

      For more details, see [OCI artifacts](#oci-artifacts).

   1. In the **Scripts** section, you can add, edit, or remove scripts.

      Scripts let you add files to the container image that you can access at runtime. They are not executed during
      the build process. This is useful for services that require pre-start initialization, such as setup scripts or
      file writes to directories like `/var/lock` or `/out`.

      You must specify the following:

      - The path where the script will be placed
      - The script content
      - The UID and GID ownership of the script
      - The octal file permissions of the script

1. Select **Next: Configure** to configure the following image settings:

   > [!NOTE]
   >
   > When customizing multiple images at once, many of these configuration
   > options are limited by default and may not be available.

   1. Specify the [environment variables](/reference/dockerfile/#env) and their
      values that the image will contain.
   1. Add [labels](/reference/dockerfile/#label) to the image.
   1. Add [annotations](/build/metadata/annotations/) to the image.
   1. Specify the users to add to the image. When you add a user, a home
      directory is automatically created for that user with 0755 permissions.
   1. Specify the user groups to add to the image.
   1. Select which [user](/reference/dockerfile/#user) to run the images as.
   1. Add [`ENTRYPOINT`](/reference/dockerfile/#entrypoint) arguments to the
      image. These arguments are appended to the base image's entrypoint.
   1. Add [`CMD`](/reference/dockerfile/#cmd) arguments to the image. These
      arguments are appended to the base image's command.
   1. Override the default (`/`) [working
      directory](/reference/dockerfile/#workdir) for the image.
   1. Specify a suffix for the customization name that is appended to the
      customized image's tag. For example, if you specify `custom` when
      customizing the `dhi-python:3.13` image, the customized image will be
      tagged as `dhi-python:3.13_custom`.
   1. Select the compression format for the image layers. You can choose between
      **ZSTD** (default) or **GZIP** compression. **ZSTD** typically provides
      faster image pulls and better compression ratios, but may have
      compatibility issues with older software. If you need compatibility with
      older Docker versions, use **GZIP**.
   1. Select the platforms you want to build the image for. You must select at
      least one platform.

1. Select **Next: Review customization**.

1. Select **Create Customization**.

   A summary of the customization appears. It may take some time for the image
   to build. Once built, it will appear in the **Tags** tab of the repository,
   and your team members can pull it like any other image.

{{< /tab >}}
{{< tab name="CLI" >}}

Authenticate with `docker login` using your Docker credentials or a [personal
access token (PAT)](../../security/access-tokens/personal-access-tokens.md) with **Read & Write**
permissions, or an [organization access token
(OAT)](../../security/access-tokens/organization-access-tokens.md). When using an OAT, the
available operations depend on the token's permission scope:

- To list or get customizations, or to view build logs, the OAT must have read
  (pull) access to the destination repository. Results are scoped to
  repositories the OAT can access.
- To create, update, or delete a customization, the OAT must have push access to
  the destination repository. Bulk operations require push access to every
  referenced destination repository.

Use the [`docker dhi customization`](/reference/cli/docker/dhi/customization/) command:

```console
# Prepare a single customization scaffold
$ docker dhi customization prepare golang 1.25 \
  --org my-org \
  --destination my-org/dhi-golang \
  --name "golang with git" \
  > my-customization.yaml

# Prepare a bulk customization scaffold (pipe JSON array via stdin)
$ echo '[{"destination":"my-org/dhi-golang","tag-definition-id":"golang/alpine-3.23/1.24-dev"}]' \
  | docker dhi customization prepare --name "golang with git" --org my-org \
  > my-customization.yaml

# Create a customization
$ docker dhi customization create my-customization.yaml --org my-org

# List customizations
$ docker dhi customization list --org my-org

# Filter customizations by name, repository, or source
$ docker dhi customization list --org my-org --filter git
$ docker dhi customization list --org my-org --repo dhi-golang
$ docker dhi customization list --org my-org --source golang

# Get a customization by ID
$ docker dhi customization get <id> --org my-org

# Update a customization
$ docker dhi customization edit my-customization.yaml --org my-org

# Delete a customization by ID
$ docker dhi customization delete <id> --org my-org

# Delete without confirmation prompt
$ docker dhi customization delete <id> --org my-org --force
```

For a complete reference of all YAML fields, see
[Image customization YAML file](#image-customization-yaml-file).

{{< /tab >}}
{{< tab name="Terraform" >}}

You can manage DHI customizations as infrastructure-as-code using the [DHI
Terraform provider](/dhi/tools/terraform/). If you haven't configured the
provider yet, see [DHI Terraform provider](/dhi/tools/terraform/) for setup
instructions.

Define a `dhi_customization` resource for each customization:

```hcl
resource "dhi_customization" "golang_with_git" {
  repository = "dhi-golang"
  name       = "golang with git"

  contents {
    packages = ["git", "curl"]
  }

  platform {
    os           = "linux"
    architecture = "amd64"
  }
}
```

The `dhi_customization` resource also supports optional configuration blocks
for `accounts`, `files`, `labels`, `annotations`, `environment`, `entrypoint`,
`cmd`, `user`, `workdir`, and `stop_signal`.

Run `terraform apply` to create the customization.

To edit a customization, update the resource configuration and run `terraform
apply`. To delete a customization, remove the resource and run `terraform apply`.

For the full list of resource attributes, see the [Terraform Registry
documentation](https://registry.terraform.io/providers/docker-hardened-images/dhi/latest/docs/resources/customization).

> [!NOTE]
>
> Monitoring customization builds is not available through the Terraform
> provider. Use the Docker Hub web interface or the DHI CLI to monitor builds.

{{< /tab >}}
{{< /tabs >}}

### Image customization YAML file

When using the CLI, customizations are defined in a YAML file. Use
`docker dhi customization prepare` to generate a scaffold with all available
fields and commented-out examples. Edit the file to describe what you want,
then pass it to `docker dhi customization create`.

The file has two parts: a preamble that identifies the customization and
its targets, and a configuration section that specifies what to change.

#### About the `id` field

The `id` field is assigned automatically by Docker Hub when you run
`docker dhi customization create`. When creating a new customization, omit
`id` entirely. It is read-only.

To find the ID of an existing customization, run:

```console
$ docker dhi customization list --org my-org
```

The `id` appears in the output and in files retrieved with
`docker dhi customization get <id> --org my-org`. It lets
`docker dhi customization edit` identify which customization to update.
Scaffolds from `docker dhi customization prepare` do not include `id`, and
that is expected.

#### Set targets

The `name` and `targets` fields are required in every customization file. The
`targets` array specifies which image versions the customization applies to.
Use a single entry for a single-image customization, or multiple entries for a
bulk customization that applies the same configuration to several images at
once.

```yaml
name: golang with git

targets:
  - destination: my-org/dhi-golang
    tag_definition_id: golang/alpine-3.23/1.25
```

| Field | Description |
|:---|:---|
| `name` | Human-readable name. Converted to lowercase and hyphenated, it becomes the image tag suffix. For example, `golang with git` produces tags ending in `_golang-with-git`. |
| `targets[].destination` | Destination repository in Docker Hub, such as `my-org/dhi-golang`. |
| `targets[].tag_definition_id` | Tag definition to customize, such as `golang/alpine-3.23/1.25`. Use `docker dhi customization prepare` with tab completion to find valid values. |

> [!NOTE]
>
> When `targets` has more than one entry, the fields `accounts`, `entrypoint`,
> and `cmd` are not supported. Including them causes `docker dhi customization
> create` to return an error.

#### Add packages

To install additional OS packages in your customized image, list them under
`contents.packages`. Available packages depend on the base image variant.

```yaml
contents:
  packages:
    - git
    - curl
```

#### Add OCI artifacts

To layer additional files into your customized image, such as custom
certificates, internal tools, or configuration files, list OCI artifact
images under `contents.artifacts`.

```yaml
contents:
  artifacts:
    - name: my-org/my-certs:latest
      includes:
        - etc/ssl/certs
      excludes:
        - etc/ssl/certs/old
```

| Field | Description |
|:---|:---|
| `name` | Image reference of the OCI artifact. Must be in the same Docker Hub namespace as the mirrored DHI. |
| `includes` | Paths to copy from the artifact. No files are included by default. You must list at least one path. |
| `excludes` | Paths to exclude after applying `includes`. |

To learn more about OCI artifacts, including how to create them, best
practices, and how environment variables behave, see
[OCI artifacts](#oci-artifacts).

#### Inject files into the image

To add static files at build time, such as configuration files or startup
scripts, use the `paths` field. Files are added as static content and are not
executed during the build.

```yaml
paths:
  - path: /etc/myconfig
    contents: |
      key=value
    mode: "0644"
    uid: 0
    gid: 0
```

| Field | Description |
|:---|:---|
| `path` | Absolute path where the file will be placed in the image. |
| `contents` | File content. Use a YAML block scalar (`\|`) for multi-line content. |
| `mode` | Octal file permissions, such as `"0644"`. Quote the value to prevent YAML from treating the leading zero as octal notation. |
| `uid` | User ID of the file owner. |
| `gid` | Group ID of the file owner. |

#### Configure user accounts

To add users or groups to the image, or to change which user the container
runs as, use the `accounts` field.

> [!NOTE]
>
> Not supported for bulk customizations (multiple `targets`).

```yaml
accounts:
  root: true
  runs-as: nonroot
  users:
    - name: nonroot
      uid: 65532
      gid: 65532
  groups:
    - name: nonroot
      gid: 65532
      members:
        - nonroot
```

| Field | Description |
|:---|:---|
| `root` | Whether to enable the root user. Default is `false`. Required if `runs-as` is set to `root`. |
| `runs-as` | The default user the container runs as. |
| `users[].name` | Username. |
| `users[].uid` | User ID. |
| `users[].gid` | Primary group ID. Optional. |
| `groups[].name` | Group name. |
| `groups[].gid` | Group ID. |
| `groups[].members` | Usernames to add to this group. Optional. |

#### Set environment variables

To add or override environment variables in the image, use the `environment`
field. These are merged with the base image's existing environment and do not
replace it.

```yaml
environment:
  MY_VAR: my_value
  DEBUG: "false"
```

Quote values that a YAML parser would interpret as non-string types, for
example `"false"`, `"0"`, and `"null"`.

#### Set labels and annotations

To add OCI metadata to the image, use `labels` and `annotations`. Labels are
stored in the image config; annotations are stored in the image manifest. Use
[OCI standard keys](https://specs.opencontainers.org/image-spec/annotations/)
where applicable.

```yaml
labels:
  org.opencontainers.image.authors: your-email@example.com
  org.opencontainers.image.version: "1.0.0"

annotations:
  org.opencontainers.image.title: Custom hardened image
  org.opencontainers.image.description: Customized Docker Hardened Image
```

#### Override entrypoint and command

To change how the container starts, use `entrypoint` and `cmd`. These arguments
are appended to the base image's existing entrypoint and command.

> [!NOTE]
>
> Not supported for bulk customizations (multiple `targets`).

```yaml
entrypoint:
  - /docker-entrypoint.sh

cmd:
  - /bin/bash
```

#### Set platforms and compression

To build for multiple architectures, list them under `platforms`. At least one
platform is required.

```yaml
platforms:
  - linux/amd64
  - linux/arm64
```

To control layer compression, set `compression`. `ZSTD` (the default) offers
better compression and faster pulls. Use `GZIP` for compatibility with older
tooling.

```yaml
compression: ZSTD
```

## OCI artifacts

In DHI customization, OCI artifacts are Docker images containing files you
want to layer into your image, such as custom certificates, internal tools, or
configuration files.

### Create an OCI artifact image

Keep artifact images as minimal as possible and include only the necessary
files.

For example, to distribute a custom root CA certificate as part of a trusted CA
bundle, you can use a multi-stage build. This approach registers your
certificate with the system and outputs an updated CA bundle, which can be
extracted into a minimal final image:

```dockerfile
# syntax=docker/dockerfile:1

FROM dhi.io/bash:5-dev AS certs

ENV DEBIAN_FRONTEND=noninteractive

RUN mkdir -p /usr/local/share/ca-certificates/my-rootca
COPY certs/rootCA.crt /usr/local/share/ca-certificates/my-rootca

RUN update-ca-certificates

FROM scratch
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
```

You can follow this pattern to create other OCI artifacts, such as images
containing tools or libraries that you want to include in your customized DHI.
Install the necessary tools or libraries in the first stage, and then copy the
relevant files to the final stage that uses `FROM scratch`. This ensures that
your OCI artifact is minimal and contains only the necessary files.

In order for the OCI artifact to be available in a DHI customization, it must be built and
pushed to a repository in the same namespace as the mirrored DHI repository.

If you're customizing a DHI for multiple platforms (such as `linux/amd64` and
`linux/arm64`), build your OCI artifact for all the platforms using the
`--platform` flag:

```console
$ docker buildx build --platform linux/amd64,linux/arm64 \
  -t <your-namespace>/my-oci-artifact:latest \
  --push .
```

This creates a single image manifest that you can use for each platform. The
customization build system automatically selects the correct platform variant
when building each customized image.

> [!IMPORTANT]
>
> The customization UI will only allow you to select platforms that are
> available in all OCI artifacts you've added. If a platform is missing from
> any OCI artifact, you won't be able to select that platform for your
> customization.

Once pushed to a repository in your organization's namespace, the OCI artifact
automatically appears in the customization workflow when you select OCI
artifacts to add to your customized Docker Hardened Image.

### Environment variables

When you include OCI artifacts in a customization, the environment variables
defined in those artifacts are merged into the final image. The merge follows
these rules:

- Your customization's environment settings take precedence. An artifact's
  variable is only applied if the corresponding key is absent or empty in your
  customization.
- `PATH` is an exception. Artifact `PATH` entries are added to the front of
  the existing `PATH`, giving them runtime precedence.

This differs from `COPY --from` in a Dockerfile, which copies files without
inheriting environment variables from the source image. To avoid inheriting
environment variables, build the artifact using a `FROM scratch` final stage.
See [Create an OCI artifact image](#create-an-oci-artifact-image).

### Best practices

Follow these best practices when creating OCI artifacts for DHI customizations:

- Use multi-stage builds: Build or install dependencies in a builder stage,
  then copy only the necessary files to a `FROM scratch` final stage. This keeps
  the OCI artifact minimal and avoids inheriting environment variables from the
  builder image into your customization.

- Include only essential files: OCI artifacts should contain only the files
  you need to add to the customized image. Avoid including package managers,
  shells, or other utilities that won't be used in the final image.

- Match target platforms: Build your OCI artifact for all platforms you plan
  to use in your customizations. Use `docker buildx build --platform` to create
  multi-platform images when needed.

- Use specific tags: Tag your OCI artifacts with specific versions or dates
  (like `v1.0` or `20250101`) rather than relying solely on `latest`. This
  ensures reproducible builds and makes it easier to track which artifacts are
  used in which customizations.

- Enable immutable tags: Consider enabling [immutable
  tags](../../docker-hub/repos/manage/hub-images/immutable-tags.md) for your
  OCI artifact repositories. This prevents accidental overwrites and ensures that
  each version of your OCI artifact remains unchanged, improving reproducibility
  and reliability of your customizations.

## Customize a DHI Helm chart

You can customize DHI Helm charts to meet your organization's specific needs.
Via the Docker Hub web interface, you can modify the image references to
reference mirrored images or customized images you've created. This lets you
create a custom, securely-built chart with references to images stored in Docker
Hub or other private registries. DHI securely packages customized Helm charts
that reference your repositories, wherever they are stored, by default.

To customize image references, an organization owner must [mirror](mirror.md)
the DHI chart repository to your organization on Docker Hub.

You can create one chart customization per Helm chart repository. This is
different from image customizations, where you can create multiple
customizations per repository. If you need to make changes, you can edit your
existing customization. Alternatively, you can mirror the same Helm chart
repository again and add a new customization to the new mirror.

> [!NOTE]
>
> You can customize Docker Hardened Image charts like any other Helm chart using
> standard Helm tools and practices, such as a `values.yaml` file, outside of
> Docker Hub. The following instructions describe how to customize image
> references for the chart using the Docker Hub web interface.

To customize a Docker Hardened Image Helm chart after it has been mirrored:

1. Sign in to [Docker Hub](https://hub.docker.com).
1. Select **My Hub**.
1. In the namespace drop-down, select your organization that has a mirrored DHI
   repository.
1. Select **Hardened Images** > **Manage** > **Mirrored Helm charts**.
1. For the mirrored DHI repository you want to customize, select the **Name**.
1. Select the **Customizations** tab.
1. Select **Create customization**.

   At this point, the on-screen instructions will guide you through the
   customization process.

### Helm chart customization YAML file

When using the CLI, Helm chart customizations use the same `prepare` / `create`
workflow as image customizations, but the configuration section uses
`reference_mappings` instead of image fields.

Use `reference_mappings` to substitute image references within the chart, for
example to point a chart's image references at your mirrored DHIs.

```yaml
name: use mirrored images

targets:
  - destination: my-org/dhi-haproxy-chart
    tag_definition_id: haproxy/helm/1

reference_mappings:
  - from: dhi/haproxy
    to: my-org/dhi-haproxy
```

| Field | Description |
|:---|:---|
| `reference_mappings[].from` | The image reference in the chart to replace. |
| `reference_mappings[].to` | The replacement image reference, typically a mirrored DHI in your organization. |

## Monitor customization builds

After creating a customization, you can track build status and view logs
through Docker Hub or the DHI CLI.

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub**.
3. In the namespace drop-down, select your organization.
4. Select **Hardened Images** > **Manage**.
5. Select the **Customizations** tab.

{{< /tab >}}
{{< tab name="CLI" >}}

List builds for a customization:

```console
$ docker dhi customization build list <customization-id> --org my-org
```

Get details of a specific build:

```console
$ docker dhi customization build get <customization-id> <build-id> --org my-org
```

View build logs:

```console
$ docker dhi customization build logs <customization-id> <build-id> --org my-org
```

{{< /tab >}}
{{< /tabs >}}

## Edit or delete a customization

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub**.
3. In the namespace drop-down, select your organization that has a mirrored repository.
4. Select **Hardened Images** > **Manage**.
5. Select **Customizations**.

6. For the customized DHI repository you want to manage, select the menu icon in the far right column.
   From here, you can:

   - **Edit**: Edit the customization.
   - **Create new**: Create a new customization based on the source repository.
   - **Delete**: Delete the customization.

7. Follow the on-screen instructions to complete the edit or deletion.

{{< /tab >}}
{{< tab name="CLI" >}}

To edit a customization, update your YAML file and run:

```console
$ docker dhi customization edit my-customization.yaml --org my-org
```

The YAML file must include the `id` field to identify which customization to
update. To find the ID, run `docker dhi customization list --org my-org`.

To delete a customization by ID:

```console
$ docker dhi customization delete <id> --org my-org
$ docker dhi customization delete <id> --org my-org --force
```

The `--force` flag skips the confirmation prompt.

{{< /tab >}}
{{< /tabs >}}


---

# Use Hardened System Packages

*Sección: Dhi*

Docker Hardened System Packages are built from source by Docker. This ensures
supply chain integrity throughout your entire image stack by eliminating risks
from potentially compromised public packages.

Access to hardened packages varies by subscription:

- **DHI Community**: Includes hardened packages in base images. Can configure the
  public package repository to access the same packages in custom images.
- **DHI Select**: Includes all Community packages, plus access to additional
  compliance-specific packages (such as FIPS variants) and Docker-patched
  packages through the image customization UI.
- **DHI Enterprise**: Includes all Select packages, plus the ability to configure
  the enterprise package repository directly in your own images for full access
  to compliance and security-patched packages.

To browse the packages currently available in Docker's public hardened package
repositories, see the following indexes:

- [Debian package index](https://dhi.io/deb/debian/main/index.html)
- [Alpine package index](https://dhi.io/apk/alpine/v3.24/main/index.html)

Docker is constantly adding new hardened packages. If a package you need isn't
available yet, you can [request it in the DHI catalog
repository](https://github.com/docker-hardened-images/catalog/issues).

## Built-in packages

Supported distributions of Docker Hardened Images (DHI) automatically include
hardened system packages. No additional configuration is required. Simply pull
and use the images as normal.

All packages in these images are built by Docker from source, maintaining
the same security standards as the base images themselves.

## Add hardened packages to your images

You can add hardened packages to your own images in the following two ways.

### Add packages through image customization

{{< summary-bar feature_name="Docker Hardened Images" >}}

When customizing Docker Hardened Images with DHI Select or DHI Enterprise, you
can add hardened packages for Alpine-based images through the customization
interface. Follow the steps to [create an image
customization](customize.md#create-an-image-customization) and select hardened
packages during the customization process.

### Configure the package manager

You can configure your package manager to pull from Docker's hardened package
repositories. This lets you install hardened packages in your own images.

#### Public repository

To use Docker's public hardened package repository in your own images,
configure your package manager in your Dockerfile to install the DHI signing
key and add the DHI repository.

The configuration process involves three steps:

1. Install the [signing key](https://github.com/docker-hardened-images/keyring)
2. Configure the package repository
3. Update and install packages

{{< tabs group="os" >}}
{{< tab name="Alpine" >}}

The following example shows how to configure the Alpine package manager in your
Dockerfile to use Docker's public hardened package repository:

```dockerfile
FROM alpine:3.23

# Install the signing key
RUN cd /etc/apk/keys && \
    wget https://dhi.io/keyring/dhi-apk@docker-0F81AD7700D99184.rsa.pub

# Replace the default repositories with the hardened package repository
RUN echo "https://dhi.io/apk/alpine/v3.23/main" > /etc/apk/repositories

# Update and install packages
RUN apk update && \
    apk add libpng
```

Replace `3.23` with your Alpine version in both the base image tag and repository URL.
Supported versions include Alpine 3.23 and 3.24.

To verify the configuration, build and run the image:

```console
$ docker build -t myapp:latest .
$ docker run -it myapp:latest sh
```

Inside the container, check the configured repositories:

```console
/ # cat /etc/apk/repositories
https://dhi.io/apk/alpine/v3.23/main
```

This ensures all packages are installed from Docker's hardened repository.

{{< /tab >}}
{{< tab name="Debian" >}}

The following example shows how to configure the Debian package manager in your
Dockerfile to use Docker's public hardened package repository:

```dockerfile
FROM debian:trixie-slim

# Install the signing key
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates curl gnupg \
    && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://dhi.io/keyring/dhi-deb-gpg.D46852F6925E9F71.key \
    | gpg --dearmor -o /usr/share/keyrings/dhi-deb.gpg

# Add the hardened package repository
RUN echo "deb [signed-by=/usr/share/keyrings/dhi-deb.gpg] https://dhi.io/deb/debian/main trixie main" \
    > /etc/apt/sources.list.d/dhi.list

# Update and install packages
RUN apt-get update && apt-get install -y jq \
    && rm -rf /var/lib/apt/lists/*
```

To verify the configuration, build and run the image:

```console
$ docker build -t myapp:latest .
$ docker run -it myapp:latest bash
```

Inside the container, check the configured repository:

```console
root@myapp:/# cat /etc/apt/sources.list.d/dhi.list
deb [signed-by=/usr/share/keyrings/dhi-deb.gpg] https://dhi.io/deb/debian/main trixie main
```

When the DHI repository carries a hardened version of a package, `apt` prefers
it over the upstream Debian version automatically. You can confirm this with
`apt-cache policy <package>`, which shows a candidate with a `+dhi` or `dhi`
version suffix sourced from `https://dhi.io/deb/debian/main`.

Not every Debian package is available as a hardened system package. When a
package is not in the DHI repository, `apt` transparently falls back to the
upstream Debian mirrors configured in the base image.

{{< /tab >}}
{{< /tabs >}}

All packages installed from the Docker Hardened Images repository are built from
source by Docker and include full provenance.

#### Enterprise repository

{{< summary-bar feature_name="Docker Hardened Images Enterprise" >}}

With DHI Enterprise, you have access to an additional package
repository that includes hardened packages for compliance variants such as FIPS,
as well as additional security patches.

The configuration process involves five steps:

1. Install the [signing keys](https://github.com/docker-hardened-images/keyring)
2. Configure the base package repository
3. Add the enterprise security repository
4. Configure package installation with authentication
5. Build the image passing credentials as a secret using the DHI CLI

{{< tabs group="os" >}}
{{< tab name="Alpine" >}}

The following example shows how to configure the Alpine package manager in your
Dockerfile to use Docker's enterprise hardened package repository:

```dockerfile
FROM alpine:3.23

# Install the signing key
RUN cd /etc/apk/keys && \
    wget https://dhi.io/keyring/dhi-apk@docker-0F81AD7700D99184.rsa.pub

# Replace the default repositories with the hardened package repository
RUN echo "https://dhi.io/apk/alpine/v3.23/main" > /etc/apk/repositories

# Update and install the enterprise configuration package to add the security repository
RUN apk update && \
    apk add dhi-enterprise-conf

# Install packages from the security repository with authentication
RUN --mount=type=secret,id=http_auth \
    HTTP_AUTH="$(cat /run/secrets/http_auth)" \
    apk update && \
    apk add openssl-fips
```

Build the image with authentication passed securely as a build secret:

```console
$ docker dhi auth apk > http_auth.txt
$ docker build --secret id=http_auth,src=http_auth.txt -t myapp-enterprise:latest .
$ rm http_auth.txt
```

The `--secret` flag securely mounts the authentication credentials during build
without storing them in the image layers or metadata.

{{< /tab >}}
{{< tab name="Debian" >}}

The following example shows how to configure the Debian package manager in your
Dockerfile to use Docker's enterprise hardened package repository. Mount
credentials at `/etc/apt/auth.conf.d/dhi.conf`; `apt` reads files in
`/etc/apt/auth.conf.d/` automatically when they have mode `0600`:

```dockerfile
FROM debian:trixie-slim

# Install the signing keys
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates curl gnupg \
    && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://dhi.io/keyring/dhi-deb-gpg.D46852F6925E9F71.key \
    | gpg --dearmor -o /usr/share/keyrings/dhi-deb.gpg
RUN curl -fsSL https://dhi.io/keyring/dhi-deb-sec-gpg.D46852F6925E9F71.key \
    | gpg --dearmor -o /usr/share/keyrings/dhi-deb-sec.gpg

# Add the hardened package repository and the enterprise security repository
RUN echo "deb [signed-by=/usr/share/keyrings/dhi-deb.gpg] https://dhi.io/deb/debian/main trixie main" \
    > /etc/apt/sources.list.d/dhi.list
RUN echo "deb [signed-by=/usr/share/keyrings/dhi-deb-sec.gpg] https://dhi.io/deb/debian/security trixie main" \
    > /etc/apt/sources.list.d/dhi-sec.list

# Install packages from the security repository with authentication
RUN --mount=type=secret,id=netrc,target=/etc/apt/auth.conf.d/dhi.conf,mode=0600 \
    apt-get update && apt-get install -y openssl \
    && rm -rf /var/lib/apt/lists/*
```

Build the image, passing credentials securely as a build secret through an
environment variable:

```console
$ NETRC=$(docker dhi auth deb) docker build \
    --secret id=netrc,env=NETRC \
    -t myapp-enterprise:latest .
```

The `--secret id=netrc,env=NETRC` form securely mounts the authentication
credentials during build without storing them in the image layers or metadata.

{{< /tab >}}
{{< /tabs >}}

## Verify packages

Every hardened package is cryptographically signed and includes metadata that
proves its provenance and build integrity. You can verify the signatures and
view the metadata to ensure your packages come from Docker's trusted build
infrastructure.

### View package metadata

To view information about a hardened package:

{{< tabs group="os" >}}
{{< tab name="Alpine" >}}

```console
$ apk info -L <package-name>
```

{{< /tab >}}
{{< tab name="Debian" >}}

```console
$ dpkg -L <package-name>
```

{{< /tab >}}
{{< /tabs >}}

This shows the files included in the package and its metadata.

### Verify package signatures

Hardened packages are cryptographically signed by Docker. When you install the
signing keys and configure your package manager as described previously, the
package manager automatically verifies signatures during installation.

If a package fails signature verification, the package manager will refuse to
install it, protecting you from tampered or compromised packages.

### Build provenance and cryptographic verification

Docker hardened packages are built by Docker's trusted infrastructure and include
verifiable metadata and cryptographic signatures.

To view this metadata for an installed package:

{{< tabs group="os" >}}
{{< tab name="Alpine" >}}

```console
$ apk info -a <package-name>
```

{{< /tab >}}
{{< tab name="Debian" >}}

```console
$ apt-cache show <package-name>
```

{{< /tab >}}
{{< /tabs >}}

Or to view metadata for a package before installing:

{{< tabs group="os" >}}
{{< tab name="Alpine" >}}

```console
$ apk fetch --stdout <package-name> | tar -xzO .PKGINFO
```

{{< /tab >}}
{{< tab name="Debian" >}}

```console
$ apt-get download <package-name>
$ dpkg-deb -I <package-name>_*.deb
```

{{< /tab >}}
{{< /tabs >}}

The package signing keys ensure that packages haven't been tampered with after
being built. When you install the signing key and configure your package manager,
all packages are automatically verified before installation.

### Package attestations

Each hardened package includes its own attestations, similar to [image
attestations](verify.md). These attestations provide provenance and build
information for individual packages, allowing you to trace the supply chain down
to the package level.

You can retrieve package attestations by first extracting package information
from the image's SLSA provenance, then using the package digest to access its
attestations.

#### Extract package information from image attestations

To get provenance information for a specific package from an image's SLSA
provenance attestation, you first need to retrieve the image's provenance and
then filter for the specific package you're interested in.

The SLSA provenance attestation includes a `materials` array that lists all
build inputs, including packages. You can use `jq` to filter this array for a
specific package:

```console
$ docker scout attest get dhi.io/golang:1.26-alpine3.23 \
    --predicate-type https://slsa.dev/provenance/v0.2 | \
    jq '.predicate.materials[] | select( .uri == "https://dhi.io/apk/alpine/v3.23/main/aarch64/golang-1.26-1.26.0-r0.apk" )'
```

Replace the package URI in the `select()` filter with the specific package
you're looking for. You can find available packages by first running the command
without the `select()` filter to see all materials.

This returns the package URI and its SHA-256 digest:

```json
{
  "uri": "https://dhi.io/apk/alpine/v3.23/main/aarch64/golang-1.26-1.26.0-r0.apk",
  "digest": {
    "sha256": "4082a2500abc2e7b8435f9398d3514d760044fa52ca3d10cf80015469124a838"
  }
}
```

#### List attestations for a package

Using the package digest from the previous section, you can list all available
attestations for that package:

```console
$ curl -s https://dhi.io/apk/alpine/v3.23/main/sha256:4082a2500abc2e7b8435f9398d3514d760044fa52ca3d10cf80015469124a838/attestations/list | jq .
```

This returns information about the package and its available attestations:

```json
{
  "subject": {
    "name": "pkg:apk/alpine/golang-1.26@1.26.0-r0?os_name=&os_version=",
    "digest": {
      "sha256": "4082a2500abc2e7b8435f9398d3514d760044fa52ca3d10cf80015469124a838"
    }
  },
  "attestations": [
    {
      "predicate_type": "https://slsa.dev/provenance/v1",
      "digest": {
        "sha256": "97c919cf0edb27087739bbabeea4c1ef88d069cd41791476ba64b69280d63a32"
      },
      "url": "https://dhi.io/apk/alpine/v3.23/main/sha256:4082a2500abc2e7b8435f9398d3514d760044fa52ca3d10cf80015469124a838/attestations/sha256:97c919cf0edb27087739bbabeea4c1ef88d069cd41791476ba64b69280d63a32"
    }
  ]
}
```

#### Retrieve package attestations

To retrieve the actual attestation content, use the URL provided in the
attestation list:

```console
$ curl -s https://dhi.io/apk/alpine/v3.23/main/sha256:4082a2500abc2e7b8435f9398d3514d760044fa52ca3d10cf80015469124a838/attestations/sha256:97c919cf0edb27087739bbabeea4c1ef88d069cd41791476ba64b69280d63a32 | jq .
```

This returns the full SLSA provenance attestation for the package, which
includes information about how the package was built, its dependencies, and
other build materials.

You can continue this process recursively to trace the supply chain all the way
down to the compiler and other build tools used to create the package.


---

# Use a Docker Hardened Image chart

*Sección: Dhi*

Docker Hardened Image (DHI) charts are Docker-provided Helm charts built from upstream sources, designed for
compatibility with Docker Hardened Images. These charts are available in the [DHI catalog on Docker Hub](https://hub.docker.com/hardened-images/catalog?types=helmChart).

DHI charts incorporate multiple layers of supply chain security that aren't present in upstream charts:

- SLSA Level 3 compliance: Each chart is built with SLSA Build Level 3 standards, including detailed build provenance
- Software Bill of Materials (SBOMs): Comprehensive SBOMs detail all components referenced within the chart
- Cryptographic signing: All associated metadata is cryptographically signed by Docker for integrity and authenticity
- Hardened configuration: Charts automatically reference Docker Hardened Images for secure deployments
- Tested compatibility: Charts are robustly tested to work out-of-the-box with Docker Hardened Images

You can use a DHI chart like any other Helm chart stored in an OCI registry.
When you have a Docker Hardened Images subscription, you can also customize DHI
charts to reference customized images and mirrored repositories. The customized
chart build pipeline ensures that your customizations are built securely, use
the latest base charts, and include attestations.

## Mirror a Helm chart and/or its images to a third-party registry

If you want to mirror to your own third-party registry, you can follow the
instructions in [Mirror a Docker Hardened Image repository](/dhi/how-to/mirror/) for either the
chart, the image, or both.

The same `regctl` tool that is used for mirroring container images can also be used for mirroring Helm charts, as Helm
charts are OCI artifacts.

For example:

```console
regctl image copy \
    "${SRC_CHART_REPO}:${TAG}" \
    "${DEST_REG}/${DEST_CHART_REPO}:${TAG}" \
    --referrers \
    --referrers-src "${SRC_ATT_REPO}" \
    --referrers-tgt "${DEST_REG}/${DEST_CHART_REPO}" \
    --force-recursive
```

## Create a Kubernetes secret for pulling images

You need to create a Kubernetes secret for pulling images from `dhi.io`, Docker
Hub, or your own registry. This is necessary because Docker Hardened Image
repositories require authentication. If you mirror the images to your own
registry, you still need to create this secret if the registry requires
authentication.

1. For `dhi.io` or Docker Hub, create a [personal access token
   (PAT)](/security/access-tokens/personal-access-tokens/) using your Docker account or an
   [organization access token (OAT)](/security/access-tokens/organization-access-tokens/).
   Ensure the token has at least read-only access to the Docker Hardened Image
   repositories.
2. Create a secret in Kubernetes using the following command. Replace `<your-secret-name>`, `<your-username>`,
   `<your-personal-access-token>`, and `<your-email>` with your own values.

   > [!NOTE]
   >
   > You need to create this secret in each Kubernetes namespace that uses a
   > DHI. If you've mirror your DHIs to another registry, replace
   > `dhi.io` with your registry's hostname. Replace
   > `<your-username>`, `<your-access-token>`, and `<your-email>` with your own
   > values. `<your-username>` is Docker ID if using a PAT or your organization
   > name if using an OAT. `<your-secret-name>` is a name you choose for the
   > secret.

   ```console
   $ kubectl create secret docker-registry <your-secret-name> \
       --docker-server=dhi.io \
       --docker-username=<your-username> \
       --docker-password=<your-access-token> \
       --docker-email=<your-email>
   ```

   For example:

    ```console
    $ kubectl create secret docker-registry dhi-pull-secret \
        --docker-server=dhi.io \
        --docker-username=docs \
        --docker-password=dckr_pat_12345 \
        --docker-email=moby@example.com
   ```

## Install a Helm chart

To install a Helm chart from Docker Hardened Images:

1. Sign in to the registry using Helm:

   ```console
   $ echo $ACCESS_TOKEN | helm registry login dhi.io --username <your-username> --password-stdin
   ```

    Replace `<your-username>` and set `$ACCESS_TOKEN`.

2. Install the chart using `helm install`. Optionally, you can also use the `--dry-run` flag to test the installation without
   actually installing anything.


   ```console
   $ helm install <release-name> oci://dhi.io/<helm-chart-repository> --version <chart-version> \
     --set "imagePullSecrets[0].name=<your-secret-name>"
   ```

   Replace `<helm-chart-repository>` and `<chart-version>` accordingly. If the
   chart is in your own registry or another repository, replace
   `dhi.io/<helm-chart-repository>` with your own location. Replace
   `<your-secret-name>` with the name of the image pull secret created
   from [Create a Kubernetes secret for pulling images](#create-a-kubernetes-secret-for-pulling-images).

## Customize a Helm chart

You can customize Docker Hardened Image Helm charts to reference customized
images and mirrored repositories. For more details, see [Customize Docker
Hardened Images and charts](customize.md).

## Verify a Helm chart and view its attestations

You can verify Helm charts. For more details, see [Verify Helm chart attestations](verify.md#verify-helm-chart-attestations-with-docker-scout).


---

# Mirror a Docker Hardened Image repository

*Sección: Dhi*

{{< summary-bar feature_name="Docker Hardened Images" >}}

Mirroring requires a DHI Select or Enterprise subscription. Without a
subscription, you can pull Docker Hardened Images directly from `dhi.io` without
mirroring. With a DHI Select or Enterprise subscription, you must mirror to your
organization to get:

- Compliance variants (FIPS-enabled or STIG-ready images)
- Extended Lifecycle Support (ELS) variants (requires add-on)
- Image or Helm chart customization
- Air-gapped or restricted network environments
- [SLA-backed security updates](https://docs.docker.com/go/dhi-sla/)

## How to mirror

This topic covers two types of mirroring for Docker Hardened Image (DHI)
repositories:

- [Mirror to your organization](#mirror-a-dhi-repository-to-your-organization):
  Mirror a DHI repository to your organization's namespace on Docker Hub.

- [Mirror to a third-party
  registry](#mirror-a-dhi-repository-to-a-third-party-registry): Mirror a
  repository to another container registry, such as Amazon ECR, Google Artifact
  Registry, or a private Harbor instance.

## Mirror a DHI repository to your organization

Organization owners, editors, and members with a [custom role](../../security/roles-and-permissions/custom-roles/index.md)
that includes the DHI mirroring permission can create, view, and manage mirrors.
When using the CLI or Terraform, you can also mirror using an [organization
access token (OAT)](../../security/access-tokens/organization-access-tokens.md) with the
appropriate permission scopes, without requiring role-based access.

When a member with a custom role that includes the DHI mirroring permission
creates a mirror, Docker automatically creates and manages the
`dhi-mirroring-admins` team in your organization, adds that member to it, and
grants the team access to the new mirror. This lets the member manage mirrors
they create without organization owner or editor access. Mirrors created by
organization owners or editors don't use this team. Removing members from this
team may affect their ability to view and manage mirrors.

You can mirror image and chart repositories to your organization's namespace on
Docker Hub. Mirroring makes the repositories available within your organization
and lets you customize them for your environment:

- Image repositories: Mirroring lets you customize images by adding packages,
  OCI artifacts (such as custom certificates or additional tools), environment
  variables, labels, and other configuration settings. For more details, see
  [Customize a Docker Hardened Image](customize.md#customize-a-docker-hardened-image).

- Chart repositories: Mirroring lets you customize image references within
  the chart. This is particularly useful when using customized images or when
  you've mirrored images to a third-party registry and need the chart to
  reference those custom locations. For more details, see [Customize a Docker
  Hardened Helm chart](customize.md#customize-a-docker-hardened-helm-chart).

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Go to [Docker Hub](https://hub.docker.com) and sign in.
2. Select **My Hub**.
3. In the namespace drop-down, select your organization.
4. Select **Hardened Images** > **Catalog**.
5. Select a DHI repository to view its details.
6. Mirror the repository:
    - To mirror an image repository, select **Use this image** > **Mirror
      repository**, and then follow the on-screen instructions. If you have the ELS add-on, you can also
      select **Enable support for end-of-life versions**.
    - To mirror a Helm chart repository, select **Get Helm chart**, and then follow the on-screen instructions.

It may take a few minutes for all the tags to finish mirroring.

{{< /tab >}}
{{< tab name="CLI" >}}

Authenticate with `docker login` using your Docker credentials, a [personal
access token (PAT)](../../security/access-tokens/personal-access-tokens.md) with **Read & Write**
permissions, or an [organization access token
(OAT)](../../security/access-tokens/organization-access-tokens.md). When using an OAT, the
available operations depend on the token's permission scope:

- To list mirrored repositories, the OAT must have read (pull) access to the
  relevant repositories. Results are scoped to repositories the OAT can access.
- To create a mirror to an existing destination repository, the OAT must have
  push access to that repository. To create a mirror to a new destination
  repository that doesn't yet exist, the OAT must have org-wide repository
  access (for example, `<org>/*` with pull or push). Repository-scoped access to
  the future repository name is not sufficient.
- To stop mirroring, the OAT must have push access to the relevant repository.
- OATs with public repository read-only access cannot list or manage mirrored
  repositories.

Use the [`docker dhi mirror`](/reference/cli/docker/dhi/mirror/) command:

```console
$ docker dhi mirror start --org my-org \
  dhi/golang,my-org/dhi-golang \
  dhi/nginx,my-org/dhi-nginx \
  dhi/prometheus-chart,my-org/dhi-prometheus-chart
```

Mirror with dependencies:

```console
$ docker dhi mirror start --org my-org dhi/golang,my-org/dhi-golang --dependencies
```

List mirrored images in your organization:

```console
$ docker dhi mirror list --org my-org
```

Filter mirrored images by name or type:

```console
$ docker dhi mirror list --org my-org --filter python
$ docker dhi mirror list --org my-org --type image
$ docker dhi mirror list --org my-org --type helm-chart
```

{{< /tab >}}
{{< tab name="Terraform" >}}

You can manage DHI mirrors as infrastructure-as-code using the [DHI Terraform
provider](/dhi/tools/terraform/).

Define a `dhi_mirror` resource for each repository you want to mirror:

```hcl
resource "dhi_mirror" "golang" {
  source_namespace = "dhi"
  source_name      = "golang"
  destination_name = "dhi-golang"
}

resource "dhi_mirror" "nginx" {
  source_namespace = "dhi"
  source_name      = "nginx"
  destination_name = "dhi-nginx"
}
```

To enable Extended Lifecycle Support (ELS) variants, set the `els` attribute:

```hcl
resource "dhi_mirror" "golang" {
  source_namespace = "dhi"
  source_name      = "golang"
  destination_name = "dhi-golang"
  els              = true
}
```

Run `terraform apply` to create the mirrors.

For the full list of resource attributes, see the [Terraform Registry
documentation](https://registry.terraform.io/providers/docker-hardened-images/dhi/latest/docs/resources/mirror).

{{< /tab >}}
{{< /tabs >}}

After mirroring, the repository appears in your organization's repository list,
prefixed by `dhi-`, and continues to receive updated images. It behaves like any
other Docker Hub repository, so you can manage access and permissions, configure
webhooks, and use other standard Hub features. See [Docker Hub
repositories](../../docker-hub/repos/index.md) for details.

### Stop mirroring a repository

After you stop mirroring, the repository remains, but it no longer receives
updates. You can still use the last images or charts that were mirrored.

> [!NOTE]
>
> If you only want to stop mirroring ELS versions, you can clear the ELS
> option in the mirrored repository's **Settings** tab.

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Go to [Docker Hub](https://hub.docker.com) and sign in.
2. Select **My Hub**.
3. In the namespace drop-down, select your organization that has access to DHI.
4. Select **Hardened Images** > **Manage**.
5. Select the **Mirrored Images** or **Mirrored Helm charts** tab.
6. In the far right column of the repository you want to stop mirroring, select the menu icon.
7. Select **Stop mirroring**.

{{< /tab >}}
{{< tab name="CLI" >}}

Authenticate with `docker login` using your Docker credentials, a [personal
access token (PAT)](../../security/access-tokens/personal-access-tokens.md) with **Read & Write**
permissions, or an [organization access token
(OAT)](../../security/access-tokens/organization-access-tokens.md) with push access to the
relevant repository.

Use the [`docker dhi mirror`](/reference/cli/docker/dhi/mirror/) command:

```console
$ docker dhi mirror stop --org my-org dhi-golang
```

{{< /tab >}}
{{< tab name="Terraform" >}}

To stop mirroring, remove the `dhi_mirror` resource from your Terraform
configuration and run `terraform apply`. The repository remains in your
organization but no longer receives updates.

{{< /tab >}}
{{< /tabs >}}

## Mirror a DHI repository to a third-party registry

After mirroring a DHI repository to your organization on Docker Hub, you can
optionally mirror it to another container registry, such as Amazon ECR, Google
Artifact Registry, GitHub Container Registry, or a private Harbor instance.

You can use any standard workflow to mirror the image, such as the
[Docker CLI](/reference/cli/docker/), [Docker Hub Registry
API](/reference/api/registry/latest/), third-party registry tools, or CI/CD
automation.

However, to preserve the full security context, including attestations, you must
also mirror its associated OCI artifacts. DHI repositories store the image
layers on `dhi.io` (or `docker.io` for customized images) and the signed
attestations in a separate registry (`registry.scout.docker.com`).

To copy both, you can use [`regctl`](https://regclient.org/cli/regctl/), an
OCI-aware CLI that supports mirroring images along with attached artifacts such
as SBOMs, vulnerability reports, and SLSA provenance. For ongoing synchronization,
you can use [`regsync`](https://regclient.org/cli/regsync/).

### Automate syncing with webhooks

To keep external registries or systems in sync with your mirrored Docker
Hardened Images, and to receive notifications when updates occur, you can
configure a [webhook](/docker-hub/repos/manage/webhooks/) on the mirrored
repository in Docker Hub. A webhook sends a `POST` request to a URL you define
whenever a new image tag is pushed or updated.

For example, you might configure a webhook to call a CI/CD system at
`https://ci.example.com/hooks/dhi-sync` whenever a new tag is mirrored. The
automation triggered by this webhook can pull the updated image from Docker Hub
and push it to an internal registry such as Amazon ECR, Google Artifact
Registry, or GitHub Container Registry.

Other common webhook use cases include:

- Triggering validation or vulnerability scanning workflows
- Signing or promoting images
- Sending notifications to downstream systems

#### Example webhook payload

When a webhook is triggered, Docker Hub sends a JSON payload like the following:

```json{collapse=true}
{
  "callback_url": "https://registry.hub.docker.com/u/exampleorg/dhi-python/hook/abc123/",
  "push_data": {
    "pushed_at": 1712345678,
    "pusher": "trustedbuilder",
    "tag": "3.13-alpine3.21"
  },
  "repository": {
    "name": "dhi-python",
    "namespace": "exampleorg",
    "repo_name": "exampleorg/dhi-python",
    "repo_url": "https://hub.docker.com/r/exampleorg/dhi-python",
    "is_private": true,
    "status": "Active",
    ...
  }
}
```

### Example mirroring with `regctl`

The following example shows how to mirror a specific tag of a Docker Hardened
Image from Docker Hub to another registry, along with its associated
attestations using `regctl`. You must [install
`regctl`](https://github.com/regclient/regclient) first.

The example assumes you have mirrored the DHI repository to your organization's
namespace on Docker Hub as described in the previous section. You can apply the
same steps to a non-mirrored image by updating the `SRC_ATT_REPO` and
`SRC_REPO` variables accordingly.

1. Set environment variables for your specific environment. Replace the
   placeholders with your actual values.

   In this example, you authenticate as your Docker organization using an
   [organization access token
   (OAT)](../../security/access-tokens/organization-access-tokens.md). The OAT must have at
   least pull access to every DHI repository you want to mirror. Only
   repositories in the token's scope are accessible. Alternatively, you can
   authenticate as a Docker Hub user with a [personal access token
   (PAT)](../../security/access-tokens/personal-access-tokens.md) that has `read only` access.

   > [!WARNING]
   >
   > The following examples export credentials directly on the command line for
   > demonstration purposes. This exposes sensitive tokens in your shell history
   > and process list. In production environments, use secure methods such as
   > reading from files with restricted permissions, environment files loaded
   > at runtime, or secret management tools.

   ```console
   $ export DOCKER_ORG="YOUR_DOCKER_ORG"
   $ export DOCKER_OAT="YOUR_DOCKER_OAT"
   $ export DEST_REG="registry.example.com"
   $ export DEST_REPO="mirror/dhi-python"
   $ export DEST_REG_USERNAME="YOUR_DESTINATION_REGISTRY_USERNAME"
   $ export DEST_REG_TOKEN="YOUR_DESTINATION_REGISTRY_TOKEN"
   $ export SRC_REPO="docker.io/${DOCKER_ORG}/dhi-python"
   $ export SRC_ATT_REPO="registry.scout.docker.com/${DOCKER_ORG}/dhi-python"
   $ export TAG="3.13-alpine3.21"
   ```

2. Sign in via `regctl` to Docker Hub, the Scout registry that contains
   the attestations, and your destination registry.

   ```console
   $ echo $DOCKER_OAT | regctl registry login -u "$DOCKER_ORG" --pass-stdin docker.io
   $ echo $DOCKER_OAT | regctl registry login -u "$DOCKER_ORG" --pass-stdin registry.scout.docker.com
   $ echo $DEST_REG_TOKEN | regctl registry login -u "$DEST_REG_USERNAME" --pass-stdin "$DEST_REG"
   ```

3. Mirror the image and attestations using `--referrers` and referrer endpoints:

   ```console
   $ regctl image copy \
        "${SRC_REPO}:${TAG}" \
        "${DEST_REG}/${DEST_REPO}:${TAG}" \
        --referrers \
        --referrers-src "${SRC_ATT_REPO}" \
        --referrers-tgt "${DEST_REG}/${DEST_REPO}" \
        --force-recursive
   ```

4. Verify that artifacts were preserved.

   First, get a digest for a specific tag and platform. For example, `linux/amd64`.

   ```console
   DIGEST="$(regctl manifest head "${DEST_REG}/${DEST_REPO}:${TAG}" --platform linux/amd64)"
   ```

   List attached artifacts (SBOM, provenance, VEX, vulnerability reports).

   ```console
   $ regctl artifact list "${DEST_REG}/${DEST_REPO}@${DIGEST}"
   ```

   Or, list attached artifacts with `docker scout`.

   ```console
   $ docker scout attest list "registry://${DEST_REG}/${DEST_REPO}@${DIGEST}"
   ```

### Example ongoing mirroring with `regsync`

`regsync` automates pulling from your organizations mirrored DHI repositories on
Docker Hub and pushing to your external registry including attestations. It
reads a YAML configuration file and can filter tags.

The following example uses a `regsync.yaml` file that syncs Node 24 and Python
3.12 Debian 13 variants, excluding Alpine and Debian 12.

```yaml{title="regsync.yaml",collapse=true}
version: 1
# Optional: inline creds if not relying on prior CLI logins
# creds:
#   - registry: docker.io
#     user: <your-docker-org>
#     pass: "{{file \"/run/secrets/docker_oat\"}}"
#   - registry: registry.scout.docker.com
#     user: <your-docker-org>
#     pass: "{{file \"/run/secrets/docker_oat\"}}"
#   - registry: registry.example.com
#     user: <service-user>
#     pass: "{{file \"/run/secrets/dest_token\"}}"

sync:
  - source: docker.io/<your-org>/dhi-node
    target: registry.example.com/mirror/dhi-node
    type: repository
    fastCopy: true
    referrers: true
    referrerSource: registry.scout.docker.com/<your-org>/dhi-node
    referrerTarget: registry.example.com/mirror/dhi-node
    tags:
      allow: [ "24.*" ]
      deny: [ ".*alpine.*", ".*debian12.*" ]

  - source: docker.io/<your-org>/dhi-python
    target: registry.example.com/mirror/dhi-python
    type: repository
    fastCopy: true
    referrers: true
    referrerSource: registry.scout.docker.com/<your-org>/dhi-python
    referrerTarget: registry.example.com/mirror/dhi-python
    tags:
      allow: [ "3.12.*" ]
      deny: [ ".*alpine.*", ".*debian12.*" ]
```

To do a dry run with the configuration file, you can run the following command.
You must [install `regsync`](https://github.com/regclient/regclient) first.

```console
$ regsync check -c regsync.yaml
```

To run the sync with the configuration file:

```console
$ regsync once -c regsync.yaml
```

## What next

After mirroring, see [Pull a DHI](use.md#pull-a-dhi) to learn how to pull and use mirrored images.


---

# Apply Docker Hardened Image policies to your images

*Sección: Dhi*

Docker publishes the set of security and compliance policies that Docker
Hardened Images (DHIs) are built to meet, so you can hold your own images to the
same standards. You evaluate images against these policies with the
[`docker scout policy`](../../scout/policy/local.md) command.

These policies encode requirements such as running as a non-root user, being
free of fixable critical and high vulnerabilities, containing no embedded
malware or secrets, and shipping signed supply chain attestations. They don't
verify whether an image is a DHI or built on a DHI base image; they check
whether an image meets the same bar that DHIs are held to.

Unlike the built-in Docker Scout policies, the DHI policies aren't embedded in
the CLI. They're maintained as Rego source in the
[`docker-hardened-images/policies`](https://github.com/docker-hardened-images/policies)
repository and published as an OCI policy bundle at
[`dhi/policies`](https://hub.docker.com/repository/docker/dhi/policies/general).
You pull the bundle at evaluation time with the `--policy-bundle` flag, so you
can apply DHI standards locally, in CI, or both, without sending any data to the
Docker Scout service.

## Policies in the DHI bundle

The `dhi/policies` bundle includes the following policies:

| Policy | Policy name | What it checks |
| --- | --- | --- |
| No default root user for non-dev images | `dhi-default-non-root-user` | The image is configured to run as a non-root user. |
| No fixable vulnerabilities past their remediation SLA | `fixable-vulnerabilities` | No fixable CVEs remain unaddressed past their remediation SLA (7 days for critical and high, 30 days for others). |
| No high-profile vulnerabilities | `high-profile-vulnerabilities` | The image is free of a curated list of well-known CVEs, optionally including the CISA KEV catalog. |
| No embedded malware | `dhi-no-embedded-malware` | A malware scan attestation is present and passing. |
| No embedded secrets | `dhi-no-embedded-secrets` | A secret scan attestation is present and passing. |
| No failing tests | `dhi-no-failing-tests` | A test attestation is present and passing. |
| Signed supply chain attestations | `dhi-signed-supply-chain-attestations` | SBOM and provenance attestations are attached and signed. |
| Unintentional shell or package manager | `dhi-unintentional-shell-or-package-manager` | No undeclared shell or package manager is present in the image. |
| STIG scan | `dhi-stig-scan-score` | For FIPS-compliant images, the STIG scan meets the required score. |

The **Policy name** is the stable ID you reference in a `--policy-config` file to
enable, disable, or tune a policy.

For the authoritative list and the Rego source for each policy, see the
[`docker-hardened-images/policies`](https://github.com/docker-hardened-images/policies)
repository.

## Prerequisites

- The [Docker Scout CLI plugin](../../scout/install.md). It's included with
  Docker Desktop.
- Access to pull the `dhi/policies` bundle from Docker Hub. Authentication uses
  your existing Docker registry credentials, so sign in first:

  ```console
  $ docker login
  ```

## Evaluate an image against the DHI policies

To evaluate an image against the DHI policy bundle, pass the bundle reference to
`docker scout policy` with the `--policy-bundle` flag:

```console
$ docker scout policy <image> --policy-bundle dhi/policies:latest
```

The CLI pulls the bundle, indexes the image into an SBOM, enriches it with CVE
and VEX data, and evaluates each policy in the bundle against that data. Bundles
are cached by digest, so re-running against the same bundle doesn't re-download
it.

### Example: Build and evaluate a DHI-based image

The following example builds an image from a DHI base image and evaluates it
against the DHI policy bundle.

#### Step 1: Use a DHI base image in your Dockerfile

Create a Dockerfile that uses a Docker Hardened Image from the DHI catalog as
the base. For example:

```dockerfile
# Dockerfile
FROM dhi.io/python:3.13

ENTRYPOINT ["python", "-c", "print('Hello from a DHI-based image')"]
```

#### Step 2: Build the image

Open a terminal and navigate to the directory containing your Dockerfile. Then,
build the image and load it into your local image store:

```console
$ docker build --load -t my-dhi-app:v1 .
```

#### Step 3: Evaluate the image against the DHI policies

Sign in and evaluate the local image against the DHI policy bundle:

```console
$ docker login
$ docker scout policy my-dhi-app:v1 \
  --policy-bundle dhi/policies:latest
```

The command prints a compliance result for each policy in the bundle, along with
the details of any violations.

## Customize the DHI policies

You can tune which policies run and their thresholds with a `--policy-config`
file. The
[`docker-hardened-images/policies`](https://github.com/docker-hardened-images/policies)
repository includes an example `config.json` you can start from.

```console
$ docker scout policy my-dhi-app:v1 \
  --policy-bundle dhi/policies:latest \
  --policy-config ./config.json
```

The config file matches policies by the **Policy name** listed in
[Policies in the DHI bundle](#policies-in-the-dhi-bundle) and lets you disable
individual policies or adjust their settings. For example, the following config
disables the STIG scan policy and opts out of CISA KEV checks in the
high-profile vulnerabilities policy:

```json
{
  "policies": [
    {
      "name": "dhi-stig-scan-score",
      "enabled": false
    },
    {
      "name": "high-profile-vulnerabilities",
      "config": {
        "include_cisa_kev": false
      }
    }
  ]
}
```

For the full config file format, see
[Configure built-in policies](../../scout/policy/local.md#configure-built-in-policies).

You can also combine the DHI bundle with the built-in Docker Scout policies,
additional bundles, or your own custom Rego files. `--policy-bundle`,
`--policy-file`, and `--policy-dir` are all repeatable:

```console
$ docker scout policy my-dhi-app:v1 \
  --policy-bundle dhi/policies:latest \
  --policy-file ./custom.rego
```

For more on authoring custom policies and combining policy sources, see
[Evaluate policies](../../scout/policy/local.md).

## Enforce policy compliance in CI

Use the [Docker Scout GitHub Action](https://github.com/docker/scout-action) to
evaluate the DHI policies on every push and fail the workflow when an image
doesn't meet them. The following workflow builds the image, then evaluates it
against the DHI policy bundle:

```yaml
name: DHI policy check

on:
  push:

env:
  IMAGE_NAME: my-dhi-app:${{ github.sha }}

jobs:
  policy:
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repository
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USER }}
          password: ${{ secrets.DOCKER_PAT }}

      - name: Build the image
        uses: docker/build-push-action@v6
        with:
          context: .
          load: true
          tags: ${{ env.IMAGE_NAME }}

      - name: Evaluate DHI policies
        uses: docker/scout-action@v1.23.1
        with:
          command: policy
          image: ${{ env.IMAGE_NAME }}
          policy-bundle: dhi/policies:latest
          exit-code: true
```

The `docker/login-action` step authenticates with Docker Hub so the runner can
pull the DHI base image and the `dhi/policies` bundle. Store your Docker Hub
username and a [personal access token](../../security/access-tokens/personal-access-tokens.md) as the
`DOCKER_USER` and `DOCKER_PAT` repository secrets.

Set `exit-code: true` to fail the step when any policy isn't met. The
`policy-bundle` input accepts a comma-separated list of bundles, and you can
combine it with the `policy-file`, `policy-dir`, and `policy-config` inputs, the
same as the CLI flags.

For more on running policy evaluation in CI, see
[Evaluate policies](../../scout/policy/local.md#use-in-ci).


---

# Scan Docker Hardened Images

*Sección: Dhi*

Docker Hardened Images (DHIs) are designed to be secure by default, but like any
container image, it's important to scan them regularly as part of your
vulnerability management process.

## Scan with OpenVEX-compliant scanners

To get accurate vulnerability assessments, use scanners that support
[VEX](../explore/security-concepts/vex.md) attestations. The following scanners can
read and apply the VEX statements included with Docker Hardened Images:

- [Docker Scout](#docker-scout): Automatically applies VEX statements with zero configuration
- [Trivy](#trivy): Supports VEX through VEX Hub or local VEX files
- [Grype](#grype): Supports VEX via the `--vex` flag

For a full list of supported scanners, see [Scanner integrations](../explore/scanner-integrations.md).

## Docker Scout

Docker Scout is integrated into Docker Desktop and the Docker CLI. It provides
vulnerability insights, CVE summaries, and direct links to remediation guidance.

### Scan a DHI using Docker Scout

To scan a Docker Hardened Image using Docker Scout, run the following
command:

```console
$ docker login dhi.io
$ docker scout cves dhi.io/<image>:<tag> --platform <platform>
```

Example output:

```plaintext
    v SBOM obtained from attestation, 101 packages found
    v Provenance obtained from attestation
    v VEX statements obtained from attestation
    v No vulnerable package detected
    ...
```

For more detailed filtering and JSON output, see [Docker Scout CLI reference](/reference/cli/docker/scout/).

### Build child images with provenance attestations

When you build a custom image that uses a Docker Hardened Image as its base, you must build with `--provenance=mode=max` and `--sbom=true` so that Docker Scout can trace the base image lineage and correctly apply VEX statements.

Without these flags, Docker Scout cannot identify the DHI base image in
the provenance chain. As a result, it reports CVEs that are already suppressed
by VEX statements in the base image, producing false CVE positives in your
scan results.

> [!NOTE]
> **Why provenance attestation is required**
>
> Docker Scout uses max-mode provenance attestations to identify the DHI base image
> and track its lineage. A cryptographically signed provenance attestation ensures that
> base image lineage is verified and tamper-resistant, giving Docker Scout the trust
> anchor it needs to correctly apply VEX statements from the base image.

To build with maximum provenance and SBOM attestations:

```console
$ docker build \
    --provenance=mode=max \
    --sbom=true \
    --push \
    -t docker.io/<namespace>/<image>:<tag> .
```

After building with these flags, Docker Scout reads the full provenance
chain, matches the DHI base image, and applies its VEX statements. Scans of
your child image then reflect the correct suppressed CVEs, giving you an
accurate vulnerability assessment.

### VEX attestations in child images

If you introduce new layers in your child image and want to suppress CVEs in those layers, you can attach your own VEX attestation to the child image independently, you do not need to duplicate or aggregate the VEX statements from the DHI base image.

When `docker scout cves` runs against your child image, Scout reads VEX attestations from the full provenance chain and applies them cumulatively:

- **Base image VEX** - attached to the DHI, applied to CVEs in base image layers
- **Child image VEX** - attached to your image, applied to CVEs in layers you introduced

For example, if you add a `requests` layer to a DHI Python base image and attach a VEX statement suppressing `CVE-2024-47081`, Scout applies both VEX attestations independently and attributes each to its respective author:

```text
✓ VEX statements obtained from attestation
CVE-2024-47081  VEX: not affected [vulnerable code not present] : <your-namespace>
```

Scout suppresses CVEs from the DHI base VEX and CVEs from your child VEX in the same scan - no aggregate VEX document is required.

To create and attach a VEX attestation to your child image:

```bash
cat > child-vex.json << 'EOF'
{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "@id": "https://<your-namespace>/vex/<image-name>/1",
  "author": "<your-namespace>",
  "timestamp": "<timestamp>",
  "version": 1,
  "statements": [
    {
      "vulnerability": {
        "name": "<CVE-ID>"
      },
      "products": [
        {
          "@id": "pkg:pypi/<package>@<version>"
        }
      ],
      "status": "not_affected",
      "justification": "vulnerable_code_not_present"
    }
  ]
}
EOF

docker scout attestation add \
  --file child-vex.json \
  --predicate-type https://openvex.dev/ns/v0.2.0 \
  docker.io/<your-namespace>/<image>:<tag>
```

> [!NOTE]
> This is only possible because you built with `--provenance=mode=max`. Without the full
> provenance chain, Scout cannot traverse back to the base image to retrieve its VEX attestations.

### Automate DHI scanning in CI/CD with Docker Scout

Integrating Docker Scout into your CI/CD pipeline enables you to automatically
verify that images built from Docker Hardened Images remain free from known
vulnerabilities during the build process. This proactive approach ensures the
continued security integrity of your images throughout the development
lifecycle.

#### Example GitHub Actions workflow

The following is a sample GitHub Actions workflow that builds an image, scans it and pushes to the registry only if the scan passes:

```yaml {collapse="true"}
name: DHI Vulnerability Scan

on:
  push:
    branches:
      - main
  pull_request:

env:
  REGISTRY: docker.io
  IMAGE_NAME: ${{ github.repository }}
  SHA: ${{ github.event.pull_request.head.sha || github.event.after }}

jobs:
  scan:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      pull-requests: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@{{% param "checkout_action_version" %}}

      - name: Set up Docker with containerd image store
        uses: docker/setup-docker-action@{{% param "setup_docker_action_version" %}}
        with:
          daemon-config: |
            {
              "features": {
                 "containerd-snapshotter": true
              }
            }

      - name: Log in to Docker Hub
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          context: .
          sbom: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.SHA }}
      
      - name: Run Docker Scout CVE scan
        uses: docker/scout-action@v1
        with:
          command: cves
          image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.SHA }}
          only-severities: critical,high
          exit-code: true

      - name: Push image
        if: success()
        run: |
          docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.SHA }}
```

The `exit-code: true` parameter ensures that the workflow fails if any critical or
high-severity vulnerabilities are detected, preventing the deployment of
insecure images.

> [!NOTE]
>
> The `--provenance=mode=max` and `--sbom=true` flags are required so that
> Docker Scout can trace the DHI base image lineage and correctly apply its
> VEX statements. Enabling the containerd image store via
> `docker/setup-docker-action` allows BuildKit to store attestations locally
> without pushing to a registry first. Without the containerd image store,
> Docker Engine rejects the build with: `Attestation is not supported for the docker driver. 
> Switch to a different driver, or turn on the containerd image store, and try again.`
> The `Push image` step runs only if the scan passes, using `if: success()`
> to ensure images are only pushed to the registry when they are free of
> critical or high-severity vulnerabilities.

For more details on using Docker Scout in CI, see [Integrating Docker
Scout with other systems](../../scout/integrations/index.md).

## Grype

[Grype](https://github.com/anchore/grype) is an open-source scanner that checks
container images against vulnerability databases like the NVD and distro
advisories.

### Scan a DHI using Grype

To scan a Docker Hardened Image using Grype with VEX filtering, first export
the VEX attestation and then scan with the `--vex` flag:

```console
$ docker login dhi.io
$ docker pull dhi.io/<image>:<tag>
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
$ grype dhi.io/<image>:<tag> --vex vex.json
```

The `--vex` flag applies VEX statements during the scan, filtering out known
non-exploitable CVEs for accurate results.

For more information on exporting VEX attestations, see [Export VEX
attestations](#export-vex-attestations).

## Trivy

[Trivy](https://github.com/aquasecurity/trivy) is an open-source vulnerability
scanner for containers and other artifacts. It detects vulnerabilities in OS
packages and application dependencies.

### Scan a DHI using Trivy

After installing Trivy, you can scan a Docker Hardened Image by pulling
the image and running the scan command:

```console
$ docker login dhi.io
$ docker pull dhi.io/<image>:<tag>
$ trivy image --scanners vuln dhi.io/<image>:<tag>
```

To filter vulnerabilities using VEX statements, Trivy supports multiple
approaches. Docker recommends using VEX Hub, which provides a seamless workflow
for automatically downloading and applying VEX statements from configured
repositories.

#### Using VEX Hub (recommended)

Configure Trivy to download the Docker Hardened Images advisories repository
from VEX Hub. Run the following commands to set up the VEX repository:

```console
$ trivy vex repo init
$ cat << REPO > ~/.trivy/vex/repository.yaml
repositories:
  - name: default
    url: https://github.com/aquasecurity/vexhub
    enabled: true
    username: ""
    password: ""
    token: ""
  - name: dhi-vex
    url: https://github.com/docker-hardened-images/advisories
    enabled: true
REPO
$ trivy vex repo list
$ trivy vex repo download
```

After setting up VEX Hub, you can scan a Docker Hardened Image with VEX filtering:

```console
$ docker login dhi.io
$ docker pull dhi.io/<image>:<tag>
$ trivy image --scanners vuln --vex repo dhi.io/<image>:<tag>
```

For example, scanning the `dhi.io/python:3.13` image:

```console
$ trivy image --scanners vuln --vex repo dhi.io/python:3.13
```

Example output:

```plaintext
Report Summary

┌─────────────────────────────────────────────────────────────────────────────┬────────────┬─────────────────┐
│                                   Target                                    │    Type    │ Vulnerabilities │
├─────────────────────────────────────────────────────────────────────────────┼────────────┼─────────────────┤
│ dhi.io/python:3.13 (debian 13.2)                                            │   debian   │        0        │
├─────────────────────────────────────────────────────────────────────────────┼────────────┼─────────────────┤
│ opt/python-3.13.11/lib/python3.13/site-packages/pip-25.3.dist-info/METADATA │ python-pkg │        0        │
└─────────────────────────────────────────────────────────────────────────────┴────────────┴─────────────────┘
Legend:
- '-': Not scanned
- '0': Clean (no security findings detected)
```

The `--vex repo` flag applies VEX statements from the configured repository during the scan,
which filters out known non-exploitable CVEs.

#### Using local VEX files

In addition to VEX Hub, Trivy also supports the use of local VEX files for
vulnerability filtering. You can download the VEX attestation that Docker
Hardened Images provide and use it directly with Trivy.

First, download the VEX attestation for your image:

```console
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
```

Then scan the image with the local VEX file:

```console
$ trivy image --scanners vuln --vex vex.json dhi.io/<image>:<tag>
```

## Export VEX attestations

For scanners that need local VEX files (like Grype or Trivy with local files),
you can export the VEX attestations from Docker Hardened Images.

> [!NOTE]
>
> By default, VEX attestations are fetched from `registry.scout.docker.com`. Ensure that you can access this registry
> if your network has outbound restrictions. You can also mirror the attestations to an alternate registry. For more
> details, see [Mirror to a third-party registry](mirror.md#mirror-to-a-third-party-registry).

Export VEX attestations to a JSON file:

```console
$ docker scout vex get dhi.io/<image>:<tag> --output vex.json
```

> [!NOTE]
>
> The `docker scout vex get` command requires [Docker Scout
> CLI](https://github.com/docker/scout-cli/) version 1.18.3 or later.
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://docs/dhi-python:3.13` instead of `docs/dhi-python:3.13`.

## Explore the VEX file

After exporting the VEX attestation, you can inspect its contents to
understand what each statement means and filter by status. For a guided
walkthrough of the VEX document structure, status values, and `jq` filtering
commands, see [Explore VEX statements in Docker Hardened
Images](/guides/dhi-vex-walkthrough/).


---

# Search and evaluate Docker Hardened Images

*Sección: Dhi*

## Search the catalog

You can browse, search, or filter images by category in the [Docker Hub
catalog](https://hub.docker.com/hardened-images/catalog). For details about
the catalog interface, see [Docker Hub](/dhi/tools/hub/).

Alternatively, use the [DHI MCP server](/dhi/tools/mcp/) to search and
inspect the catalog directly from your AI assistant, or use the [DHI
CLI](/dhi/tools/cli/) to browse the catalog from the command line:

```console
$ docker dhi catalog list
```

Filter by image type, name, or compliance requirements:

```console
$ docker dhi catalog list --type image
$ docker dhi catalog list --filter python
$ docker dhi catalog list --fips
$ docker dhi catalog list --stig
```

To view repository details, including available tags and CVE counts:

```console
$ docker dhi catalog get python
```

## Compare and evaluate images

Docker Scout lets you analyze the differences between two images. Comparing a
DHI to a standard image helps you understand the security improvements, package
differences, and overall benefits of adopting hardened images.

Comparison is useful for:

- Evaluating the security improvements when migrating from a standard image to a DHI
- Understanding package and vulnerability differences between image variants
- Assessing the impact of customizations or updates

### Prerequisites

Before comparing images:

- Install [Docker Desktop](/desktop/) to use Docker Scout comparison features.
- Sign in to `dhi.io` for Docker Hardened Images:

  ```console
  $ docker login dhi.io
  ```

### Basic comparison

To compare a Docker Hardened Image with another image, use the [`docker scout
compare`](/reference/cli/docker/scout/compare/) command:

```console
$ docker scout compare dhi.io/<image>:<tag> \
    --to <comparison-image>:<tag> \
    --platform <platform>
```

For example, to compare a DHI Node.js image with the official Node.js image:

```console
$ docker scout compare dhi.io/node:22-debian13 \
    --to node:22 \
    --platform linux/amd64
```

The output shows an overview at the top with key comparison metrics, followed by
detailed package and vulnerability information. Example overview:

```console
  ## Overview

                      │                    Analyzed Image                     │              Comparison Image
  ────────────────────┼───────────────────────────────────────────────────────┼─────────────────────────────────────────────
    Target            │  dhi.io/node:22-debian13                              │  node:22
      digest          │  55d471f61608                                         │  9ee3220f602f
      platform        │ linux/amd64                                           │ linux/amd64
      vulnerabilities │    0C     0H     0M     0L                            │    0C     1H     3M   153L     4?
                      │           -1     -3   -153     -4                     │
      size            │ 41 MB (-367 MB)                                       │ 408 MB
      packages        │ 19 (-726)                                             │ 745
```

### Filter unchanged packages

To focus only on the differences and ignore unchanged packages, use the
`--ignore-unchanged` flag:

```console
$ docker scout compare dhi.io/node:22-debian13 \
    --to node:22 \
    --platform linux/amd64 \
    --ignore-unchanged
```

This output highlights only the packages and vulnerabilities that differ between
the two images.


---

# Get started with DHI Select and Enterprise

*Sección: Dhi*

{{< summary-bar feature_name="Docker Hardened Images" >}}

This guide shows you how to get started with DHI Select and Enterprise
subscriptions. Unlike DHI Community, this workflow lets you mirror repositories
to your organization namespace on Docker Hub, access compliance variants (FIPS),
customize images, and get SLA-backed updates.

## Prerequisites

To use this workflow, you need:

- Organization owner access in your Docker Hub namespace.
- One of the following:
  - A DHI Select or Enterprise subscription. [Contact Docker
    sales](https://www.docker.com/products/hardened-images/#compare) to purchase DHI Enterprise
    or [learn more about DHI plans](../../subscription-billing/plans/dhi.md).
  - An active DHI trial. [Start a free DHI
    trial](https://hub.docker.com/hardened-images/start-free-trial).
- [Docker Desktop](../../desktop/release-notes.md) 4.65 or later to use the
  `docker dhi` CLI.

Each step, when applicable, shows Docker Hub and command line instructions. You
can use either interface.

## Step 1: Find an image to use

{{< tabs group="interface" >}}
{{< tab name="Docker Hub" >}}

1. Go to [Docker Hub](https://hub.docker.com/) and sign in.
2. Select your organization in the left sidebar.
3. Navigate to **Hardened Images** > **Catalog**.
4. Use the search bar or filters to find an image (for example, `python`,
   `node`, or `golang`). For this example, search for `python`.

   To search for an image with a compliance variant (FIPS or STIG), select
   **Filter by** and select the relevant compliance option.

5. Select the Python repository to view its details.

6. Select **Images** to view available image variants.

{{< /tab >}}
{{< tab name="Command line" >}}

1. List available image repositories:

   ```console
   $ docker dhi catalog list --type image
   ```

2. To filter by name and FIPS compliance, use the `--filter` and `--fips` flags:

   ```console
   $ docker dhi catalog list --filter python --fips
   ```

3. Get image details for the repository:

   ```console
   $ docker dhi catalog get python
   ```

{{< /tab >}}
{{< /tabs >}}

Continue to the next step to mirror the image. To dive deeper into exploring
images see [Search and evaluate Docker Hardened Images](search-evaluate.md).

## Step 2: Mirror the repository

Mirroring copies a DHI repository into your organization namespace on Docker
Hub. This lets you receive SLA-backed Docker security patches for your images
and use customization as well as compliance variants. Only organization owners
can mirror repositories.

{{< tabs group="interface" >}}
{{< tab name="Docker Hub" >}}

1. In the image repository details page you found in the previous step, select
   **Use this image** > **Mirror repository**. Note that you must be signed in
   to Docker Hub to perform this action.
2. Select **Mirror**.
3. Wait for images to finish mirroring. This can take a few minutes.
4. Verify the mirrored repository appears in your organization namespace with a
   `dhi-` prefix (for example, `dhi-python`).

{{< /tab >}}
{{< tab name="Command line" >}}

To use the following commands, you must authenticate or configure DHI CLI
authentication using your Docker token. For details, see [Use the DHI
CLI](../tools/cli.md#configuration).

1. Start mirroring the repository to your organization namespace. Replace
   `<your-org>` with your organization name.

   ```console
   $ docker dhi mirror start --org <your-org> dhi/python,<your-org>/dhi-python
   ```

2. Wait for images to finish mirroring. This can take a few minutes.

3. Verify the mirrored repository. Replace `<your-org>` with your organization
   name.

   ```console
   $ docker dhi mirror list --org <your-org>
   ```

{{< /tab >}}
{{< /tabs >}}

Continue to the next step to customize the image. To dive deeper into mirroring
images see [Mirror a repository](mirror.md).

## Step 3: Customize the image

One of the key benefits of DHI Select and Enterprise is the ability to customize
your mirrored images. You can add system packages, configure settings, or make other
modifications to meet your organization's specific requirements.

This example shows how to add the `curl` system package to your mirrored Python image.

{{< tabs group="interface" >}}
{{< tab name="Docker Hub" >}}

1. Go to your organization namespace on Docker Hub.
2. Navigate to your mirrored repository (for example, `dhi-python`).
3. Select **Customizations**.
4. Select **Create customization**.
5. Search for `3-alpine3.23` and select any one of the images.
6. In **Add packages**, select **curl**.
7. Select **Next: Configure**.
8. In **Customization name**, enter a name for your customization (for example, `curl`).
9. Select **Next: Review customization**.
10. Select **Create customization** to start the build.

It can take a few minutes for the customization to build. Go to the
**Customizations** tab of your mirrored repository and view the **Last build**
column to monitor the build status.

{{< /tab >}}
{{< tab name="Command line" >}}

To use the following commands, you must authenticate or configure DHI CLI
authentication using your Docker token. For details, see [Use the DHI
CLI](../tools/cli.md#configuration).

1. Create a customization. Replace `<your-org>` with your organization name.
   This creates a file called `my-customization.yaml` with the customization
   details.

   ```console
   $ docker dhi customization prepare --org <your-org> python 3-alpine3.23 \
       --destination <your-org>/dhi-python \
       --name "python with curl" \
       > my-customization.yaml
   ```

2. Add the `curl` package to the customization. You can edit the file with any
   text or code editor. The following commands use `echo` to add the necessary
   lines to the YAML file:

   ```console
   $ echo "contents:" >> my-customization.yaml
   $ echo "  packages:" >> my-customization.yaml
   $ echo "    - curl" >> my-customization.yaml
   ```

3. Apply the customization:

   ```console
   $ docker dhi customization create --org <your-org> my-customization.yaml
   ```

4. Verify the customization was created:

   ```console
   $ docker dhi customization list --org <your-org>
   ```

It can take a few minutes for the customization to build. To check the build status:

1. Go to your organization namespace on Docker Hub.
2. Navigate to your mirrored repository (for example, `dhi-python`).
3. Select **Customizations**.
4. View the **Last build** column to monitor the build status.

{{< /tab >}}
{{< /tabs >}}

To dive deeper into customization, see [Customize a Docker Hardened
Image](customize.md).

## Step 4: Pull and run your customized image

After the customization build completes, you can pull and run the customized
image from your organization namespace on Docker Hub.

1. Sign in to Docker Hub:

   ```console
   $ docker login
   ```

2. Pull the customized image from your organization. Replace `<your-org>` with
   your organization name. The customized tag includes the suffix based on your
   customization name.

   ```console
   $ docker pull <your-org>/dhi-python:3-alpine3.23_python-with-curl
   ```

3. Run the image and test that `curl` is installed:

   ```console
   $ docker run --rm <your-org>/dhi-python:3-alpine3.23_python-with-curl curl --version
   ```

   This confirms that the `curl` package was successfully added to the image.

To dive deeper into using images, see:

- [Use a Docker Hardened Image](use.md) for general usage
- [Use a Helm chart](helm.md) for deploying with Helm

## Step 5: Remove customization and stop mirroring

To remove the customization and stop mirroring the repository:

1. Go to your organization namespace on Docker Hub.
2. Navigate to your mirrored repository (for example, `dhi-python`).
3. Select **Customizations**.
4. Find the customization you want to delete (for example, `python with curl`).
5. Select the trash can icon.
6. Select **Delete customization** to confirm the deletion.
7. To stop mirroring, go back to your organization's repositories list.
8. Find the mirrored repository (for example, `dhi-python`).
9. Select **Settings**.
10. Select **Stop mirroring**.
11. Select **Stop mirroring** to confirm.

## What's next

You've mirrored, customized, and run a Docker Hardened Image. Here are a few ways to keep going:

- [Migrate existing applications to DHIs](../migration/migrate-with-ai.md): Use
  Gordon to update your Dockerfiles to use Docker Hardened Images as the base.

- [Verify DHIs](verify.md): Use tools like [Docker Scout](/scout/) or Cosign to
  inspect and verify signed attestations, like SBOMs and provenance.

- [Scan DHIs](scan.md): Analyze the image with Docker Scout or other scanners
  to identify known CVEs.


---

# Troubleshoot

*Sección: Dhi*

This page covers debugging techniques and common issues you may encounter while
migrating to or using Docker Hardened Images (DHIs).

## General debugging

Docker Hardened Images prioritize minimalism and security, which means
they intentionally leave out many common debugging tools (like shells or package
managers). This makes direct troubleshooting difficult without introducing risk.
To address this, you can use [Docker
Debug](/reference/cli/docker/debug/), a secure workflow that
temporarily attaches an ephemeral debug container to a running service or image
without modifying the original image.

This section shows how to debug Docker Hardened Images locally during development.
With Docker Debug, you can also debug containers remotely using the `--host`
option.

### Use Docker Debug

#### Step 1: Run a container from a Hardened Image

Start with a DHI-based container that simulates an issue:

```console
$ docker run -d --name myapp dhi.io/python:3.13 python -c "import time; time.sleep(300)"
```

This container doesn't include a shell or tools like `ps`, `top`, or `cat`.

If you try:

```console
$ docker exec -it myapp sh
```

You'll see:

```console
exec: "sh": executable file not found in $PATH
```

#### Step 2: Use Docker Debug to inspect the container

Use the `docker debug` command to attach a temporary, tool-rich debug container to the running instance.

```console
$ docker debug myapp
```

From here, you can inspect running processes, network status, or mounted files.

For example, to check running processes:

```console
$ ps aux
```

Type `exit` to leave the container when done.

### Alternative debugging approaches

In addition to using Docker Debug, you can also use the following approaches for
debugging DHI containers.

#### Use the -dev variant

Docker Hardened Images offer a `-dev` variant that includes a shell
and a package manager to install debugging tools. Simply replace the image tag
with `-dev`:

```console
$ docker run -it --rm dhi.io/python:3.13-dev sh
```

Type `exit` to leave the container when done. Note that using the `-dev` variant
increases the attack surface and it is not recommended as a runtime for
production environments.

#### Mount debugging tools with image mounts

You can use the image mount feature to mount debugging tools into your container
without modifying the base image.

##### Step 1: Run a container from a hardened image

Start with a DHI-based container that simulates an issue:

```console
$ docker run -d --name myapp dhi.io/python:3.13 python -c "import time; time.sleep(300)"
```

##### Step 2: Mount debugging tools into the container

Run a new container that mounts a tool-rich image (like `busybox`) into
the running container's namespace:

```console
$ docker run --rm -it --pid container:myapp \
  --mount type=image,source=busybox,destination=/dbg,ro \
  dhi.io/python:3.13 /dbg/bin/sh
```

This mounts the BusyBox image at `/dbg`, giving you access to its tools while
keeping your original container image unchanged. Since the hardened Python image
doesn't include standard utilities, you need to use the full path to the mounted
tools:

```console
$ /dbg/bin/ls /
$ /dbg/bin/ps aux
$ /dbg/bin/cat /etc/os-release
```

Type `exit` to leave the container when done.

## Common issues

The following are specific issues you may encounter when working with Docker
Hardened Images, along with recommended solutions.

### Permissions

DHIs run as a nonroot user by default for enhanced security. This can result in
permission issues when accessing files or directories. Ensure your application
files and runtime directories are owned by the expected UID/GID or have
appropriate permissions.

To find out which user a DHI runs as, check the repository page for the image on
Docker Hub. See [View image variant
details](../tools/hub.md#image-variant-details-page) for more information.

### Privileged ports

Nonroot containers cannot bind to ports below 1024 by default. This is enforced
by both the container runtime and the kernel (especially in Kubernetes and
Docker Engine < 20.10).

Inside the container, configure your application to listen on an unprivileged
port (1025 or higher). For example `docker run -p 80:8080 my-image` maps
port 8080 in the container to port 80 on the host, allowing you to access it
without needing root privileges.

### No shell

Runtime DHIs omit interactive shells like `sh` or `bash`. If your build or
tooling assumes a shell is present (e.g., for `RUN` instructions), use a `dev`
variant of the image in an earlier build stage and copy the final artifact into
the runtime image.

To find out which shell, if any, a DHI has, check the repository page for the
image on Docker Hub. See [View image variant
details](../tools/hub.md#image-variant-details-page) for more information.

Also, use Docker Debug when you need shell access to a running container. For
more details, see [General debugging](#general-debugging).

### Entry point differences

DHIs may define different entry points compared to Docker Official Images (DOIs)
or other community images.

To find out the ENTRYPOINT or CMD for a DHI, check the repository page for the
image on Docker Hub. See [View image variant
details](../tools/hub.md#image-variant-details-page) for more information.

### No package manager

Runtime Docker Hardened Images are stripped down for security and minimal attack
surface. As a result, they don't include a package manager such as `apk` or
`apt`. This means you can't install additional software directly in the runtime
image.

If your build or application setup requires installing packages (for example, to
compile code, install runtime dependencies, or add diagnostic tools), use a `dev`
variant of the image in a build stage. Then, copy only the necessary artifacts
into the final runtime image.


---

# Use a Docker Hardened Image

*Sección: Dhi*

You can use a Docker Hardened Image (DHI) just like any other image on Docker
Hub. DHIs follow the same familiar usage patterns. Pull them with `docker pull`,
reference them in your Dockerfile, and run containers with `docker run`.

The key difference is that DHIs are security-focused and intentionally minimal
to reduce the attack surface. This means some variants don't include a shell or
package manager, and may run as a non-root user by default.

> [!IMPORTANT]
>
> You must authenticate to the Docker Hardened Images registry (`dhi.io`) to
> pull DHI Community images. You can authenticate using either of the following:
>
> - **Docker ID and password:** Use your Docker Hub username and password. If
>   you don't have a Docker account, [create one](../../accounts/individual/create-account.md)
>   for free.
> - **Access token:** Use a [personal access token
>   (PAT)](../../security/access-tokens/personal-access-tokens.md) for personal accounts, or an
>   [organization access token
>   (OAT)](../../security/access-tokens/organization-access-tokens.md) with your organization
>   name as the username.
>
> Run `docker login dhi.io` to authenticate.

## Considerations when adopting DHIs

Docker Hardened Images are intentionally minimal to improve security. If you're
updating existing Dockerfiles or frameworks to use DHIs, keep in mind that
runtime images don't include shells or package managers, run as non-root users
by default, and may have different configurations than images you're familiar
with.

For a comprehensive checklist of migration considerations and detailed guidance,
see [Migrate to Docker Hardened Images](../migration/index.md).

## Pull, run, and reference DHIs

Docker Hardened Images use different image references depending on your
subscription:

| Subscription        | Image reference            | Authentication        |
|---------------------|----------------------------|-----------------------|
| Community           | `dhi.io/<image>:<tag>`     | `docker login dhi.io` |
| Select & Enterprise | `<your-org>/<image>:<tag>` | `docker login`        |

Select and Enterprise users should [mirror](mirror.md) repositories to their
Docker Hub organization to access compliance variants and customization
features.

After authenticating, use the image reference in standard Docker commands and
Dockerfiles. For example:

```console
$ docker pull dhi.io/python:3.13
$ docker run --rm dhi.io/python:3.13 python -c "print('Hello from DHI')"
```

```dockerfile
FROM dhi.io/python:3.13
COPY . /app
CMD ["python", "/app/main.py"]
```

For multi-stage builds:
- Use a `-dev` tag for build stages that need a shell or package manager. See
  [Use dev variants for framework-based
  applications](#use-dev-variants-for-framework-based-applications).
- Use the `static` image for compiled executables with minimal runtime
  dependencies. See [Use a static image for compiled
  executables](#use-a-static-image-for-compiled-executables).

To learn how to search for available variants, see [Search and evaluate
images](search-evaluate.md).

## Use a DHI in CI/CD pipelines

Docker Hardened Images work just like any other image in your CI/CD pipelines.
You can reference them in Dockerfiles, pull them as part of a pipeline step, or
run containers based on them during builds and tests.

Unlike typical container images, DHIs also include signed
[attestations](../explore/security-concepts/attestations.md) such as SBOMs and provenance
metadata. You can incorporate these into your pipeline to support supply chain
security, policy checks, or audit requirements if your tooling supports it.

To strengthen your software supply chain, consider adding your own attestations
when building images from DHIs. This lets you document how the image was built,
verify its integrity, and enable downstream validation and policy enforcement
using tools like Docker Scout.

To learn how to attach attestations during the build process, see [Docker Build
Attestations](/manuals/build/metadata/attestations.md).

### Discover attestations with ORAS

You can use [ORAS](https://oras.land/) to discover and inspect the attestations
attached to Docker Hardened Images. This is particularly useful in CI/CD
pipelines for supply chain security validation and compliance checks.

For automated workflows, authenticate using an [organization access token
(OAT)](../../security/access-tokens/organization-access-tokens.md). OATs are owned by the
organization rather than an individual user, making them better suited for CI/CD
pipelines.

To discover attestations with ORAS:

1. [Generate an organization access
   token](../../security/access-tokens/organization-access-tokens.md) with **Read public
   repositories** scope.

   The following example shows how to discover attestations on DHI community
   images from `dhi.io`. If you're discovering attestations on images mirrored to
   your organization, generate an OAT scoped to read from your mirrored repository
   instead of **Read public repositories**.

2. Sign in to `dhi.io` using your organization name as the username and the OAT
   as the password.

   > [!WARNING]
   >
   > The following examples export credentials directly on the command line for
   > demonstration purposes. This exposes sensitive tokens in your shell history
   > and process list. In production environments, use secure methods such as
   > reading from files with restricted permissions, environment files loaded
   > at runtime, or secret management tools.

    ```console
    $ oras login dhi.io -u <YOUR_ORGANIZATION_NAME>
    ```

   Or non-interactively in a CI/CD pipeline, set your organization name and token:

   ```console
   $ export DOCKER_ORG="YOUR_ORGANIZATION_NAME"
   $ export OAT="YOUR_ORGANIZATION_ACCESS_TOKEN"
   $ echo $OAT | oras login dhi.io -u "$DOCKER_ORG" --password-stdin
   ```

3. Discover attestations on a DHI image:

   ```console
   $ oras discover dhi.io/node:24-dev --platform linux/amd64
   ```

   > [!NOTE]
   >
   > The `--platform` flag is required. Without it, `oras discover` resolves to
   > the multi-arch image index, which returns only an index-level signature
   > rather than the full set of per-platform attestations.

   A successful response lists the attestations attached to the image,
   including SBOMs, provenance, vulnerability reports, and changelog metadata.

## Use a static image for compiled executables

Docker Hardened Images include a `static` image repository designed specifically
for running compiled executables in an extremely minimal and secure runtime.
Unlike a non-hardened `FROM scratch` image, the DHI `static` image includes
attestations and essential packages like `ca-certificates`.

Use a `-dev` or other builder image to compile your binary, then copy the output
into a `static` image:

```dockerfile
FROM dhi.io/golang:1.22-dev AS build
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp

FROM dhi.io/static:20230311
COPY --from=build /app/myapp /myapp
ENTRYPOINT ["/myapp"]
```

For more multi-stage build patterns, see the [Go migration
example](../migration/examples/go.md).

## Use dev variants for framework-based applications

If you're building applications with frameworks that require package managers or
build tools (such as Python, Node.js, or Go), use a `-dev` variant during the
development or build stage. These variants include essential utilities like
shells, compilers, and package managers to support local iteration and CI
workflows.

Use `-dev` images in your inner development loop or in isolated CI stages to
maximize productivity. Once you're ready to produce artifacts for production,
switch to a smaller runtime variant to reduce the attack surface and image size.

For detailed multi-stage Dockerfile examples using dev variants, see the
migration examples:
- [Go](../migration/examples/go.md)
- [Python](../migration/examples/python.md)
- [Node.js](../migration/examples/node.md)

## Use Socket Firewall variants to monitor package installations

If you want supply chain protection during dependency installation, use a Socket
Firewall variant in place of the standard `-dev` variant in your build stage.
These variants come with [Socket](https://socket.dev/) preinstalled to monitor
package manager activity and block malicious packages before they reach your
image.

Two tiers are available. Use `-sfw-dev` for Socket Firewall Free, or
`-sfw-ent-dev` for Socket Firewall Enterprise (requires an API key from Socket).
The runtime stage stays the same regardless of which build stage variant you
use.

```dockerfile
FROM dhi.io/python:3.13-alpine3.23-sfw-dev AS build
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM dhi.io/python:3.13-alpine3.23
COPY --from=build /app /app
CMD ["python", "app.py"]
```

For more information on Socket Firewall variants, see [Available image
types](../explore/available.md).

## Use compliance and ELS variants

{{< summary-bar feature_name="Docker Hardened Images" >}}

With a DHI Select or DHI Enterprise subscription, you can access additional
image variants:

- Compliance variants: FIPS-enabled and STIG-ready images for regulatory
  requirements
- ELS (Extended Lifecycle Support) variants (requires add-on): Security patches
  for end-of-life image versions

To access these variants, [mirror](mirror.md) the repository to your Docker
Hub organization. For ELS, enable **Mirror end-of-life images** when setting up
mirroring. Once mirrored, use the compliance or EOL tags like any other image
tag.

## Use with Kubernetes

When deploying Docker Hardened Images to Kubernetes, the process is similar to
using any other container image with one key difference: you must configure
image pull secrets to authenticate to the DHI registry. This applies whether
you're pulling directly from `dhi.io`, from a mirror on Docker Hub, or from
your own third-party registry.

### Create an image pull secret

You can create an image pull secret using either an access token or Docker Desktop credentials.

For the `--docker-server` value:
- Use `dhi.io` for community images pulled directly from Docker Hardened Images
- Use `docker.io` for mirrored repositories on Docker Hub
- Use your registry's hostname for third-party registries

#### Using an access token

Create a secret using a [Personal Access Token
(PAT)](../../security/access-tokens/personal-access-tokens.md) or [Organization Access Token
(OAT)](../../security/access-tokens/organization-access-tokens.md). Ensure the token has at
least read-only access to the repositories.

```console
$ kubectl create -n <kubernetes namespace> secret docker-registry <secret name> --docker-server=<registry server> \
        --docker-username=<registry user> --docker-password=<access token> \
        --docker-email=<registry email>
```

#### Using Docker Desktop credentials

If you're already authenticated with Docker Desktop, you can create a secret
using your stored credentials. This method works for registries you've
authenticated to via Docker Desktop (using `docker login <registry>`).

```console
$ NS=<namespace>
$ kubectl create -n ${NS} secret docker-registry dhi-pull-secret \
    --docker-server=<registry server> \
    --docker-username=<registry user> \
    --docker-password="$(echo https://<registry server> | docker-credential-desktop get | jq -r .Secret)" \
    --docker-email=<registry email>
```

This method extracts credentials from Docker Desktop's credential store, avoiding the need to create a separate access token for local development.

### Test the image pull secret

After creating the secret, verify it works by deploying a test pod that
references the secret in its `imagePullSecrets` configuration.

Create a test pod:

```console
kubectl apply --wait -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: dhi-test
  namespace: <kubernetes namespace>
spec:
  containers:
  - name: test
    image: bash:5
    command: [ "sh", "-c", "echo 'Hello from DHI in Kubernetes!'" ]
  imagePullSecrets:
  - name: <secret name>
EOF
```

Check the pod status to ensure it completed successfully:

```console
$ kubectl get -n <kubernetes namespace> pods/dhi-test
```

A successful test shows `Completed` status:

```console
NAME       READY   STATUS      RESTARTS     AGE
dhi-test   0/1     Completed   ...          ...
```

If you see `ErrImagePull` status instead, there's an issue with your secret
configuration:

```console
NAME       READY   STATUS         RESTARTS   AGE
dhi-test   0/1     ErrImagePull   0          ...
```

Verify the pod output matches the expected message:

```console
$ kubectl logs -n <kubernetes namespace> pods/dhi-test
Hello from DHI in Kubernetes!
```

Clean up the test pod:

```console
$ kubectl delete -n <kubernetes namespace> pods/dhi-test
```


---

# Verify a Docker Hardened Image or chart

*Sección: Dhi*

Docker Hardened Images (DHI) and charts include signed attestations that verify
the build process, contents, and security posture.

Docker's public key for DHI images and charts is published at:

- https://registry.scout.docker.com/keyring/dhi/latest.pub
- https://github.com/docker-hardened-images/keyring

Docker recommends using [Docker Scout](/scout/), but you can use
[`regctl`](https://github.com/regclient/regclient) and
[`cosign`](https://docs.sigstore.dev/) to retrieve and verify attestations.
Docker Scout offers several key advantages: it understands DHI attestation
structures, automatically resolves platforms, provides human-readable summaries,
validates in one step with `--verify`, and integrates tightly with Docker's
attestation infrastructure.

> [!IMPORTANT]
>
> You must authenticate to the Docker Hardened Images registry (`dhi.io`) to
> pull images. Use your Docker ID credentials (the same username and password
> you use for Docker Hub) when signing in. If you don't have a Docker account,
> [create one](../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

## Verify image attestations

> [!NOTE]
>
> Before you run `docker scout attest` commands, ensure any image that you have
> pulled locally is up to date with the remote image. You can do this by running
> `docker pull`. If you don't do this, you may see `No attestation found`.

### List available attestations

To list attestations for a mirrored DHI image:

{{< tabs group="tool" >}}
{{< tab name="Docker Scout" >}}

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python:3.13` instead of `dhi.io/python:3.13`.

```console
$ docker scout attest list dhi.io/<image>:<tag>
```

This command shows all available attestations, including SBOMs, provenance, vulnerability reports, and more.

{{< /tab >}}
{{< tab name="regctl" >}}

First, authenticate to both registries. This example authenticates as your
Docker organization using an [organization access token
(OAT)](../../security/access-tokens/organization-access-tokens.md). The OAT must have at least
pull access to the DHI repositories you want to verify. Only repositories in
the token's scope are accessible. Alternatively, you can authenticate as a
Docker Hub user with a [personal access token
(PAT)](../../security/access-tokens/personal-access-tokens.md) that has `read only` access.

> [!WARNING]
>
> The following examples export credentials directly on the command line for
> demonstration purposes. This exposes sensitive tokens in your shell history
> and process list. In production environments, use secure methods such as
> reading from files with restricted permissions, environment files loaded
> at runtime, or secret management tools.

```console
$ export DOCKER_ORG="YOUR_DOCKER_ORG"
$ export DOCKER_OAT="YOUR_DOCKER_OAT"
$ echo $DOCKER_OAT | regctl registry login -u "$DOCKER_ORG" --pass-stdin docker.io
$ echo $DOCKER_OAT | regctl registry login -u "$DOCKER_ORG" --pass-stdin registry.scout.docker.com
```

Then list attestations using the `--external` flag. DHI repositories store image
layers on `dhi.io` (or `docker.io` for mirrored images) and signed attestations
in `registry.scout.docker.com`:

```console
$ regctl artifact list docker.io/${DOCKER_ORG}/<image>:<tag> \
  --external registry.scout.docker.com/${DOCKER_ORG}/<image> \
  --platform linux/amd64
```

For example:

```console
$ regctl artifact list docker.io/${DOCKER_ORG}/dhi-node:22 \
  --external registry.scout.docker.com/${DOCKER_ORG}/dhi-node \
  --platform linux/amd64
```


{{< /tab >}}
{{< /tabs >}}

### Retrieve a specific attestation

{{< tabs group="tool" >}}
{{< tab name="Docker Scout" >}}

To retrieve a specific attestation, use the `--predicate-type` flag with the full predicate type URI:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  dhi.io/<image>:<tag>
```

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python:3.13` instead of `dhi.io/python:3.13`.

For example:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  dhi.io/python:3.13
```

To retrieve only the predicate body:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  --predicate \
  dhi.io/<image>:<tag>
```

{{< /tab >}}
{{< tab name="regctl" >}}

Once you've listed attestations, download the full attestation artifact using the digest from the `Name` field:

```console
$ regctl artifact get <attestation-digest> > attestation.json
```

For example, to save a SLSA provenance attestation:

```console
$ regctl artifact get registry.scout.docker.com/${DOCKER_ORG}/dhi-node@sha256:6cbf803796e281e535f2681de7cd33a1012202610322a50ee745d1bb02ac3c18 > slsa_provenance.json
```

{{< /tab >}}
{{< /tabs >}}

### Validate the attestation

{{< tabs >}}
{{< tab name="Docker Scout" >}}

To validate the attestation using Docker Scout, you can use the `--verify` flag:

```console
$ docker scout attest get dhi.io/<image>:<tag> \
   --predicate-type https://scout.docker.com/sbom/v0.1 --verify
```

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name
> with `registry://`. For example, use `registry://dhi.io/node:20.19-debian12`
> instead of `dhi.io/node:20.19-debian12`.


For example, to verify the SBOM attestation for the `dhi.io/node:20.19-debian12` image:

```console
$ docker scout attest get dhi.io/node:20.19-debian12 \
   --predicate-type https://scout.docker.com/sbom/v0.1 --verify
```

{{< /tab >}}
{{< tab name="cosign" >}}

Once you've listed the attestations and obtained the digest from the `Name` field, verify them using cosign:

```console
$ cosign verify \
  <attestation-digest-from-name-field> \
  --key https://registry.scout.docker.com/keyring/dhi/latest.pub \
  --insecure-ignore-tlog=true
```

For example:

```console
$ cosign verify \
  registry.scout.docker.com/${DOCKER_ORG}/dhi-node@sha256:6cbf803796e281e535f2681de7cd33a1012202610322a50ee745d1bb02ac3c18 \
  --key https://registry.scout.docker.com/keyring/dhi/latest.pub \
  --insecure-ignore-tlog=true
```

> [!NOTE]
>
> The `--insecure-ignore-tlog=true` flag is needed because DHI attestations
> may not be recorded in the public Rekor transparency log to protect private
> customer information. The attestation signature is still verified against
> Docker's public key.

{{< /tab >}}
{{< /tabs >}}

#### Handle missing transparency log entries

When using `--verify` with Docker Scout or `cosign verify`, you may sometimes
see an error like:

```text
ERROR no matching signatures: signature not found in transparency log
```

This occurs because Docker Hardened Images don't always record attestations in
the public [Rekor](https://docs.sigstore.dev/logging/overview/) transparency
log. In cases where an attestation would contain private user information (for
example, your organization's namespace in the image reference), writing it to
Rekor would expose that information publicly.

Even if the Rekor entry is missing, the attestation is still signed with
Docker's public key and can be verified offline by skipping the Rekor
transparency log check.

To skip the transparency log check and validate against Docker's key, use the
`--skip-tlog` flag:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  dhi.io/<image>:<tag> \
  --verify --skip-tlog
```

> [!NOTE]
>
> The `--skip-tlog` flag is only available in Docker Scout CLI version 1.18.2 and
> later.
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python:3.13` instead of `dhi.io/python:3.13`.


This is equivalent to using `cosign` with the `--insecure-ignore-tlog=true`
flag, which validates the signature against Docker's published public key, but
ignores the transparency log check.

### Show the equivalent cosign command

When using the `--verify` flag, it also prints the corresponding
[cosign](https://docs.sigstore.dev/) command to verify the image signature:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  --verify \
  dhi.io/<image>:<tag>
```

> [!NOTE]
>
> If the image exists locally on your device, you must prefix the image name with `registry://`. For example, use
> `registry://dhi.io/python:3.13` instead of `dhi.io/python:3.13`.

For example:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  --verify \
  dhi.io/python:3.13
```

If verification succeeds, Docker Scout prints the full `cosign verify` command.

Example output:

```console
    v SBOM obtained from attestation, 101 packages found
    v Provenance obtained from attestation
    v cosign verify ...
```

> [!IMPORTANT]
>
> When using cosign, you must first authenticate to both the DHI registry
> and the Docker Scout registry.
>
> For example:
>
> ```console
> $ docker login dhi.io
> $ docker login registry.scout.docker.com
> $ cosign verify ...
> ```

## Verify package attestations

In addition to image attestations, individual hardened packages have their own
attestations. These package-level attestations allow you to verify the
provenance and build information for specific packages within an image.

For instructions on how to extract package information from image attestations
and retrieve package-level attestations, see [Package
attestations](hardened-packages.md#package-attestations).

## Verify Helm chart attestations with Docker Scout

Docker Hardened Image Helm charts include the same comprehensive attestations
as container images. The verification process for charts is identical to that
for images, using the same Docker Scout CLI commands.

### List available chart attestations

To list attestations for a DHI Helm chart:

```console
$ docker scout attest list dhi.io/<chart>:<version>
```

For example, to list attestations for the external-dns chart:

```console
$ docker scout attest list dhi.io/external-dns-chart:1.20.0
```

This command shows all available chart attestations, including SBOMs, provenance, vulnerability reports, and more.

### Retrieve a specific chart attestation

To retrieve a specific attestation from a Helm chart, use the `--predicate-type` flag with the full predicate type URI:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  dhi.io/<chart>:<version>
```

For example:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  dhi.io/external-dns-chart:1.20.0
```

To retrieve only the predicate body:

```console
$ docker scout attest get \
  --predicate-type https://cyclonedx.org/bom/v1.6 \
  --predicate \
  dhi.io/<chart>:<version>
```

### Validate chart attestations with Docker Scout

To validate a chart attestation using Docker Scout, use the `--verify` flag:

```console
$ docker scout attest get dhi.io/<chart>:<version> \
   --predicate-type https://scout.docker.com/sbom/v0.1 --verify
```

For example, to verify the SBOM attestation for the external-dns chart:

```console
$ docker scout attest get dhi.io/external-dns-chart:1.20.0 \
   --predicate-type https://scout.docker.com/sbom/v0.1 --verify
```

The same `--skip-tlog` flag described in [Handle missing transparency log
entries](#handle-missing-transparency-log-entries) can also be used with chart
attestations when needed.

## Available DHI attestations

See [available
attestations](../explore/security-concepts/attestations.md#image-attestations) for a list
of attestations available for each DHI image and [Helm chart
attestations](../explore/security-concepts/attestations.md#helm-chart-attestations) for a
list of attestations available for each DHI chart.

## Explore attestations on Docker Hub

You can also browse attestations visually when [exploring an image
variant](search-evaluate.md#image-variant-details). The **Attestations** section
lists each available attestation with its:

- Type (e.g. SBOM, VEX)
- Predicate type URI
- Digest reference for use with `cosign`

These attestations are generated and signed automatically as part of the Docker
Hardened Image or chart build process.


---

# Query VEX for a Docker Hardened Image

*Sección: Dhi*

This is a guided example of using the [DHI API](../tools/api.md)
to fetch VEX statements and suppressed CVEs for a Docker Hardened Image (DHI)
by digest, using the `imagePackagesForImageCoords` query. The query takes an
image digest and returns every package, every CVE reported against it,
whether Docker suppresses that CVE, and why.

> [!NOTE]
> For one-off lookups or local scanning workflows, [`docker scout vex
> get`](scan.md#export-vex-attestations) may be simpler.
> Use the API described here when you need to query many images
> programmatically.

For the API endpoint and authentication, see [Use the DHI
API](../tools/api.md). This page assumes you already have a valid
token.

## Query suppressed CVEs

This is the `imagePackagesForImageCoords` query used in this example. It
fetches every package in an image, every CVE reported against it, and
whether Docker suppresses that CVE:

```graphql
query BaseVex($ctx: Context!, $q: IpImagePackagesForImageCoordsQuery!) {
  imagePackagesForImageCoords(context: $ctx, query: $q) {
    imagePackages {
      packages {
        package {
          purl
          name
          version
          vulnerabilities {
            sourceId
            isExcepted
            fixedBy
            cvss {
              severity
            }
            vulnerabilityExceptions {
              id
              sourceType
              type
              justification
              additionalDetails
              isDhiStatement
            }
          }
        }
      }
    }
  }
}
```

With variables:

```json
{
  "ctx": { "organization": "your-org" },
  "q": {
    "digest": "sha256:<platform-manifest-digest>",
    "hostName": "hub.docker.com",
    "repoName": "your-org/your-repo",
    "includeExcepted": true,
    "includeNodsa": true
  }
}
```

For the full argument reference, see
[`imagePackagesForImageCoords`](../tools/api.md#imagepackagesforimagecoords).

### Get an access token

Exchange your organization access token (OAT) or personal access token (PAT)
for an access token, as described in [Use the DHI
API](../tools/api.md#authentication):

```console
$ DHI_API_TOKEN=$(curl -s -X POST https://hub.docker.com/v2/auth/token \
  -H "Content-Type: application/json" \
  -d "{\"identifier\": \"<identifier>\", \"secret\": \"<token>\"}" \
  | jq -r .access_token)
```

Use your Docker Hub username as `identifier` for a PAT, or your organization
name for an OAT.

### Send the request

Combine the query and variables into the request body described in [Use the
DHI API](../tools/api.md#request-format). The following example
uses `jq` to build the body safely, since the query spans multiple lines:

```console
$ QUERY='query BaseVex($ctx: Context!, $q: IpImagePackagesForImageCoordsQuery!) {
  imagePackagesForImageCoords(context: $ctx, query: $q) {
    imagePackages {
      packages {
        package {
          purl
          name
          version
          vulnerabilities {
            sourceId
            isExcepted
            fixedBy
            cvss {
              severity
            }
            vulnerabilityExceptions {
              id
              sourceType
              type
              justification
              additionalDetails
              isDhiStatement
            }
          }
        }
      }
    }
  }
}'

$ curl https://api.dso.docker.com/v1/graphql \
  -H "Authorization: Bearer $DHI_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --arg query "$QUERY" '{
    query: $query,
    variables: {
      ctx: { organization: "your-org" },
      q: {
        digest: "sha256:<platform-manifest-digest>",
        hostName: "hub.docker.com",
        repoName: "your-org/your-repo",
        includeExcepted: true,
        includeNodsa: true
      }
    }
  }')"
```

Substitute your organization, digest, host, and repository.

## Sample response

The following example is trimmed to a single package:

```json
{
  "package": {
    "purl": "pkg:deb/debian/tar@1.35%2Bdfsg-3.1%2Bdhi1?os_distro=trixie&os_name=debian&os_version=13",
    "name": "tar",
    "version": "1.35+dfsg-3.1+dhi1",
    "vulnerabilities": [
      {
        "sourceId": "CVE-2025-45582",
        "cvss": { "severity": "MEDIUM" },
        "fixedBy": null,
        "isExcepted": false,
        "vulnerabilityExceptions": []
      },
      {
        "sourceId": "CVE-2026-18477",
        "cvss": { "severity": "MEDIUM" },
        "fixedBy": null,
        "isExcepted": true,
        "vulnerabilityExceptions": [
          {
            "id": "debian-nodsa-CVE-2026-18477",
            "sourceType": "EXTERNAL",
            "type": "FALSE_POSITIVE",
            "justification": null,
            "additionalDetails": "Debian NODSA",
            "isDhiStatement": false
          }
        ]
      }
    ]
  }
}
```

Use `isExcepted` to tell whether a CVE is suppressed. For the full response
field reference and the OpenVEX mapping, see
[`imagePackagesForImageCoords`](../tools/api.md#imagepackagesforimagecoords).

## Query customization images

DHI VEX statements apply directly to images built with the [customization
feature](customize.md). Query the customized image's own
digest to get its packages, CVEs, and suppressions in a single call. You
don't need to query the base image separately.

## Caveats

The suppression set for a given digest can change as new advisories and
assessments are published. Cache results per digest with a short TTL rather
than treating a response as permanent.


---

# Migration

*Sección: Dhi*

This section provides guidance for migrating your applications to Docker
Hardened Images (DHI). Migrating to DHI enhances the security posture of your
containerized applications by leveraging hardened base images with built-in
security features.

## Migration paths

Choose the migration approach that best fits your needs:

{{< grid items="grid_migration_paths" >}}

## Resources

{{< grid items="grid_migration_resources" >}}


---

# Migration checklist

*Sección: Dhi*

Use this checklist to ensure you address key considerations when migrating to Docker Hardened Images.

## Migration considerations

| Item               | Action required                                                                                                                                                                                                                                                                                                                 |
|:-------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Base image         | Update your Dockerfile `FROM` statements to reference a Docker Hardened Image instead of your current base image.                                                                                                                                                                                                                                                      |
| Package management | Install packages only in `dev`-tagged images during build stages. Use `apk` for Alpine-based images or `apt` for Debian-based images. Copy the necessary artifacts to your runtime stage, as runtime images don't include package managers.                                                                                                                                                                        |
| Non-root user      | Verify that all files and directories your application needs are readable and writable by the nonroot user (UID 65532), as runtime images run as nonroot by default.                                                                                                                                                                              |
| Multi-stage build  | Use `dev` or `sdk`-tagged images for build stages where you need build tools and package managers. Use non-dev images for your final runtime stage.                                                                                                                                                                                                                                     |
| TLS certificates   | Remove any steps that install ca-certificates, as DHIs include ca-certificates by default.                                                                                                                                                                                                                               |
| Ports              | Configure your application to listen on port 1025 or higher inside the container, as the nonroot user can't bind to privileged ports (below 1024) in Kubernetes or Docker Engine versions older than 20.10. |
| Entry point        | Check the entry point of your chosen DHI using `docker inspect` or the image documentation. Update your Dockerfile's `ENTRYPOINT` or `CMD` instructions if your application relies on a different entry point.                                                                                                                                                                        |
| No shell           | Move any shell commands (`RUN`, `SHELL`) to build stages using `dev`-tagged images. Runtime images don't include a shell, so copy all necessary artifacts from the build stage.                                                                                                                                                                            |


---

# Migration examples

*Sección: Dhi*

This section provides detailed migration examples for common programming languages and frameworks.

## Available examples

{{< grid items="grid_examples" >}}

In addition to this documentation, each Docker Hardened Image repository in
the [Docker Hardened Images
catalog](https://hub.docker.com/hardened-images/catalog) includes image-specific
guidance and best practices for migrating applications built with that language
or framework.


---

# .NET

*Sección: Dhi*

This example shows how to migrate a .NET application to Docker Hardened Images.

The following examples show Dockerfiles before and after migration to Docker
Hardened Images. Each example includes four variations:

- Before (Wolfi): A sample Dockerfile using Wolfi distribution images, before migrating to DHI
- Before (DOI): A sample Dockerfile using Docker Official Images, before migrating to DHI
- After (multi-stage): A sample Dockerfile after migrating to DHI with multi-stage builds (recommended for minimal, secure images)
- After (single-stage): A sample Dockerfile after migrating to DHI with single-stage builds (simpler but results in a larger image with a broader attack surface)

> [!NOTE]
>
> Multi-stage builds are recommended for most use cases. Single-stage builds are
> supported for simplicity, but come with tradeoffs in size and security.
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

{{< tabs >}}
{{< tab name="Before (Wolfi)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM cgr.dev/chainguard/dotnet-sdk:latest-dev AS builder

WORKDIR /src
COPY . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN dotnet restore
RUN dotnet publish -c Release -o /src/out --no-restore

FROM cgr.dev/chainguard/aspnet-runtime:latest

WORKDIR /app
COPY --from=builder /src/out ./

ENTRYPOINT ["dotnet", "app.dll"]
```

{{< /tab >}}
{{< tab name="Before (DOI)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS builder

WORKDIR /src
COPY . ./

# Install any additional packages if needed using apt
# RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

RUN dotnet restore
RUN dotnet publish -c Release -o /app --no-restore

FROM mcr.microsoft.com/dotnet/aspnet:8.0

WORKDIR /app
COPY --from=builder /app ./

ENTRYPOINT ["dotnet", "app.dll"]
```

{{< /tab >}}
{{< tab name="After (multi-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

# === Build stage: Restore, build, and publish the .NET application ===
FROM dhi.io/dotnet:8-sdk-alpine3.22 AS builder

WORKDIR /src
COPY . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN dotnet restore
RUN dotnet publish -c Release -o /app --no-restore

# === Final stage: Create minimal runtime image ===
FROM dhi.io/aspnetcore:8-alpine3.22

WORKDIR /app
COPY --from=builder /app ./

ENTRYPOINT ["dotnet", "app.dll"]
```

{{< /tab >}}
{{< tab name="After (single-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM dhi.io/dotnet:8-sdk-alpine3.22

WORKDIR /src
COPY . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN dotnet restore
RUN dotnet publish -c Release -o /app --no-restore

WORKDIR /app

ENTRYPOINT ["dotnet", "/app/app.dll"]
```

{{< /tab >}}
{{< /tabs >}}


---

# Go

*Sección: Dhi*

This example shows how to migrate a Go application to Docker Hardened Images.

The following examples show Dockerfiles before and after migration to Docker
Hardened Images. Each example includes five variations:

- Before (Ubuntu): A sample Dockerfile using Ubuntu-based images, before migrating to DHI
- Before (Wolfi): A sample Dockerfile using Wolfi distribution images, before migrating to DHI
- Before (DOI): A sample Dockerfile using Docker Official Images, before migrating to DHI
- After (multi-stage): A sample Dockerfile after migrating to DHI with multi-stage builds (recommended for minimal, secure images)
- After (single-stage): A sample Dockerfile after migrating to DHI with single-stage builds (simpler but results in a larger image with a broader attack surface)

> [!NOTE]
>
> Multi-stage builds are recommended for most use cases. Single-stage builds are
> supported for simplicity, but come with tradeoffs in size and security.
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

{{< tabs >}}
{{< tab name="Before (Ubuntu)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM ubuntu/go:1.22-24.04

WORKDIR /app
ADD . ./

# Install any additional packages if needed using apt
# RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" --installsuffix cgo -o main .

ENTRYPOINT ["/app/main"]
```

{{< /tab >}}
{{< tab name="Before (Wolfi)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM cgr.dev/chainguard/go:latest-dev

WORKDIR /app
ADD . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" --installsuffix cgo -o main .

ENTRYPOINT ["/app/main"]
```

{{< /tab >}}
{{< tab name="Before (DOI)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM golang:latest

WORKDIR /app
ADD . ./

# Install any additional packages if needed using apt
# RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" --installsuffix cgo -o main .

ENTRYPOINT ["/app/main"]
```

{{< /tab >}}
{{< tab name="After (multi-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

# === Build stage: Compile Go application ===
FROM dhi.io/golang:1.25-alpine3.23-dev AS builder

WORKDIR /app
ADD . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" --installsuffix cgo -o main .

# === Final stage: Create minimal runtime image ===
FROM dhi.io/golang:1.25-alpine3.23

WORKDIR /app
COPY --from=builder /app/main  /app/main

ENTRYPOINT ["/app/main"]
```

{{< /tab >}}
{{< tab name="After (single-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM dhi.io/golang:1.25-alpine3.23-dev

WORKDIR /app
ADD . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" --installsuffix cgo -o main .

ENTRYPOINT ["/app/main"]
```

{{< /tab >}}
{{< /tabs >}}


---

# Java

*Sección: Dhi*

This example shows how to migrate a Java application to Docker Hardened Images.

The following examples show Dockerfiles before and after migration to Docker
Hardened Images. Each example includes five variations:

- Before (Ubuntu): A sample Dockerfile using Ubuntu-based images, before migrating to DHI
- Before (Wolfi): A sample Dockerfile using Wolfi distribution images, before migrating to DHI
- Before (DOI): A sample Dockerfile using Docker Official Images, before migrating to DHI
- After (multi-stage): A sample Dockerfile after migrating to DHI with multi-stage builds (recommended for minimal, secure images)
- After (single-stage): A sample Dockerfile after migrating to DHI with single-stage builds (simpler but results in a larger image with a broader attack surface)

> [!NOTE]
>
> Multi-stage builds are recommended for most use cases. Single-stage builds are
> supported for simplicity, but come with tradeoffs in size and security.
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

{{< tabs >}}
{{< tab name="Before (Ubuntu)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM ubuntu:24.04 AS builder

WORKDIR /app
COPY . ./

RUN apt-get update && apt-get install -y default-jdk maven --no-install-recommends && rm -rf /var/lib/apt/lists/*

RUN mvn -B package -DskipTests

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y default-jre --no-install-recommends && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY --from=builder /app/target/app.jar /app/app.jar

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

{{< /tab >}}
{{< tab name="Before (Wolfi)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM cgr.dev/chainguard/maven:latest-dev AS builder

WORKDIR /app
COPY . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN mvn -B package -DskipTests

FROM cgr.dev/chainguard/jre:latest

WORKDIR /app
COPY --from=builder /app/target/app.jar /app/app.jar

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

{{< /tab >}}
{{< tab name="Before (DOI)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM maven:3.9-eclipse-temurin-21 AS builder

WORKDIR /app
COPY . ./

# Install any additional packages if needed using apt
# RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*

RUN mvn -B package -DskipTests

FROM eclipse-temurin:21-jre

WORKDIR /app
COPY --from=builder /app/target/app.jar /app/app.jar

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

{{< /tab >}}
{{< tab name="After (multi-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

# === Build stage: Compile and package the Java application with Maven ===
FROM dhi.io/maven:3-jdk21-alpine3.22-dev AS builder

WORKDIR /app
COPY . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN mvn -B package -DskipTests

# === Final stage: Create minimal runtime image ===
FROM dhi.io/eclipse-temurin:21-alpine3.22

WORKDIR /app
COPY --from=builder /app/target/app.jar /app/app.jar

ENTRYPOINT ["java", "-jar", "/app/app.jar"]
```

{{< /tab >}}
{{< tab name="After (single-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM dhi.io/maven:3-jdk21-alpine3.22-dev

WORKDIR /app
COPY . ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache git

RUN mvn -B package -DskipTests

ENTRYPOINT ["java", "-jar", "/app/target/app.jar"]
```

{{< /tab >}}
{{< /tabs >}}


---

# Node.js

*Sección: Dhi*

This example shows how to migrate a Node.js application to Docker Hardened Images.

The following examples show Dockerfiles before and after migration to Docker
Hardened Images. Each example includes five variations:

- Before (Ubuntu): A sample Dockerfile using Ubuntu-based images, before migrating to DHI
- Before (Wolfi): A sample Dockerfile using Wolfi distribution images, before migrating to DHI
- Before (DOI): A sample Dockerfile using Docker Official Images, before migrating to DHI
- After (multi-stage): A sample Dockerfile after migrating to DHI with multi-stage builds (recommended for minimal, secure images)
- After (single-stage): A sample Dockerfile after migrating to DHI with single-stage builds (simpler but results in a larger image with a broader attack surface)

> [!NOTE]
>
> Multi-stage builds are recommended for most use cases. Single-stage builds are
> supported for simplicity, but come with tradeoffs in size and security.
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

{{< tabs >}}
{{< tab name="Before (Ubuntu)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y nodejs npm --no-install-recommends && rm -rf /var/lib/apt/lists/*

WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install

COPY . .

CMD ["node", "index.js"]
```

{{< /tab >}}
{{< tab name="Before (Wolfi)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM cgr.dev/chainguard/node:latest-dev
WORKDIR /usr/src/app

COPY package*.json ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache python3 make g++

RUN npm install

COPY . .

CMD ["index.js"]
```

{{< /tab >}}
{{< tab name="Before (DOI)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM node:latest
WORKDIR /usr/src/app

COPY package*.json ./

# Install any additional packages if needed using apt
# RUN apt-get update && apt-get install -y python3 make g++ && rm -rf /var/lib/apt/lists/*

RUN npm install

COPY . .

CMD ["node", "index.js"]
```

{{< /tab >}}
{{< tab name="After (multi-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

# === Build stage: Install dependencies and build application ===
FROM dhi.io/node:22-alpine3.23-dev AS builder
WORKDIR /usr/src/app

COPY package*.json ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache python3 make g++

RUN npm install

COPY . .

# === Final stage: Create minimal runtime image ===
FROM dhi.io/node:22-alpine3.23
ENV PATH=/app/node_modules/.bin:$PATH

COPY --from=builder --chown=node:node /usr/src/app /app

WORKDIR /app

CMD ["index.js"]
```

{{< /tab >}}
{{< tab name="After (single-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM dhi.io/node:22-alpine3.23-dev
WORKDIR /usr/src/app

COPY package*.json ./

# Install any additional packages if needed using apk
# RUN apk add --no-cache python3 make g++

RUN npm install

COPY . .

CMD ["node", "index.js"]
```

{{< /tab >}}
{{< /tabs >}}


---

# Python

*Sección: Dhi*

This example shows how to migrate a Python application to Docker Hardened Images.

The following examples show Dockerfiles before and after migration to Docker
Hardened Images. Each example includes five variations:

- Before (Ubuntu): A sample Dockerfile using Ubuntu-based images, before migrating to DHI
- Before (Wolfi): A sample Dockerfile using Wolfi distribution images, before migrating to DHI
- Before (DOI): A sample Dockerfile using Docker Official Images, before migrating to DHI
- After (multi-stage): A sample Dockerfile after migrating to DHI with multi-stage builds (recommended for minimal, secure images)
- After (single-stage): A sample Dockerfile after migrating to DHI with single-stage builds (simpler but results in a larger image with a broader attack surface)

> [!NOTE]
>
> Multi-stage builds are recommended for most use cases. Single-stage builds are
> supported for simplicity, but come with tradeoffs in size and security.
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

{{< tabs >}}
{{< tab name="Before (Ubuntu)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM ubuntu:24.04 AS builder

RUN apt-get update && apt-get install -y python3 python3-pip python3-venv --no-install-recommends && rm -rf /var/lib/apt/lists/*

ENV LANG=C.UTF-8
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

WORKDIR /app

RUN python3 -m venv /app/venv
COPY requirements.txt .

RUN pip install --no-cache-dir -r requirements.txt

FROM ubuntu:24.04

RUN apt-get update && apt-get install -y python3 --no-install-recommends && rm -rf /var/lib/apt/lists/*

WORKDIR /app

ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

COPY app.py ./
COPY --from=builder /app/venv /app/venv

ENTRYPOINT [ "python3", "/app/app.py" ]
```

{{< /tab >}}
{{< tab name="Before (Wolfi)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM cgr.dev/chainguard/python:latest-dev AS builder

ENV LANG=C.UTF-8
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

WORKDIR /app

RUN python -m venv /app/venv
COPY requirements.txt .

# Install any additional packages if needed using apk
# RUN apk add --no-cache gcc musl-dev

RUN pip install --no-cache-dir -r requirements.txt

FROM cgr.dev/chainguard/python:latest

WORKDIR /app

ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

COPY app.py ./
COPY --from=builder /app/venv /app/venv

ENTRYPOINT [ "python", "/app/app.py" ]
```

{{< /tab >}}
{{< tab name="Before (DOI)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM python:latest AS builder

ENV LANG=C.UTF-8
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

WORKDIR /app

RUN python -m venv /app/venv
COPY requirements.txt .

# Install any additional packages if needed using apt
# RUN apt-get update && apt-get install -y gcc && rm -rf /var/lib/apt/lists/*

RUN pip install --no-cache-dir -r requirements.txt

FROM python:latest

WORKDIR /app

ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

COPY app.py ./
COPY --from=builder /app/venv /app/venv

ENTRYPOINT [ "python", "/app/app.py" ]
```

{{< /tab >}}
{{< tab name="After (multi-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

# === Build stage: Install dependencies and create virtual environment ===
FROM dhi.io/python:3.13-alpine3.23-dev AS builder

ENV LANG=C.UTF-8
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

WORKDIR /app

RUN python -m venv /app/venv
COPY requirements.txt .

# Install any additional packages if needed using apk
# RUN apk add --no-cache gcc musl-dev

RUN pip install --no-cache-dir -r requirements.txt

# === Final stage: Create minimal runtime image ===
FROM dhi.io/python:3.13-alpine3.23

WORKDIR /app

ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

COPY app.py ./
COPY --from=builder /app/venv /app/venv

ENTRYPOINT [ "python", "/app/app.py" ]
```

{{< /tab >}}
{{< tab name="After (single-stage)" >}}

```dockerfile
#syntax=docker/dockerfile:1

FROM dhi.io/python:3.13-alpine3.23-dev

ENV LANG=C.UTF-8
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV PATH="/app/venv/bin:$PATH"

WORKDIR /app

RUN python -m venv /app/venv
COPY requirements.txt .

# Install any additional packages if needed using apk
# RUN apk add --no-cache gcc musl-dev

RUN pip install --no-cache-dir -r requirements.txt

COPY app.py ./

ENTRYPOINT [ "python", "/app/app.py" ]
```

{{< /tab >}}
{{< /tabs >}}


---

# Migrate from Alpine or Debian

*Sección: Dhi*

Docker Hardened Images (DHI) come in both [Alpine-based and Debian-based
variants](../explore/available.md). In many cases, migrating from another image
based on these distributions is as simple as changing the base image in your
Dockerfile.

This guide helps you migrate from an existing Alpine-based or Debian-based
Docker Official Image (DOI) to DHI.

If you're currently using a Debian-based Docker Official Image, migrate to the
Debian-based DHI variant. If you're using an Alpine-based image, migrate to the
Alpine-based DHI variant. This minimizes changes to package management and
dependencies during migration.

## Key differences

When migrating from non-hardened images to DHI, be aware of these key differences:

| Item               | Non-hardened images                                                                                                                                                                                                                                                                                                         | Docker Hardened Images                                                                                                                                                                                                                                                                                                         |
|:-------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Package management | Package managers generally available in all images.                                                                                                                                                                                                                                  | Package managers generally only available in images with a `dev` tag. Runtime images don't contain package managers. Use multi-stage builds and copy necessary artifacts from the build stage to the runtime stage.                                                                  |
| Non-root user      | Usually runs as root by default                                                                                                                                                                                                                                                                                                | Runtime variants run as the nonroot user by default. Ensure that necessary files and directories are accessible to the nonroot user.                                                                                                                                                                                                          |
| Multi-stage build  | Optional                                                                                                                                                                                                                                                                                                                       | Recommended. Use images with a `dev` or `sdk` tags for build stages and non-dev images for runtime.                                                                                                                                                                                                                           |
| TLS certificates   | May need to be installed                                                                                                                                                                                                                                                                                                       | Contain standard TLS certificates by default. There is no need to install TLS certificates.                                                                                                                                                                                                                                   |
| Ports              | Can bind to privileged ports (below 1024) when running as root                                                                                                                                                                                                                                                                 | Run as a nonroot user by default. Applications can't bind to privileged ports (below 1024) when running in Kubernetes or in Docker Engine versions older than 20.10. Configure your application to listen on port 1025 or higher inside the container.                                                                        |
| Entry point        | Varies by image                                                                                                                                                                                                                                                                                                                | May have different entry points than Docker Official Images. Inspect entry points and update your Dockerfile if necessary.                                                                                                                                                                                                    |
| Shell           | Shell generally available in all images                                                                                                                                                                                                                                                                                                  | Runtime images don't contain a shell. Use `dev` images in build stages to run shell commands and then copy artifacts to the runtime stage.                                                                                                                                                                                      |

## Migration steps

### Step 1: Update the base image in your Dockerfile

Update the base image in your application's Dockerfile to a hardened image. This
is typically going to be an image tagged as `dev` or `sdk` because it has the tools
needed to install packages and dependencies.

The following example diff snippet from a Dockerfile shows the old base image
replaced by the new hardened image.

> [!NOTE]
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.


```diff
- ## Original base image
- FROM golang:1.25

+ ## Updated to use hardened base image
+ FROM dhi.io/golang:1.25-debian13-dev
```

Note that DHI does not have a `latest` tag in order to promote best practices
around image versioning. Ensure that you specify the appropriate version tag for
your image. To find the right tag, explore the available tags in the [DHI
Catalog](https://hub.docker.com/hardened-images/catalog/). In addition, the
distribution base is specified in the tag (for example, `-alpine3.22` or
`-debian12`), so be sure to select the correct variant for your application.

### Step 2: Update the runtime image in your Dockerfile

> [!NOTE]
>
> Multi-stage builds are recommended to keep your final image minimal and
> secure. Single-stage builds are supported, but they include the full `dev` image
> and therefore result in a larger image with a broader attack surface.

To ensure that your final image is as minimal as possible, you should use a
[multi-stage build](../../build/building/multi-stage.md). All stages in your
Dockerfile should use a hardened image. While intermediary stages will typically
use images tagged as `dev` or `sdk`, your final runtime stage should use a runtime image.

Utilize the build stage to compile your application and copy the resulting
artifacts to the final runtime stage. This ensures that your final image is
minimal and secure.

The following example shows a multi-stage Dockerfile with a build stage and runtime stage:

```dockerfile
# Build stage
FROM dhi.io/golang:1.25-debian13-dev AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# Runtime stage
FROM dhi.io/golang:1.25-debian13
WORKDIR /app
COPY --from=builder /app/myapp .
ENTRYPOINT ["/app/myapp"]
```

After updating your Dockerfile, build and test your application. If you encounter
issues, see the [Troubleshoot](../how-to/troubleshoot.md) guide for common
problems and solutions.

## Language-specific examples

See the examples section for language-specific migration examples:

- [Go](examples/go.md)
- [Python](examples/python.md)
- [Node.js](examples/node.md)


---

# Migrate from Ubuntu

*Sección: Dhi*

Docker Hardened Images (DHI) come in [Alpine-based and Debian-based
variants](../explore/available.md). When migrating from an Ubuntu-based image,
you should migrate to the Debian-based DHI variant, as both Ubuntu and Debian
share the same package management system (APT) and underlying architecture,
making migration straightforward.

This guide helps you migrate from an existing Ubuntu-based image to DHI.

## Key differences

When migrating from Ubuntu-based images to DHI Debian, be aware of these key differences:

| Item               | Ubuntu-based images                                                                                                                                                                                                                                                                                                         | Docker Hardened Images                                                                                                                                                                                                                                                                                                         |
|:-------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Package management | Varies by image. Some include APT package manager, others don't                                                                                                                                                                                                  | Package managers generally only available in images with a `dev` tag. Runtime images don't contain package managers. Use multi-stage builds and copy necessary artifacts from the build stage to the runtime stage.                                                                  |
| Non-root user      | Varies by image. Some run as root, others as non-root                                                                                                                                                                                                                                                                                                | Runtime variants run as the nonroot user by default. Ensure that necessary files and directories are accessible to the nonroot user.                                                                                                                                                                                                          |
| Multi-stage build  | Recommended                                                                                                                                                                                                                                                                                                                       | Recommended. Use images with a `dev` or `sdk` tags for build stages and non-dev images for runtime.                                                                                                                                                                                                                           |
| Ports              | Can bind to privileged ports (under 1024) when running as root                                                                                                                                                                                                                                                                 | Run as a nonroot user by default. Applications can't bind to privileged ports (under 1024) when running in Kubernetes or in Docker Engine versions older than 20.10. Configure your application to listen on port 1025 or higher inside the container.                                                                        |
| Entry point        | Varies by image                                                                                                                                                                                                                                                                                                                | May have different entry points than Ubuntu-based images. Inspect entry points and update your Dockerfile if necessary.                                                                                                                                                                                                    |
| Shell              | Varies by image. Some include a shell, others don't                                                                                                                                                                                                                                                                                                  | Runtime images don't contain a shell. Use `dev` images in build stages to run shell commands and then copy artifacts to the runtime stage.                                                                                                                                                                                      |
| Package repositories | Uses Ubuntu package repositories                                                                                                                                                                                                                                                                                                  | Uses Debian package repositories. Most packages have similar names, but some may differ.                                                                                                                                                                                      |

## Migration steps

### Step 1: Update the base image in your Dockerfile

Update the base image in your application's Dockerfile to a hardened image. This
is typically going to be an image tagged as `dev` or `sdk` because it has the tools
needed to install packages and dependencies.

The following example diff snippet from a Dockerfile shows the old Ubuntu-based image
replaced by the new DHI Debian image.

> [!NOTE]
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.


```diff
- ## Original Ubuntu-based image
- FROM ubuntu/go:1.22-24.04

+ ## Updated to use hardened Debian-based image
+ FROM dhi.io/golang:1.25-debian13-dev
```

To find the right tag, explore the available tags in the [DHI
Catalog](https://hub.docker.com/hardened-images/catalog/).

### Step 2: Update package installation commands

Since Ubuntu and Debian both use APT for package management, most package
installation commands remain similar. However, you need to ensure that package
installations only occur in `dev` or `sdk` images, as runtime images don't
contain package managers.

```diff
- ## Ubuntu: Installing packages
- FROM ubuntu/go:1.22-24.04
- RUN apt-get update && apt-get install -y \
-     git \
-     && rm -rf /var/lib/apt/lists/*

+ ## DHI: Use a language-specific dev image with package manager
+ FROM dhi.io/golang:1.25-debian13-dev
+ RUN apt-get update && apt-get install -y \
+     git \
+     && rm -rf /var/lib/apt/lists/*
```

Most Ubuntu packages are available in Debian with the same names. If you
encounter missing packages, you can search for equivalent packages using the
[Debian package search](https://packages.debian.org/) website.

### Step 3: Update the runtime image in your Dockerfile

> [!NOTE]
>
> Multi-stage builds are recommended to keep your final image minimal and
> secure. Single-stage builds are supported, but they include the full `dev` image
> and therefore result in a larger image with a broader attack surface.

To ensure that your final image is as minimal as possible, you should use a
[multi-stage build](../../build/building/multi-stage.md). All stages in your
Dockerfile should use a hardened image. While intermediary stages will typically
use images tagged as `dev` or `sdk`, your final runtime stage should use a runtime image.

Utilize the build stage to install dependencies and prepare your application,
then copy the resulting artifacts to the final runtime stage. This ensures that
your final image is minimal and secure.

The following example shows a multi-stage Dockerfile migrating from Ubuntu to DHI Debian:

```dockerfile
# Build stage
FROM dhi.io/golang:1.25-debian13-dev AS builder
WORKDIR /app

# Install system dependencies (only available in dev images)
RUN apt-get update && apt-get install -y \
    git \
    && rm -rf /var/lib/apt/lists/*

# Copy application files
COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w" -o main .

# Runtime stage
FROM dhi.io/golang:1.25-debian13
WORKDIR /app

# Copy compiled binary from builder
COPY --from=builder /app/main /app/main

# Run the application
ENTRYPOINT ["/app/main"]
```

## Language-specific examples

See the examples section for language-specific migration examples:

- [Go](examples/go.md)
- [Python](examples/python.md)
- [Node.js](examples/node.md)


---

# Migrate from Wolfi

*Sección: Dhi*

This guide helps you migrate from Wolfi-based images to Docker Hardened
Images (DHI). Generally, the migration process is straightforward since Wolfi is
Alpine-like and DHI provides an Alpine-based hardened image.

Like other hardened images, DHI provides comprehensive
[attestations](/dhi/explore/security-concepts/attestations/) including SBOMs and provenance,
allowing you to [verify](../how-to/verify.md) image signatures and
[scan](../how-to/scan.md) for vulnerabilities to ensure the security
and integrity of your images.

## Migration steps

The following example demonstrates how to migrate a Dockerfile from a
Wolfi-based image to an Alpine-based Docker Hardened Image.

### Step 1: Update the base image in your Dockerfile

Update the base image in your application's Dockerfile to a hardened image. This
is typically going to be an image tagged as `dev` or `sdk` because it has the tools
needed to install packages and dependencies.

The following example diff snippet from a Dockerfile shows the old base image
replaced by the new hardened image.

> [!NOTE]
>
> You must authenticate to `dhi.io` before you can pull Docker Hardened Images.
> Use your Docker ID credentials (the same username and password you use for
> Docker Hub). If you don't have a Docker account, [create
> one](../../accounts/individual/create-account.md) for free.
>
> Run `docker login dhi.io` to authenticate.

```diff
- ## Original base image
- FROM cgr.dev/chainguard/go:latest-dev

+ ## Updated to use hardened base image
+ FROM dhi.io/golang:1.25-alpine3.24-dev
```

Note that DHI does not have a `latest` tag in order to promote best practices
around image versioning. Ensure that you specify the appropriate version tag for your image. To find the right tag, explore the available tags in the [DHI Catalog](https://hub.docker.com/hardened-images/catalog/).

### Step 2: Update the runtime image in your Dockerfile

> [!NOTE]
>
> Multi-stage builds are recommended to keep your final image minimal and
> secure. Single-stage builds are supported, but they include the full `dev` image
> and therefore result in a larger image with a broader attack surface.

To ensure that your final image is as minimal as possible, you should use a
[multi-stage build](../../build/building/multi-stage.md). All stages in your
Dockerfile should use a hardened image. While intermediary stages will typically
use images tagged as `dev` or `sdk`, your final runtime stage should use a runtime image.

Utilize the build stage to compile your application and copy the resulting
artifacts to the final runtime stage. This ensures that your final image is
minimal and secure.

The following example shows a multi-stage Dockerfile with a build stage and runtime stage:

```dockerfile
# Build stage
FROM dhi.io/golang:1.25-alpine3.24-dev AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# Runtime stage
FROM dhi.io/golang:1.25-alpine3.24
WORKDIR /app
COPY --from=builder /app/myapp .
ENTRYPOINT ["/app/myapp"]
```

After updating your Dockerfile, build and test your application. If you encounter
issues, see the [Troubleshoot](../how-to/troubleshoot.md) guide for common
problems and solutions.

## Language-specific examples

See the examples section for language-specific migration examples:

- [Go](examples/go.md)
- [Python](examples/python.md)
- [Node.js](examples/node.md)


---

# Migrate using Gordon

*Sección: Dhi*

{{< summary-bar feature_name="Gordon DHI migration" >}}

You can use Gordon to automatically migrate your
Dockerfile to use Docker Hardened Images (DHI).

1. Ensure Gordon is [enabled](../../subscription-billing/plans/gordon.md#enable-ask-gordon).
2. In the terminal, navigate to the directory containing your Dockerfile.
3. Start a conversation with the assistant:
   ```bash
   docker ai
   ```
4. Type:
   ```console
   "Migrate my dockerfile to DHI"
   ```
5. Follow the conversation with the assistant. The assistant will edit your Dockerfile, so when
   it requests access to the filesystem and more, type `yes` to allow the assistant to proceed.

When the migration is complete, you see a success message:

```text
The migration to Docker Hardened Images (DHI) is complete. The updated Dockerfile
successfully builds the image, and no vulnerabilities were detected in the final image.
The functionality and optimizations of the original Dockerfile have been preserved.
```

> [!IMPORTANT]
>
> As with any AI tool, you must verify the assistant's edits and test your image.


---

# Release notes

*Sección: Dhi*




---

# DHI CLI release notes

*Sección: Dhi*

This page lists changes in recent stable releases of the DHI CLI (`docker dhi`). For
the full release history, including pre-releases and downloads, see the
[dhictl releases on GitHub](https://github.com/docker-hardened-images/dhictl/releases).

<!-- BEGIN GENERATED RELEASES -->

## 0.0.7

{{< release-date date="2026-07-21" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.7)

### Bug Fixes

- Fixes JSON output incorrectly escaping ampersands as `\u0026` — values such as catalog categories containing `&` now appear as-is in output

## 0.0.6

{{< release-date date="2026-07-13" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.6)

This release fixes an issue that prevented customizations from being created via the CLI.

### Bug Fixes

- Fixes `dhictl customization create` failing when GraphQL rejected mutation inputs that incorrectly included the output-only `__typename` field from OCI artifact data

## 0.0.5

{{< release-date date="2026-06-29" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.5)

Maintenance release with dependency updates.

## 0.0.4

{{< release-date date="2026-05-25" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.4)

### What's New

- Adds `deb` subcommand for DHI DEB repositories that emits netrc-style credentials for authenticating against DHI DEB repositories

## 0.0.3

{{< release-date date="2026-04-22" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.3)

### What's New

- Adds attestation list and get commands for managing attestations
- Adds SBOM subcommand for software bill of materials attestation
- Adds bulk support to prepare command for customizations
- Adds compression field support for customizations
- Adds tag-definition-id column to catalog get output

### Breaking change

We removed the `--output` flags from the few commands that had it (`customization prepare` and `customization get`) in favor of stdout redirections.
```console
# before
dhictl customization prepare --org my-org golang 1.25 --output my-customization.yaml

# after 
dhictl customization prepare --org my-org golang 1.25 > my-customization.yaml
```

## 0.0.2

{{< release-date date="2026-03-19" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.2)

This is a maintenance release focused on build system improvements.

### Technical Changes

- Disables CGO globally to fix macOS 16 dyld crash and simplify build process

## 0.0.1

{{< release-date date="2026-03-12" >}}

[GitHub release](https://github.com/docker-hardened-images/dhictl/releases/tag/v0.0.1)

This release improves the mirroring functionality in dhictl by allowing command arguments.

### Improvements

- Mirror start command now accepts arguments for more flexible mirroring operations

<!-- END GENERATED RELEASES -->

## Earlier releases

For older versions, see the
[dhictl releases on GitHub](https://github.com/docker-hardened-images/dhictl/releases).


---

# Docker Hardened Images release notes

*Sección: Dhi*

This page contains information about the new features, improvements, and changes
in the Docker Hardened Images (DHI) platform. Release notes are aggregated by
quarter and include only notable product changes.

## Q3 2026

New features and enhancements released in the third quarter of 2026.

- DHI MCP server: The DHI catalog is now accessible via a remote MCP server at
  `https://dhi.io/mcp`. Connect any MCP-capable AI assistant to search
  repositories, inspect image metadata, retrieve SBOMs, check CVEs, and manage
  mirrors using plain language. For more information, see [Use the DHI MCP
  server](/dhi/tools/mcp/).
- DHI API: VEX statements and suppressed CVEs for a Docker Hardened Image are
  now available to query by digest through the DHI GraphQL API. For more
  information, see [Use the DHI API](../tools/api.md).

## Q2 2026

New features and enhancements released in the second quarter of 2026.

- Debian Hardened System Packages: Added support for Debian-based Docker
  Hardened System Packages (HSP), including new CLI workflows for authenticating
  to the Debian HSP repository.
- Mend.io scanner integration: Mend.io is now a supported scanner for consuming
  DHI VEX data.
- Black Duck scanner integration: Black Duck is now a supported scanner for
  consuming DHI VEX data.
- DHI Select self-serve purchase: DHI Select is now available for self-serve
  purchase directly through the Docker website.
- Bulk customization: Apply customizations to multiple images in a single
  operation through the Docker Hub UI and the CLI.
- Terraform provider: Manage DHI resources, including customizations and
  mirrors, using the official Terraform provider.

## Q1 2026

New features and enhancements released in the first quarter of 2026.

- Docker Hardened System Packages (HSP): Announced Docker Hardened System
  Packages, a new offering that provides individually hardened packages for use
  in your own base images. For more information, see the [announcement blog
  post](https://www.docker.com/blog/announcing-docker-hardened-system-packages/).
- Wiz scanner integration: Wiz is now a supported scanner for consuming DHI VEX
  data.

## Q4 2025

New features and enhancements released in the fourth quarter of 2025.

- Docker Hardened Images Community (Free): Docker Hardened Images are now
  available for every developer through a Community subscription tier. The
  subscription tiers are now Community, Select, and Enterprise. For more
  information, see the [announcement blog
  post](https://www.docker.com/blog/docker-hardened-images-for-every-developer/).
- Independent security validation by SRLabs: SRLabs published an independent
  security validation of Docker Hardened Images. See the
  [validation announcement](https://www.docker.com/blog/docker-hardened-images-security-independently-validated-by-srlabs/).
- Docker Scout scoring for DHI: Docker Scout image scoring now accounts for the
  security improvements provided by DHI.
- Trivy VEX repository: VEX data for DHI is published in a Trivy-compatible OCI
  VEX repository, making it easier for Trivy and other scanners to consume.
- Docker Scout DHI policy: New Docker Scout policy that evaluates whether images
  use Docker Hardened Images.
- Hardened Helm charts (Beta): Beta release of Docker Hardened Helm Charts. For
  more information, see the [announcement blog
  post](https://www.docker.com/blog/docker-hardened-images-helm-charts-beta/).
- Mirroring UX: Updated the mirroring experience in Docker Hub with a refreshed
  UI and clearer flows.

## Q3 2025

New features and enhancements released in the third quarter of 2025.

- Next evolution release: A major release that introduced customizations,
  FedRAMP-ready images, the AI Migration Agent, and deeper scanner integrations.
  See the [announcement blog
  post](https://www.docker.com/blog/the-next-evolution-of-docker-hardened-images/)
  and the [FedRAMP compliance blog
  post](https://www.docker.com/blog/fedramp-compliance-with-hardened-images/).
- DHI customizations: Customize DHI images directly from the Docker Hub UI,
  with options for adding packages, files, and configuration on top of a base
  hardened image.
- AI Migration Agent: AI-assisted Dockerfile migration to help convert existing
  Dockerfiles to use Docker Hardened Images.
- CIS compliance attestations: CIS benchmark compliance attestations are now
  included with DHI images.
- STIG variants: STIG-hardened image variants for U.S. Department of Defense
  compliance use cases.

## Q2 2025

New features and enhancements released in the second quarter of 2025.

- Docker Hardened Images launch: Docker announced Docker Hardened Images, a new
  family of secure, minimal, and production-ready container images maintained by
  Docker. For more information, see the [launch blog
  post](https://www.docker.com/blog/introducing-docker-hardened-images/).
- FIPS variants: FIPS-validated image variants for Docker Hardened Images.


---

# Resources and feedback

*Sección: Dhi*

This page provides links to additional resources, community channels, and ways
to give feedback on Docker Hardened Images (DHI).

For product information and feature comparison, visit the [Docker Hardened
Images product page](https://www.docker.com/products/hardened-images/).

## Guides

For guides that demonstrate how to use Docker Hardened Images in various
scenarios, see the [guides section filtered by DHI](/guides/?tags=dhi).

## Docker Hub

Docker Hardened Images are available on Docker Hub:

- [Docker Hardened Images Catalog](https://dhi.io): Browse and pull Docker
  Hardened Images from the official catalog
- [Docker Hub MCP Server](https://hub.docker.com/mcp/server/dockerhub/overview):
  MCP server to list Docker Hardened Images (DHIs) available in your
  organizations

## GitHub repositories and resources

Docker Hardened Images repositories are available in the
[docker-hardened-images](https://github.com/docker-hardened-images) GitHub
organization:

- [Catalog](https://github.com/docker-hardened-images/catalog): DHI definition
  files and catalog metadata
- [Advisories](https://github.com/docker-hardened-images/advisories): CVE
  advisories for OSS packages distributed with DHIs
  - [Scanner vendor integration guide](https://github.com/docker-hardened-images/advisories/tree/main/integration):
    Reference for scanner vendors integrating DHI VEX support
- [Keyring](https://github.com/docker-hardened-images/keyring): Public signing
  keys and verification tools
- [Log](https://github.com/docker-hardened-images/log): Log of references (tag >
  digest) for Docker Hardened Images
- [Policies](https://github.com/docker-hardened-images/policies): Rego source
  for the Docker Scout policies used to enforce DHI security and compliance
  standards
- [dhictl](https://github.com/docker-hardened-images/dhictl): Command-line
  interface for managing and interacting with Docker Hardened Images
- [Terraform Provider](https://github.com/docker-hardened-images/terraform-provider-dhi):
  Terraform provider for managing DHI resources
  ([Terraform Registry](https://registry.terraform.io/providers/docker-hardened-images/dhi/latest/docs))

## Additional resources

- [Start a free trial](https://hub.docker.com/hardened-images/start-free-trial):
  Explore DHI Select and Enterprise features including FIPS/STIG variants, customization,
  and SLA-backed support
- [Support Service Level Agreement](https://docs.docker.com/go/dhi-sla/):
  Review the SLA commitments for DHI Select and Enterprise subscriptions
- [Request a demo](https://www.docker.com/products/hardened-images/#getstarted): Get a
  personalized demo and information about DHI Select and Enterprise subscriptions
- [Request an image](https://github.com/docker-hardened-images/catalog/issues):
  Submit a request for a specific Docker Hardened Image
- [Debian package index](https://dhi.io/deb/debian/main/index.html):
  Browse hardened Debian packages in Docker's public repository
- [Alpine package index](https://dhi.io/apk/alpine/v3.24/main/index.html):
  Browse hardened Alpine packages in Docker's public repository
- <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_dhi_resources" class="link" rel="noopener">Contact Sales</a>: Connect with
  Docker sales team for enterprise inquiries
- [Docker Support](https://www.docker.com/support/): Access support resources
  for DHI Select and Enterprise customers

## Feedback and community

Use the [GitHub Discussions board](https://github.com/orgs/docker-hardened-images/discussions)
to engage with the DHI team for general questions, best practices, security
tips, and community announcements.

To report a bug, request a feature, or suggest a documentation improvement,
[open an issue](https://github.com/docker-hardened-images/catalog/issues) in
the catalog repository.

## Security disclosure

Do not post details of vulnerabilities before coordinated disclosure and
resolution. If you discover a security vulnerability, report it responsibly
by following Docker's [security disclosure
policy](https://www.docker.com/trust/vulnerability-disclosure-policy/).


---

# Tools

*Sección: Dhi*

Docker Hardened Images can be accessed and managed through several interfaces.
Choose the tool that fits your workflow.

{{< grid items="grid_tools" >}}


---

# Use the DHI API

*Sección: Dhi*

The DHI API is a GraphQL API for querying Docker Hardened Images data
programmatically, for use cases like building automation or dashboards on
top of DHI data.

## Endpoint

Send requests as `POST` requests to:

```text
https://api.dso.docker.com/v1/graphql
```

## Request format

The API accepts standard GraphQL requests: a JSON body with a `query` and,
optionally, `variables`.

```console
$ curl https://api.dso.docker.com/v1/graphql \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"query": "...", "variables": { ... }}'
```

Every query takes a `Context` argument (conventionally named `ctx` in the
`variables` object) alongside its query-specific arguments:

| Argument | Type | Required | Description |
|---|---|---|---|
| `ctx` | `Context` | Yes | Scopes the request to an organization. |
| `ctx.organization` | `String` | Yes | The Docker organization the token belongs to. |

## Authentication

An [organization access token](../../security/access-tokens/organization-access-tokens.md)
(OAT) or personal access token (PAT) isn't used directly as the bearer
token. Exchange it first for an access token:

```console
$ curl -X POST https://hub.docker.com/v2/auth/token \
  -H "Content-Type: application/json" \
  -d '{"identifier": "<identifier>", "secret": "<token>"}'
```

For `identifier`, use your Docker Hub username with a PAT, or the
organization name with an OAT. The response contains the access token:

```json
{ "access_token": "..." }
```

Pass that `access_token` as `Authorization: Bearer <access_token>`. Also set
`ctx.organization` in `variables` to the organization the token belongs to
(see [Request format](#request-format)).

## Response format

Responses follow the standard GraphQL envelope:

| Key | Description |
|---|---|
| `data` | The requested fields. A field is `null` if it couldn't be resolved, for example due to an authorization failure. |
| `errors` | Present when a field failed to resolve. Includes a `message` and a `path` identifying which field failed. |
| `extensions` | Metadata such as a `correlation_id`, useful when reporting an issue. |

For example, an unauthenticated request, or a request for data your token
can't access, returns a `null` result under `data` alongside an authorization
error in `errors`, rather than an HTTP-level failure:

```json
{
  "errors": [
    {
      "message": "You are not allowed to read data for this team",
      "path": ["someQuery"],
      "extensions": { "code": "DOWNSTREAM_SERVICE_ERROR", "status": 403 }
    }
  ],
  "data": { "someQuery": null },
  "extensions": { "correlation_id": "..." }
}
```

## Queries

### `imagePackagesForImageCoords`

Fetches every package in an image, every CVE reported against it, and
whether Docker suppresses that CVE, by digest. See [Query VEX for a Docker
Hardened Image](../how-to/vex-api.md) for a guided example.

| Argument | Type | Required | Description |
|---|---|---|---|
| `digest` | `String` | Yes | The image's platform manifest digest, not the multi-arch index digest. |
| `hostName` | `String` | Yes | `hub.docker.com` or `docker.io`. |
| `repoName` | `String` | Yes | Repository name, with or without the namespace prefix. |
| `includeExcepted` | `Boolean` | No | Include suppressed CVEs in the response alongside the reason for suppression. Without it, the response only shows the netted list, with no visibility into what was suppressed. |
| `includeNodsa` | `Boolean` | No | Include Debian NODSA exclusions, which make up most suppressions on a Debian-based image. |
| `includePublic` | `Boolean` | No | Also include public images when `ctx.organization` scopes the request to an organization. Not needed for a typical lookup. |

Keep the requested response fields limited to what you plan to render.
Fields such as `locations`, `description`, `vulnerableRange`, and `epss`
increase response size substantially and aren't needed for a CVE-count or
suppressed-CVE view.

#### Response fields

`vulnerabilityExceptions` only contains records that actually suppress a
CVE, so it always lines up with `isExcepted`: an empty array means the CVE
is live. Use `isExcepted` as your filter for "is this CVE suppressed."

| Field | Meaning |
|---|---|
| `isExcepted` | Docker suppresses this CVE for this image. Use this to filter. |
| `sourceType` | `EXTERNAL` (Debian NODSA), `MANUAL_EXCEPTION` (Docker analyst exception), or `VEX_STATEMENT` (an ingested VEX document). |
| `type` | `FALSE_POSITIVE` and `ACCEPTED_RISK` suppress the CVE. `UNDER_INVESTIGATION` and `AFFECTED` don't. |
| `justification` | The OpenVEX justification value. Always `null` for NODSA exclusions. |
| `additionalDetails` | Free-text rationale for the suppression. |
| `isDhiStatement` | Whether the statement is inherited from the DHI base image. |
| `id` | Stable identifier for the statement. |

#### Mapping to OpenVEX

If your pipeline consumes OpenVEX documents (for example, Trivy's `--vex`
flag), each suppressed record maps as follows:

| OpenVEX field | Source |
|---|---|
| `vulnerability.name` | `sourceId` |
| `products[].@id` | The parent package's `purl` |
| `status` | `not_affected` (from `type: FALSE_POSITIVE`) |
| `justification` | `justification`, defaulting to `vulnerable_code_cannot_be_controlled_by_adversary` for NODSA exclusions |
| `status_notes` | `additionalDetails` |
| `@id` | `id` |


---

# Use the DHI CLI

*Sección: Dhi*

The `docker dhi` command-line interface (CLI) is a tool for managing Docker Hardened Images:
- Browse the catalog of available DHI images and their metadata
- View attestations for DHI images, including SBOMs and provenance
- Mirror DHI images to your Docker Hub organization
- Create and manage customizations of DHI images
- Generate authentication for enterprise package repositories
- Monitor customization builds

## Installation

The `docker dhi` CLI is available in [Docker Desktop](https://docs.docker.com/desktop/) version 4.65 and later.
You can also install the standalone `dhictl` binary.

### Docker Desktop

The `docker dhi` command is included in Docker Desktop 4.65 and later. No additional installation is required.

### Standalone binary

1. Download the `dhictl` binary for your platform from the
   [releases](https://github.com/docker-hardened-images/dhictl/releases) page.
2. Move it to a directory in your `PATH`:
    - `mv dhictl /usr/local/bin/` on _Linux_ and _macOS_
    - Move `dhictl.exe` to a directory in your `PATH` on _Windows_

## Usage

Every command has built-in help accessible with the `--help` flag:

```console
$ docker dhi --help
$ docker dhi catalog list --help
```

### Browse the DHI catalog

List all available DHI images:

```console
$ docker dhi catalog list
```

Filter by type, name, or compliance:

```console
$ docker dhi catalog list --type image
$ docker dhi catalog list --filter golang
$ docker dhi catalog list --fips
$ docker dhi catalog list --stig
```

Get details of a specific image, including available tags and CVE counts:

```console
$ docker dhi catalog get <image-name>
```

### View attestations

List all attestations attached to a DHI image:

```console
$ docker dhi attestation list dhi/nginx:1.27
$ docker dhi attestation list dhi/nginx:1.27 --platform linux/amd64
$ docker dhi attestation list dhi/nginx:1.27 --predicate-type https://slsa.dev/provenance/v1
$ docker dhi attestation list dhi/nginx:1.27 --json
```

Get a specific attestation by its referrer digest:

```console
$ docker dhi attestation get dhi/nginx:1.27 sha256:<digest>
$ docker dhi attestation get dhi/nginx:1.27 sha256:<digest> -o provenance.json
```

Display the SPDX SBOM for an image:

```console
$ docker dhi attestation sbom dhi/nginx:1.27
$ docker dhi attestation sbom dhi/nginx:1.27 --platform linux/amd64
```

### Mirror DHI images

{{< summary-bar feature_name="Docker Hardened Images" >}}

Start mirroring one or more DHI images to your Docker Hub organization:

```console
$ docker dhi mirror start --org my-org \
  dhi/golang,my-org/dhi-golang \
  dhi/nginx,my-org/dhi-nginx \
  dhi/prometheus-chart,my-org/dhi-prometheus-chart
```

Mirror with dependencies:

```console
$ docker dhi mirror start --org my-org dhi/golang,my-org/dhi-golang --dependencies
```

List mirrored images in your organization:

```console
$ docker dhi mirror list --org my-org
```

Filter mirrored images by name or type:

```console
$ docker dhi mirror list --org my-org --filter python
$ docker dhi mirror list --org my-org --type image
$ docker dhi mirror list --org my-org --type helm-chart
```

Stop mirroring one or more images:

```console
$ docker dhi mirror stop dhi-golang --org my-org
$ docker dhi mirror stop dhi-python dhi-golang --org my-org
```

Stop mirroring and delete the repositories:

```console
$ docker dhi mirror stop dhi-golang --org my-org --delete
$ docker dhi mirror stop dhi-golang --org my-org --delete --force
```

### Customize DHI images

{{< summary-bar feature_name="Docker Hardened Images" >}}

The CLI can be used to create and manage DHI image customizations. For detailed
instructions on creating customizations using the GUI, see [Customize a Docker
Hardened Image](../how-to/customize.md).

The following is a quick reference for CLI commands. For complete details on all
options and flags, see the
[CLI reference](/reference/cli/docker/dhi/).

```console
# Prepare a single customization scaffold
$ docker dhi customization prepare golang 1.25 \
  --org my-org \
  --destination my-org/dhi-golang \
  --name "golang with git" \
  > my-customization.yaml

# Prepare a bulk customization scaffold (pipe JSON array via stdin)
$ echo '[{"destination":"my-org/dhi-golang","tag-definition-id":"golang/alpine-3.23/1.24-dev"}]' \
  | docker dhi customization prepare --name "golang with git" --org my-org \
  > my-customization.yaml

# Create a customization
$ docker dhi customization create my-customization.yaml --org my-org

# Create with flag overrides (flags take precedence over the YAML file)
$ docker dhi customization create my-customization.yaml --org my-org \
  --destination my-org/dhi-golang \
  --name "golang with git"

# List customizations
$ docker dhi customization list --org my-org

# Filter customizations by name, repository, or source
$ docker dhi customization list --org my-org --filter git
$ docker dhi customization list --org my-org --repo dhi-golang
$ docker dhi customization list --org my-org --source golang

# Get a customization by ID
$ docker dhi customization get <id> --org my-org

# Update a customization
# The YAML file must include the 'id' field to identify the customization to update
$ docker dhi customization edit my-customization.yaml --org my-org

# Delete a customization by ID
$ docker dhi customization delete <id> --org my-org

# Delete multiple customizations
$ docker dhi customization delete <id1> <id2> --org my-org

# Delete without confirmation prompt
$ docker dhi customization delete <id> --org my-org --force
```

For a complete reference of all YAML fields, see
[Image customization YAML file](/dhi/how-to/customize/#image-customization-yaml-file).

### Enterprise package authentication

{{< summary-bar feature_name="Docker Hardened Images Enterprise" >}}

Generate authentication credentials for accessing the enterprise hardened
package repository. These credentials are used when configuring your package
manager to install compliance and security-patched packages in your own images. For detailed
instructions, see [Enterprise
repository](../how-to/hardened-packages.md#enterprise-repository).

For Alpine-based images:

```console
$ docker dhi auth apk
```

For Debian-based images:

```console
$ docker dhi auth deb
```

### Monitor customization builds

{{< summary-bar feature_name="Docker Hardened Images" >}}

List builds for a customization:

```console
$ docker dhi customization build list <customization-id> --org my-org
$ docker dhi customization build list <customization-id> --org my-org --json
```

Get details of a specific build:

```console
$ docker dhi customization build get <customization-id> <build-id> --org my-org
$ docker dhi customization build get <customization-id> <build-id> --org my-org --json
```

View build logs:

```console
$ docker dhi customization build logs <customization-id> <build-id> --org my-org
$ docker dhi customization build logs <customization-id> <build-id> --org my-org --json
```

### JSON output

Most list and get commands support a `--json` flag for machine-readable output:

```console
$ docker dhi catalog list --json
$ docker dhi catalog get golang --json
$ docker dhi attestation list dhi/nginx:1.27 --json
$ docker dhi mirror list --org my-org --json
$ docker dhi mirror start --org my-org dhi/golang,my-org/dhi-golang --json
$ docker dhi customization list --org my-org --json
$ docker dhi customization build list <customization-id> --org my-org --json
```

## Configuration

The `docker dhi` CLI can be configured with a YAML file located at:
- `$HOME/.config/dhictl/config.yaml` on _Linux_ and _macOS_
- `%USERPROFILE%\.config\dhictl\config.yaml` on _Windows_

If `$XDG_CONFIG_HOME` is set, the configuration file is located at `$XDG_CONFIG_HOME/dhictl/config.yaml`.

Available configuration options:

| Option      | Environment Variable | Description                                                                                                               |
|-------------|----------------------|---------------------------------------------------------------------------------------------------------------------------|
| `org`       | `DHI_ORG`            | Default Docker Hub organization for mirror and customization commands.                                                    |
| `api_token` | `DHI_API_TOKEN`      | Docker token for authentication. You can generate a token in your [Docker Hub account settings](https://hub.docker.com/). |

Environment variables take precedence over configuration file values.


---

# Use Docker Hub

*Sección: Dhi*

The [Docker Hardened Images catalog](https://hub.docker.com/hardened-images/catalog)
on Docker Hub is the primary web interface for browsing, searching, and inspecting
DHI repositories and their metadata.

## Catalog page

The catalog lists all available DHI repositories. You can filter by name,
image type, or compliance requirements (FIPS, STIG) to find the image you need.

## Repository details page

When you select a repository from the catalog, the repository details page
provides the following:

- Overview: A brief explanation of the image.
- Guides: Several guides on how to use the image and migrate your existing application.
- Images: Select this option to [view image variants](#images-page).
- Security summary: Select a tag name to view a quick security summary,
  including package count and total known vulnerabilities.
- Recently pushed tags: A list of recently updated image variants and when they
  were last updated.
- Use this image: After selecting an image variant, you can select this option to
  view instructions on how to pull and use the image variant, or select **Mirror
  repository** to mirror it to your organization.

## Images page

From the repository details page, select **Images** to see all available image
variants for that repository. The table includes:

- Image version: The image name with its base distribution (for example, `debian
  13`) and associated tags.
- Type: The support lifecycle status of the variant.
- Compliance: Relevant compliance designations, for example `CIS`, `FIPS`, or
  `STIG (100%)`.
- Package manager: Whether a package manager is available. A checkmark indicates
  a package manager is present (for example, `apt` or `apk`), a dash indicates
  none.
- Shell: Whether a shell is available. A checkmark indicates a shell is present
  (for example, `bash` or `busybox`), a dash indicates none.
- User: The user that the container runs as, for example `root` or `nonroot
  (65532)`.
- Last pushed: When the image variant was last updated.
- Vulnerabilities: Vulnerability counts by severity level.

## Image variant details page

Select an image version from the Images table to view detailed information about
that specific variant:

- Packages: A list of all packages included in the image variant, with each
  package's name, version, distribution, and licensing information.
- Specifications:
  - Source and build information: The Dockerfile and Git commit used to build the image.
  - Build parameters, entrypoint, CMD, user, working directory, environment
    variables, labels, and platform.
- Vulnerabilities: A list of known CVEs for the image variant, including CVE ID,
  severity, affected package, fix version, last detected date, status, and
  suppressed CVEs.
- Attestations: Signed security attestations covering the image's build process,
  contents, and security posture. For the full list, see
  [Attestations](/dhi/explore/security-concepts/attestations/).

## Manage page

The Manage page (**My Hub** > **Hardened Images** > **Manage**) is the central
place for administering your organization's mirrored DHI repositories. It has
two tabs:

- Mirrored Images: Lists all image repositories currently mirrored to your
  organization, with their source DHI repository, destination repository name,
  and mirroring status. From here you can stop mirroring or open a repository's
  settings.
- Mirrored Helm charts: The same view for Helm chart repositories.

Selecting a mirrored repository opens its settings, where you can enable or
disable Extended Lifecycle Support (ELS) and access customizations.

For step-by-step instructions, see [Mirror a Docker Hardened Image
repository](/dhi/how-to/mirror/).

## Customizations

Customizations are accessible from **My Hub** > **Hardened Images** > **Manage** > **Mirrored Images**.
Select the menu icon next to a mirrored repository and
then **Customize**. Each customization defines
additional packages, OCI artifacts, environment variables, or labels to layer
onto the base DHI during a rebuild.

The customizations view shows each customization's name, status, and last build
time. Selecting a customization opens its configuration, where you can edit the
definition, trigger a rebuild, or delete it.

For step-by-step instructions, see [Customize a Docker Hardened
Image](/dhi/how-to/customize/).


---

# Use the DHI MCP server

*Sección: Dhi*

The Docker Hardened Images (DHI) MCP server exposes the DHI catalog through the
Model Context Protocol (MCP), letting you query repositories, inspect image
metadata, retrieve SBOMs, and check CVEs directly from your AI assistant in
plain language.

The MCP server is:

- Remote. No local binary to install. Your AI assistant connects directly to
  `https://dhi.io/mcp`.
- Compatible with any MCP-capable AI assistant, including Claude,
  Cursor, and others.

Most tools are public and require no credentials. The mirror management tools
(`dhi_list_mirrors`, `dhi_create_mirror`, `dhi_remove_mirror`) require a Docker
Hub username and personal access token (PAT) with owner access to the target
organization. Credentials are passed as an HTTP Basic auth header in the MCP
client configuration — they are never passed as tool arguments.

## Connect your AI assistant

Configuration varies by client. Select the tab for your AI assistant.

{{< tabs >}}
{{< tab name="Claude Desktop" >}}

Add the following to your Claude Desktop configuration file:

```json
{
  "mcpServers": {
    "dhi": {
      "url": "https://dhi.io/mcp"
    }
  }
}
```

The configuration file is located at:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`

{{< /tab >}}
{{< tab name="Cursor" >}}

Add the following to `.cursor/mcp.json` in your project, or
`~/.cursor/mcp.json` globally:

```json
{
  "mcpServers": {
    "dhi": {
      "url": "https://dhi.io/mcp"
    }
  }
}
```

{{< /tab >}}
{{< tab name="Claude Code" >}}

Run the following command to add the DHI MCP server:

```console
$ claude mcp add dhi --url https://dhi.io/mcp
```

Or add it manually to `.claude/mcp.json` in your project:

```json
{
  "mcpServers": {
    "dhi": {
      "url": "https://dhi.io/mcp"
    }
  }
}
```

{{< /tab >}}
{{< tab name="Docker Agent" >}}

In your [Docker Agent](../../ai/docker-agent/index.md) YAML configuration, add the
DHI MCP server as a remote toolset:

```yaml
toolsets:
  - type: mcp
    remote:
      url: "https://dhi.io/mcp"
      transport_type: streamable
```

For example, to create an agent that can answer questions about the DHI catalog:

```yaml
agents:
  root:
    model: anthropic/claude-sonnet-4-5
    description: DHI catalog assistant
    instruction: |
      Help me find and evaluate Docker Hardened Images.
      Search the DHI catalog, inspect image details, check CVEs,
      and retrieve SBOMs and attestations as needed.
    toolsets:
      - type: mcp
        remote:
          url: "https://dhi.io/mcp"
          transport_type: streamable
```

Run the agent with:

```console
$ docker agent run dhi-agent.yaml
```

{{< /tab >}}
{{< /tabs >}}

## Available tools

The DHI MCP server provides ten tools that your AI assistant calls automatically
based on what you ask:

| Tool | What it does |
|------|-------------|
| `dhi_list_repositories` | Search and filter the DHI catalog by name, type, category, FIPS, or STIG compliance |
| `dhi_get_repository` | Get full details for a repository: tag definitions, build config, platforms, and per-manifest vulnerability counts |
| `dhi_get_tag_definition` | Get the deep view of a single tag definition |
| `dhi_get_image_details` | Get per-digest details: tags, platform, size, layer and package counts, vulnerability severity counts, and attestation types |
| `dhi_get_image_packages` | Retrieve the full software bill of materials (SBOM): package name, version, type, purl, licenses, and file locations |
| `dhi_get_image_cves` | List CVEs with severity, CVSS score, fix version, EPSS score, and CISA-exploited flag; filter by minimum severity or fixable-only |
| `dhi_get_image_attestations` | List SBOM, provenance, signature, and other attestations for a specific image digest |
| `dhi_list_mirrors` | List mirrored DHI repositories for a Docker Hub organization — requires authentication |
| `dhi_create_mirror` | Start mirroring a DHI repository into a Docker Hub organization — requires authentication |
| `dhi_remove_mirror` | Stop mirroring a repository by its mirror ID — requires authentication |

## Authenticate for mirror tools

The mirror tools require a Docker Hub username and [personal access token
(PAT)](/security/access-tokens/personal-access-tokens/) with owner access to the target organization,
passed as an HTTP Basic auth header. Generate the value with:

```console
$ printf 'USERNAME:dckr_pat_...' | base64 | tr -d '\n'
```

Then add it to your MCP client configuration:

> [!WARNING]
> Base64 encoding is not encryption. The value in your configuration file
> is effectively a plaintext password. Do not commit this file to version
> control or share it.

```json
{
  "mcpServers": {
    "dhi": {
      "url": "https://dhi.io/mcp",
      "headers": {
        "Authorization": "Basic <base64-value>"
      }
    }
  }
}
```

Without credentials, the read-only catalog tools work normally and the mirror
tools return an authentication error.

## What the tools return

Each tool returns structured data that your AI assistant can summarize,
compare, or act on:

- `dhi_list_repositories` returns a list of repositories with display
  name, distributions, platforms, FIPS/STIG flags, included tools, and category.
- `dhi_get_repository` returns the full repository record, including all tag
  definitions with their tags, build configuration, image indexes, and
  per-platform manifest digests with vulnerability counts.
- `dhi_get_tag_definition` returns tags, build parameters, entrypoint,
  environment variables, run-as user, and per-platform manifests for a single
  tag definition.
- `dhi_get_image_details` returns the image platform, compressed size, layer
  count, package count, vulnerability severity counts by level, labels, and
  a list of attestation predicate types.
- `dhi_get_image_packages` returns each package in the image with its name,
  version, type (`deb`, `rpm`, `apk`, etc.), purl, licenses, and the file paths where
  it was found.
- `dhi_get_image_cves` returns each CVE affecting the image with its
  severity, CVSS score and vector, affected package, fix version (if any), EPSS
  probability score, and a flag indicating whether CISA lists it as
  actively exploited.
- `dhi_get_image_attestations` returns the predicate type and OCI reference
  for each attestation attached to the image digest.
- `dhi_list_mirrors` returns each mirror's ID, source DHI repository,
  destination repository, and mirroring status for the given organization.
- `dhi_create_mirror` starts mirroring a DHI source repository into the
  specified organization and destination repository name.
- `dhi_remove_mirror` stops mirroring for the given mirror ID. It does not
  delete the destination repository — only stops new images from being synced.


---

# Use the DHI Terraform provider

*Sección: Dhi*

The [DHI Terraform provider](https://registry.terraform.io/providers/docker-hardened-images/dhi/latest/docs)
lets you manage Docker Hardened Image mirrors and customizations as
infrastructure as code.

## Install and configure the provider

Add the provider to your Terraform configuration:

```hcl
terraform {
  required_providers {
    dhi = {
      source = "docker-hardened-images/dhi"
    }
  }
}

provider "dhi" {
  docker_hub_username = var.docker_username
  docker_hub_password = var.docker_password
  organization        = var.org_name
}
```

Instead of specifying credentials in the provider block, you can set environment
variables:

| Variable | Description |
|----------|-------------|
| `DOCKER_USERNAME` | Docker Hub username or organization namespace |
| `DOCKER_PASSWORD` | Docker Hub password or personal/organization access token |
| `DHI_ORG` | Target organization namespace |

You can authenticate using a personal access token (PAT) or an organization
access token (OAT) in place of a password. When using an OAT, permission scopes
apply:

- Read (pull) access is required to list mirrors.
- Push access is required to create or delete mirrors.

## Resources

### `dhi_mirror`

Manages a mirrored DHI repository in your organization. See [Mirror a Docker
Hardened Image repository](/dhi/how-to/mirror/) for task-based examples.

For the full list of resource attributes, see the [Terraform Registry
documentation](https://registry.terraform.io/providers/docker-hardened-images/dhi/latest/docs/resources/mirror).

### `dhi_customization`

Manages image customizations applied to a mirrored repository. See [Customize a
Docker Hardened Image](/dhi/how-to/customize/) for task-based examples.

For the full list of resource attributes, see the [Terraform Registry
documentation](https://registry.terraform.io/providers/docker-hardened-images/dhi/latest/docs/resources/customization).


---

# Docker Hub

*Sección: Docker Hub*

Docker Hub simplifies development with the world's largest container registry
for storing, managing, and sharing Docker images. By integrating seamlessly with
your tools, it enhances productivity and ensures reliable deployment,
distribution, and access to containerized applications. It also provides
developers with pre-built images and assets to speed up development workflows.

Key features of Docker Hub:

* Unlimited public repositories
* Private repositories
* Webhooks to automate workflows
* GitHub and Bitbucket integrations
* Concurrent and automated builds
* Trusted content featuring high-quality, secure images

In addition to the graphical interface, you can interact with Docker Hub using
the [Docker Hub API](../reference/api/hub/latest.md), the experimental [Docker
Hub CLI tool](https://github.com/docker/hub-tool#readme), or the [Docker Hub
MCP server](/docker-hub/mcp-server/) for AI agent integrations.

{{< grid >}}


---

# Content library

*Sección: Docker Hub*

Docker Hub's content library is the world's largest collection of
container images, extensions, and plugins. It provides a central location to
discover pre-built images and tools designed to streamline your container
workflows, making it easier to share and collaborate.

In this section, learn about:

- [Search](search.md): Discover how to browse and search Docker Hub's extensive resources.
- [Trusted content](trusted-content.md): Dive into Docker Hardened Images,
  Docker Official Images, Verified Publisher content, and Docker-Sponsored Open
  Source Software images, all vetted for security and reliability to streamline
  your workflows.
- [Generative AI](catalogs.md): Explore Docker Hub's generative AI catalogs
  and sandbox kits.
- [Mirroring](mirror.md): Learn how to create a mirror of Docker Hub's
  container image library as a pull-through cache.


---

# Generative AI content

*Sección: Docker Hub*

Docker Hub groups its generative AI content, including curated catalogs and
sandbox kits, under Generative AI. Catalogs are your go-to collections of
trusted, ready-to-use container images and resources, tailored to meet
specific development needs. They make it easier to find high-quality,
pre-verified content so you can quickly build, deploy, and manage your
applications with confidence. Catalogs in Docker Hub:

- Simplify content discovery: Organized and curated content makes it easy to
  discover tools and resources tailored to your specific domain or technology.
- Reduce complexity: Trusted resources, vetted by Docker and its partners,
  ensure security, reliability, and adherence to best practices.
- Accelerate development: Quickly integrate advanced capabilities into your
  applications without the hassle of extensive research or setup.

The following sections provide an overview of the generative AI content
available in Docker Hub.

## MCP Catalog

The [MCP Catalog](https://hub.docker.com/mcp/) is a centralized, trusted
registry for discovering, sharing, and running Model Context Protocol
(MCP)-compatible tools. Seamlessly integrated into Docker Hub, the catalog
includes:

- Over 100 verified MCP servers packaged as Docker images
- Tools from partners such as New Relic, Stripe, and Grafana
- Versioned releases with publisher verification
- Simplified pull-and-run support through Docker Desktop and Docker CLI

Each server runs in an isolated container to ensure consistent behavior and
minimize configuration headaches. For developers working with Claude Desktop or
other MCP clients, the catalog provides an easy way to extend functionality with
drop-in tools.

To learn more about MCP servers, see [MCP Catalog and Toolkit](../../ai/mcp-catalog-and-toolkit/index.md).

## AI Models Catalog

The [AI Models Catalog](https://hub.docker.com/catalogs/models/) provides
curated, trusted models that work with [Docker Model
Runner](../../ai/model-runner/index.md). This catalog is designed to make AI
development more accessible by offering pre-packaged, ready-to-use models that
you can pull, run, and interact with using familiar Docker tools.

With the AI Models Catalog and Docker Model Runner, you can:

- Pull and serve models from Docker Hub or any OCI-compliant registry
- Interact with models via OpenAI-compatible APIs
- Run and test models locally using Docker Desktop or CLI
- Package and publish models using the `docker model` CLI

Whether you're building generative AI applications, integrating LLMs into your
workflows, or experimenting with machine learning tools, the AI Models Catalog
simplifies the model management experience.

## Sandbox kits

[Sandbox kits](https://hub.docker.com/search?type=sbx_kit) package what an AI
coding agent needs to run in a [Docker Sandbox](../../ai/sandboxes/index.md):
its image, tools, credentials, network rules, and startup commands.

Each kit's Hub page shows the command to run it, in the form
`sbx run <agent> --kit docker.io/<namespace>/<kit-name>`. To learn more about
building and running kits, see [Kits](../../ai/sandboxes/customize/kits.md).


---

# Mirror the Docker Hub library

*Sección: Docker Hub*

## Use-case

If you have multiple instances of Docker running in your environment, such as
multiple physical or virtual machines all running Docker, each daemon goes out
to the internet and fetches an image it doesn't have locally, from the Docker
repository. You can run a local registry mirror and point all your daemons
there, to avoid this extra internet traffic.

> [!NOTE]
>
> Docker Official Images are an intellectual property of Docker.

### Alternatives

Alternatively, if the set of images you are using is well delimited, you can
simply pull them manually and push them to a simple, local, private registry.

Furthermore, if your images are all built in-house, not using the Hub at all and
relying entirely on your local registry is the simplest scenario.

### Gotcha

It's currently not possible to mirror another private registry. Only the central
Hub can be mirrored.

> [!NOTE]
>
> Mirrors of Docker Hub are still subject to Docker's [fair use policy](../usage/index.md#fair-use).

### Solution

The Registry can be configured as a pull through cache. In this mode a Registry
responds to all normal docker pull requests but stores all content locally.

### Using Registry Access Management (RAM) with a registry mirror

If Docker Hub access is restricted via your Registry Access Management (RAM) configuration, you will not be able to pull images originating from Docker Hub even if the images are available in your registry mirror.

You will encounter the following error:
```console
Error response from daemon: Access to docker.io has been restricted by your administrators.
```

If you are unable to allow access to Docker Hub, you can manually pull from your registry mirror and optionally, retag the image. For example:
```console
docker pull <your-registry-mirror>[:<port>]/library/busybox
docker tag <your-registry-mirror>[:<port>]/library/busybox:latest busybox:latest
```

## How does it work?

The first time you request an image from your local registry mirror, it pulls
the image from the public Docker registry and stores it locally before handing
it back to you. On subsequent requests, the local registry mirror is able to
serve the image from its own storage.

### What if the content changes on the Hub?

When a pull is attempted with a tag, the Registry checks the remote to
ensure if it has the latest version of the requested content. Otherwise, it
fetches and caches the latest content.

### What about my disk?

In environments with high churn rates, stale data can build up in the cache.
When running as a pull through cache the Registry periodically removes old
content to save disk space. Subsequent requests for removed content causes a
remote fetch and local re-caching.

To ensure best performance and guarantee correctness the Registry cache should
be configured to use the `filesystem` driver for storage.

## Run a Registry as a pull-through cache

The easiest way to run a registry as a pull through cache is to run the official
[Registry](https://hub.docker.com/_/registry) image.
At least, you need to specify `proxy.remoteurl` within `/etc/docker/registry/config.yml`
as described in the following subsection.

Multiple registry caches can be deployed over the same back-end. A single
registry cache ensures that concurrent requests do not pull duplicate data,
but this property does not hold true for a registry cache cluster.

### Configure the cache

To configure a Registry to run as a pull through cache, the addition of a
`proxy` section is required to the config file.

To access private images on the Docker Hub, a username and password can
be supplied.

```yaml
proxy:
  remoteurl: https://registry-1.docker.io
  username: [username]
  password: [password]
```

> [!WARNING]
>
> If you specify a username and password, it's very important to understand that
> private resources that this user has access to Docker Hub is made available on
> your mirror. You must secure your mirror by implementing authentication if
> you expect these resources to stay private!

> [!WARNING]
>
> For the scheduler to clean up old entries, `delete` must be enabled in the
> registry configuration.

### Configure the Docker daemon

Either pass the `--registry-mirror` option when starting `dockerd` manually,
or edit [`/etc/docker/daemon.json`](/reference/cli/dockerd.md#daemon-configuration-file)
and add the `registry-mirrors` key and value, to make the change persistent.

```json
{
  "registry-mirrors": ["https://<my-docker-mirror-host>"]
}
```

Save the file and reload Docker for the change to take effect.

> [!NOTE]
>
> Some log messages that appear to be errors are actually informational
> messages.
>
> Check the `level` field to determine whether the message is warning you about
> an error or is giving you information. For example, this log message is
> informational:
>
> ```text
> time="2017-06-02T15:47:37Z" level=info msg="error statting local store, serving from upstream: unknown blob" go.version=go1.7.4
> ```
>
> It's telling you that the file doesn't exist yet in the local cache and is
> being pulled from upstream.


---

# Docker Hub search

*Sección: Docker Hub*

The [Docker Hub search interface](https://hub.docker.com/search) lets you
explore millions of resources. To help you find exactly what you need, it offers
a variety of filters that let you narrow your results or discover different
types of content.

## Filters

The search functionality includes filters to narrow down
results based on your requirements, such as products, categories, trusted
content, and publishers. This ensures that you can quickly find and access the resources best
suited to your project.

### Products

Docker Hub's content library features various products, each designed to meet
specific needs of developers and organizations. These products include:

- Images
- Extensions
- Sandbox kits
- Helm charts
- Compose files
- AI models
- Docker Engine plugins

#### Images

Docker Hub hosts millions of container images, making it the go-to repository
for containerized applications and solutions. These images include:

- Operating system images: Foundational images for Linux distributions like
  Ubuntu, Debian, and Alpine, or Windows Server images.
- Database and storage images: Pre-configured databases such as MySQL,
  PostgreSQL, and MongoDB to simplify application development.
- Languages and frameworks-based images: Popular images for Java, Python,
  Node.js, Ruby, .NET, and more, offering pre-built environments for faster
  development.

Images in Docker Hub simplify the development process by providing pre-built,
reusable building blocks, reducing the need to start from scratch. Whether
you're a beginner building your first container or an enterprise managing
complex architectures, Docker Hub images provide a reliable foundation.

#### Extensions

Docker Hub offers extensions for Docker Desktop, which enhance its core
functionality. These extensions are purpose-built to streamline the software
development lifecycle. Extensions provide tools for:

- System optimization and monitoring: Manage resources and optimize Docker
  Desktop’s performance.
- Container management: Simplify container deployment and monitoring.
- Database management: Facilitate efficient database operations within
  containers.
- Kubernetes and cloud integration: Bridge local environments with cloud-native
  and Kubernetes workflows.
- Visualization tools: Gain insights into container resource usage through
  graphical representations.

Extensions help developers and teams create a more efficient and unified
workflow by reducing context switching and bringing essential tools into Docker
Desktop's interface.

To learn more about extensions, see [Docker
Extensions](../../extensions/index.md).

#### Sandbox kits

Docker Hub hosts kits for [Docker Sandboxes](../../ai/sandboxes/index.md),
which run AI coding agents in isolated microVM sandboxes. A kit packages what
an agent needs to run in a sandbox, such as its image, tools, credentials,
network rules, and startup commands. Sandbox kits come in two kinds:

- Sandbox: Defines a full agent from scratch, including its image and
  entrypoint.
- Mixin: Layers tools, credentials, or configuration onto an existing agent.

To learn more about building and running kits, see
[Kits](../../ai/sandboxes/customize/kits.md).

#### Helm charts

Helm charts in Docker Hub provide a streamlined way to package, configure, and
deploy Kubernetes applications. Helm is the package manager for Kubernetes, and
charts are pre-configured templates that define the resources needed to run an
application in a Kubernetes cluster. Docker Hub hosts a variety of Helm charts
that provide:

- Application packaging: Bundle Kubernetes manifests, configurations, and
  dependencies into a single, reusable chart.
- Version management: Track and manage different versions of your application
  deployments.
- Configuration templating: Customize deployments with values files, making it
  easy to deploy the same application across different environments.
- Dependency management: Automatically handle chart dependencies, ensuring all
  required components are deployed together.

Helm charts reduce the complexity of Kubernetes deployments, making it easier
for teams to deploy, upgrade, and manage applications in production
environments.

#### Compose

Docker Compose files in Docker Hub enable multi-container application
orchestration through simple YAML configuration files. Compose is a tool for
defining and running multi-container Docker applications, and Docker Hub hosts
Compose files that help you:

- Multi-container orchestration: Define and run applications consisting of
  multiple interconnected containers with a single command.
- Service configuration: Specify container images, environment variables,
  networks, volumes, and dependencies in a declarative format.
- Development and testing: Quickly spin up complete application stacks for local
  development, testing, or demonstration purposes.
- Environment consistency: Ensure consistent application behavior across
  development, staging, and production environments.

Compose files simplify the process of managing complex applications by
providing a clear, version-controlled definition of your entire application
stack.

#### AI models

Docker Hub hosts AI and machine learning models in containerized formats,
making it easier to deploy, share, and run AI applications across different
environments. These containerized AI models provide:

- Pre-trained models: Access ready-to-use machine learning models for common
  tasks such as image recognition, natural language processing, and predictive
  analytics.
- Model serving: Deploy models as containerized services that can be easily
  integrated into applications and scaled as needed.
- Reproducible environments: Package models with their dependencies, ensuring
  consistent behavior across development and production environments.
- Framework support: Find models built with popular frameworks like TensorFlow,
  PyTorch, scikit-learn, and others.

Containerized AI models remove the need to manage infrastructure dependencies,
let you deploy models across different environments, and enable scaling as
application demands change.

#### Plugins

Plugins in Docker Hub let you extend and customize Docker Engine to suit
specialized requirements. Plugins integrate directly with the Docker Engine and
provide capabilities such as:

- Network plugins: Enhance networking functionality, enabling integration with
  complex network infrastructures.
- Volume plugins: Provide advanced storage options, supporting persistent and
  distributed storage across various backends.
- Authorization plugins: Offer fine-grained access control to secure Docker
  environments.

By leveraging Docker plugins, teams can tailor Docker Engine to meet their
specific operational needs, ensuring compatibility with existing infrastructures
and workflows.

To learn more about plugins, see [Docker Engine managed plugin
system](/manuals/engine/extend/_index.md).


### Trusted content

Docker Hub's trusted content provides a curated selection of high-quality,
secure images designed to give developers confidence in the reliability and
security of the resources they use. These images are stable, regularly updated,
and adhere to industry best practices, making them a strong foundation for
building and deploying applications. Docker Hub's trusted content includes,
Docker Hardened Images, Docker Official Images, Verified Publisher images, and
Docker-Sponsored Open Source Software images.

For more details, see [Trusted content](trusted-content.md).

### Publishers

The **Publishers** filter lets you narrow image results by the organization
that published the image.

Publishers of trusted content appear first. Only a select number of publishers
are shown.

### Categories

Docker Hub makes it easy to find and explore container images with categories.
Categories group images based on their primary use case, helping you quickly
locate the tools and resources you need to build, deploy, and run your
applications.

{{% include "hub-categories.md" %}}

### Operating systems

The **Operating systems** filter lets you narrow your search to container
images compatible with specific host operating systems. This filter ensures that
the images you use align with your target environment, whether you're developing
for Linux-based systems, Windows, or both.

- **Linux**: Access a wide range of images tailored for Linux environments.
  These images provide foundational environments for building and running
  Linux-based applications in containers.
- **Windows**: Explore Windows container images.

> [!NOTE]
>
> The **Operating systems** filter is only available for images. If you select
> the **Extensions** or **Plugins** filter, then the **Operating systems**
> filter isn't available.

### Architectures

The **Architectures** filter lets you find images built to support specific CPU
architectures. This ensures compatibility with your hardware environment, from
development machines to production servers.

- **ARM**: Select images compatible with ARM processors, commonly used in IoT
  devices and embedded systems.
- **ARM 64**: Locate 64-bit ARM-compatible images for modern ARM processors,
  such as those in AWS Graviton or Apple Silicon.
- **IBM POWER**: Find images optimized for IBM Power Systems, offering
  performance and reliability for enterprise workloads.
- **PowerPC 64 LE**: Access images designed for the little-endian PowerPC 64-bit
  architecture.
- **IBM Z**: Discover images tailored for IBM Z mainframes, ensuring
  compatibility with enterprise-grade hardware.
- **x86**: Choose images compatible with 32-bit x86 architectures, suitable for
  older systems or lightweight environments.
- **x86-64**: Filter images for modern 64-bit x86 systems, widely used in
  desktops, servers, and cloud infrastructures.

> [!NOTE]
>
> The **Architectures** filter is only available for images. If you select the
> **Extensions** or **Plugins** filter, then the **Architectures** filter isn't
> available.

### Reviewed by Docker

The **Reviewed by Docker** filter provides an extra layer of assurance when
selecting extensions. This filter helps you identify whether a Docker Desktop
extension has been reviewed by Docker for quality and reliability.

- **Reviewed**: Extensions that have undergone Docker's review process, ensuring
  they meet high standards.
- **Not Reviewed**: Extensions that have not been reviewed by Docker.

> [!NOTE]
>
> The **Reviewed by Docker** filter is only available for extensions. To make
> the filter available, you must select only the **Extensions** filter in **Products**.

### Sandbox Kit type

The **Sandbox Kit type** filter lets you narrow sandbox kit results by kind.

- **Sandbox**: Kits that define a full agent from scratch.
- **Mixin**: Kits that layer onto an existing agent's sandbox.

> [!NOTE]
>
> The **Sandbox Kit type** filter is only available for sandbox kits. To make
> the filter available, you must select only the **Sandbox kits** filter in
> **Products**.


---

# Trusted content

*Sección: Docker Hub*

Docker Hub's trusted content provides a curated selection of high-quality,
secure images designed to give developers confidence in the reliability and
security of the resources they use. These images are stable, regularly updated,
and adhere to industry best practices, making them a strong foundation for
building and deploying applications. Docker Hub's trusted content includes
Docker Official Images, Docker Hardened Images and charts, Verified Publisher
images, and Docker-Sponsored Open Source Software images.

## Docker Official Images

The Docker Official Images are a curated set of Docker repositories hosted on
Docker Hub.

Docker recommends you use the Docker Official Images in your projects. These
images have clear documentation, promote best practices, and are regularly
updated. Docker Official Images support most common use cases, making them
perfect for new Docker users. Advanced users can benefit from more specialized
image variants as well as review Docker Official Images as part of your
`Dockerfile` learning process.

> [!NOTE]
>
> Use of Docker Official Images is subject to [Docker's Terms of Service](https://www.docker.com/legal/docker-terms-service/).

These images provide essential base repositories that serve as the starting
point for the majority of users.

These include operating systems such as
[Ubuntu](https://hub.docker.com/_/ubuntu/) and
[Alpine](https://hub.docker.com/_/alpine/), programming language runtimes such as
[Python](https://hub.docker.com/_/python) and
[Node](https://hub.docker.com/_/node), and other essential tools such as
[memcached](https://hub.docker.com/_/memcached) and
[MySQL](https://hub.docker.com/_/mysql).

The images are some of the [most secure images](https://www.docker.com/blog/enhancing-security-and-transparency-with-docker-official-images/)
on Docker Hub. This is particularly important as Docker Official Images are
some of the most popular on Docker Hub. Typically, Docker Official images have
few or no packages containing CVEs.

The images exemplify [Dockerfile best practices](../../build/building/best-practices.md)
and provide clear documentation to serve as a reference for other Dockerfile authors.

Images that are part of this program have a special badge on Docker Hub making
it easier for you to identify projects that are part of Docker Official Images.

![Docker official image badge](../images/official-image-badge-iso.png)

### Supported tags and respective Dockerfile links

The repository description for each Docker Official Image contains a
**Supported tags and respective Dockerfile links** section that lists all the
current tags with links to the Dockerfiles that created the image with those
tags. The purpose of this section is to show what image variants are available.

![Example: supported tags for Ubuntu](../images/supported_tags.webp)

Tags listed on the same line all refer to the same underlying image. Multiple
tags can point to the same image. For example, in the previous screenshot taken
from the `ubuntu` Docker Official Images repository, the tags `24.04`,
`noble-20240225`, `noble`, and `devel` all refer to the same image.

The `latest` tag for a Docker Official Image is often optimized for ease of use
and includes a wide variety of useful software, such as developer and build tools.
By tagging an image as `latest`, the image maintainers are essentially suggesting
that image be used as the default. In other words, if you do not know what tag to
use or are unfamiliar with the underlying software, you should probably start with
the `latest` image. As your understanding of the software and image variants advances,
you may find other image variants better suit your needs.

### Slim images

A number of language stacks such as
[Node.js](https://hub.docker.com/_/node/),
[Python](https://hub.docker.com/_/python/), and
[Ruby](https://hub.docker.com/_/ruby/) have `slim` tag variants
designed to provide a lightweight, production-ready base image
with fewer packages.

A typical consumption pattern for `slim`
images is as the base image for the final stage of a
[multi-staged build](https://docs.docker.com/build/building/multi-stage/).
For example, you build your application in the first stage of the build
using the `latest` variant and then copy your application into the final
stage based upon the `slim` variant. Here is an example `Dockerfile`.

```dockerfile
FROM node:latest AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . ./
FROM node:slim
WORKDIR /app
COPY --from=build /app /app
CMD ["node", "app.js"]
```

### Alpine images

Many Docker Official Images repositories also offer `alpine` variants. These
images are built on top of the [Alpine Linux](https://www.alpinelinux.org/)
distribution rather than Debian or Ubuntu. Alpine Linux is focused on providing
a small, simple, and secure base for container images, and Docker Official
Images `alpine` variants typically aim to install only necessary packages. As a
result, Docker Official Images `alpine` variants are typically even smaller
than `slim` variants.

The main caveat to note is that Alpine Linux uses [musl libc](https://musl.libc.org/)
instead of [glibc](https://www.gnu.org/software/libc/). Additionally, to
minimize image size, it's uncommon for Alpine-based images to include tools
such as Git or Bash by default. Depending on the depth of libc requirements or
assumptions in your programs, you may find yourself running into issues due to
missing libraries or tools.

When you use Alpine images as a base, consider the following options in order
to make your program compatible with Alpine Linux and musl:

- Compile your program against musl libc
- Statically link glibc libraries into your program
- Avoid C dependencies altogether (for example, build Go programs without CGO)
- Add the software you need yourself in your Dockerfile.

Refer to the `alpine` image [description](https://hub.docker.com/_/alpine) on
Docker Hub for examples on how to install packages if you are unfamiliar.

### Codenames

Tags with words that look like Toy Story characters (for example, `bookworm`,
`bullseye`, and `trixie`) or adjectives (such as `jammy`, and
`noble`), indicate the codename of the Linux distribution they use as a base
image. Debian release codenames are [based on Toy Story characters](https://en.wikipedia.org/wiki/Debian_version_history#Naming_convention),
and Ubuntu's take the form of "Adjective Animal". For example, the
codename for Ubuntu 24.04 is "Noble Numbat".

Linux distribution indicators are helpful because many Docker Official Images
provide variants built upon multiple underlying distribution versions (for
example, `postgres:bookworm` and `postgres:bullseye`).

### Other tags

Docker Official Images tags may contain other hints to the purpose of
their image variant in addition to those described here. Often these
tag variants are explained in the Docker Official Images repository
documentation. Reading through the "How to use this image" and
"Image Variants" sections will help you to understand how to use these
variants.

### Troubleshooting failed pulls

If you're experiencing failed pulls of Docker Official Images, check whether
the `DOCKER_CONTENT_TRUST` environment variable is set to `1`. Docker Content
Trust is being retired and the service is no longer reliable for pulls. To
resolve pull failures, unset `DOCKER_CONTENT_TRUST`. For more information, see
[Docker Content Trust (DCT)](../../retired.md#docker-content-trust-dct).

## Docker Hardened Images

Docker Hardened Images (DHI) are minimal, secure, and production-ready
container base and application images maintained by Docker. DHI also includes
Docker-provided hardened Helm charts built from upstream sources and published
as OCI artifacts in Docker Hub.

DHI is designed to reduce vulnerabilities and simplify compliance while fitting
into existing Docker workflows with little to no retooling required. Docker
maintains near-zero CVEs in DHI images, and DHI images and charts include
signed security metadata such as SBOMs and provenance attestations.

Image and chart repositories have special badges
on Docker Hub, making it easier to identify trusted DHI content.

![Docker Hardened Image badge](../images/dhi-image-label.png)

![Docker Hardened Chart badge](../images/dhi-chart-label.png)

To browse available repositories, see the [Docker Hardened Images
catalog](https://hub.docker.com/hardened-images/catalog). For implementation
guidance, see [Docker Hardened Images](/dhi/).

## Verified Publisher images

The Docker Verified Publisher program provides high-quality images from
commercial publishers verified by Docker.

These images help development teams build secure software supply chains,
minimizing exposure to malicious content early in the process to save time and
money later.

Images that are part of this program have a special badge on Docker Hub making
it easier for users to identify projects that Docker has verified as
high-quality commercial publishers.

![Docker-Verified Publisher badge](../images/verified-publisher-badge-iso.png)

## Docker-Sponsored Open Source Software images

The Docker-Sponsored Open Source Software (OSS) program provides images that are
published and maintained by open-source projects sponsored by Docker.

Images that are part of this program have a special badge on Docker Hub making
it easier for users to identify projects that Docker has verified as trusted,
secure, and active open-source projects.

![Docker-Sponsored Open Source badge](../images/sponsored-badge-iso.png)


---

# Docker Hub MCP server

*Sección: Docker Hub*

The Docker Hub MCP Server is a Model Context Protocol (MCP) server that
interfaces with Docker Hub APIs to make rich image metadata accessible to LLMs,
enabling intelligent content discovery and repository management.

For more information about MCP concepts and how MCP servers work, see the [Docker MCP Catalog and Toolkit](/ai/mcp-catalog-and-toolkit/) overview page.

## Key features

- Advanced LLM context: Docker's MCP Server provides LLMs with detailed, structured context for Docker Hub images, enabling smarter, more relevant recommendations for developers, whether they're choosing a base image or automating CI/CD workflows.
- Natural language image discovery: Developers can find the right container image using natural language, no need to remember tags or repository names. Just describe what you need, and Docker Hub will return images that match your intent.
- Simplified repository management: Hub MCP Server enables agents to manage repositories through natural language fetching image details, viewing stats, searching content, and performing key operations quickly and easily.

## Install Docker Hub MCP server

1. In Docker Desktop, select **MCP Toolkit** and select the **Profiles** tab,
   then select **Create profile** to create a new profile, or select an existing
   profile to use.
2. Select the **Catalog** tab, search for **Docker Hub**, and select **Add to**
   to add it to your profile.
3. Select the **Profiles** tab, select the profile you added Docker Hub to, and
   select the configuration icon on the Docker Hub MCP server. Enter your Docker
   Hub username and personal access token (PAT).
4. Under the **Clients** section of the same profile, if you already have a
   client connected it connects automatically. Otherwise, select the plus icon
   to add a client.

For more details on setting up profiles and connecting clients, see
[Get started with Docker MCP Toolkit](/ai/mcp-catalog-and-toolkit/get-started/).

## Use Claude Desktop as a client

1. Add the Docker Hub MCP Server configuration to your `claude_desktop_config.json`:

   {{< tabs >}}
   {{< tab name="For public repositories only">}}

   ```json
   {
     "mcpServers": {
       "docker-hub": {
         "command": "node",
         "args": ["/FULL/PATH/TO/YOUR/docker-hub-mcp-server/dist/index.js", "--transport=stdio"]
       }
     }
   }
   ```

   Where :
   - `/FULL/PATH/TO/YOUR/docker-hub-mcp-server` is the complete path to where you cloned the repository

   {{< /tab >}}
   {{< tab name="For authenticated access">}}

   ```json
   {
     "mcpServers": {
       "docker-hub": {
         "command": "node",
         "args": ["/FULL/PATH/TO/YOUR/docker-hub-mcp-server/dist/index.js", "--transport=stdio", "--username=YOUR_DOCKER_HUB_USERNAME"],
         "env": {
           "HUB_PAT_TOKEN": "YOUR_DOCKER_HUB_PERSONAL_ACCESS_TOKEN"
         }
       }
     }
   }
   ```

   Where :
   - `YOUR_DOCKER_HUB_USERNAME` is your Docker Hub username.
   - `YOUR_DOCKER_HUB_PERSONAL_ACCESS_TOKEN` is Docker Hub personal access token
   - `/FULL/PATH/TO/YOUR/docker-hub-mcp-server` is the complete path to where you cloned the repository


   {{< /tab >}}
   {{</tabs >}}

1. Save the configuration file and completely restart Claude Desktop for the changes to take effect.

## Usage with Visual Studio Code

1. Add the Docker Hub MCP Server configuration to your User Settings (JSON)
   file in Visual Studio Code. You can do this by opening the `Command Palette` and
   typing `Preferences: Open User Settings (JSON)`.


   {{< tabs >}}
   {{< tab name="For public repositories only">}}

   ```json
   {
     "mcpServers": {
       "docker-hub": {
         "command": "node",
         "args": ["/FULL/PATH/TO/YOUR/docker-hub-mcp-server/dist/index.js", "--transport=stdio"]
       }
     }
   }
   ```

   Where :
   - `/FULL/PATH/TO/YOUR/docker-hub-mcp-server` is the complete path to where you cloned the repository

   {{< /tab >}}
   {{< tab name="For authenticated access">}}

   ```json
   {
     "mcpServers": {
       "docker-hub": {
         "command": "node",
         "args": ["/FULL/PATH/TO/YOUR/docker-hub-mcp-server/dist/index.js", "--transport=stdio"],
         "env": {
           "HUB_USERNAME": "YOUR_DOCKER_HUB_USERNAME",
           "HUB_PAT_TOKEN": "YOUR_DOCKER_HUB_PERSONAL_ACCESS_TOKEN"
         }
       }
     }
   }
   ```

   Where :
   - `YOUR_DOCKER_HUB_USERNAME` is your Docker Hub username.
   - `YOUR_DOCKER_HUB_PERSONAL_ACCESS_TOKEN` is Docker Hub personal access token
   - `/FULL/PATH/TO/YOUR/docker-hub-mcp-server` is the complete path to where you cloned the repository


   {{< /tab >}}
   {{</tabs >}}

1. Open the `Command Palette` and type `MCP: List Servers`.
1. Select `docker-hub` and select `Start Server`.

## Using other clients

To integrate the Docker Hub MCP Server into your own development
environment, see the source code and installation instructions on the
[`hub-mcp` GitHub repository](https://github.com/docker/hub-mcp).


## Usage examples

This section provides task-oriented examples for common operations with Docker Hub
tools.

### Finding images


```console
# Search for official images
$ docker ai "Search for official nginx images on Docker Hub"

# Search for lightweight images to reduce deployment size and improve performance
$ docker ai "Search for minimal Node.js images with small footprint"

# Get the most recent tag of a base image
$ docker ai "Show me the latest tag details for go"

# Find a production-ready database with enterprise features and reliability
$ docker ai "Search for production ready database images"

# Compare Ubuntu versions to choose the right one for my project
$ docker ai "Help me find the right Ubuntu version for my project"
```

### Repository management

```console
# Create a repository
$ docker ai "Create a repository in my namespace"

# List all repositories in my namespace
$ docker ai "List all repositories in my namespace"

# Find the largest repository in my namespace
$ docker ai "Which of my repositories takes up the most space?"

# Find repositories that haven't been updated recently
$ docker ai "Which of my repositories haven't had any pushes in the last 60 days?"

# Find which repositories are currently active and being used
$ docker ai "Show me my most recently updated repositories"

# Get details about a repository
$ docker ai "Show me information about my '<repository-name>' repository"
```

### Pull/push images


```console
# Pull latest PostgreSQL version
$ docker ai "Pull the latest postgres image"

# Push image to your Docker Hub repository
$ docker ai "Push my <image-name> to my <repository-name> repository"
```

### Tag management

```console
# List all tags for a repository
$ $ docker ai "Show me all tags for my '<repository-name>' repository"

# Find the most recently pushed tag
$ docker ai "What's the most recent tag pushed to my '<repository-name>' repository?"

# List tags with architecture filtering
$ docker ai "List tags for in the '<repository-name>' repository that support amd64 architecture"

# Get detailed information about a specific tag
$ docker ai "Show me details about the '<tag-name>' tag in the '<repository-name>' repository"

# Check if a specific tag exists
$ docker ai "Check if version 'v1.2.0' exists for my 'my-web-app' repository"
```

### Docker Hardened Images

```console
# List available hardened images
$ docker ai "What is the most secure image I can use to run a node.js application?"

# Convert Dockerfile to use a hardened image
$ docker ai "Can you help me update my Dockerfile to use a docker hardened image instead of the current one"
```
> [!NOTE]
> To access Docker Hardened Images, a subscription is required. If you're interested in using Docker Hardened Images, visit [Docker Hardened Images](https://www.docker.com/products/hardened-images/).


## Reference

This section provides a comprehensive listing of the tools you can find
in the Docker Hub MCP Server.

### Docker Hub MCP server tools

Tools to interact with your Docker repositories and discover content on Docker Hub.

| Name | Description |
|------|-------------|
| `check-repository` | Check repository |
| `check-repository-tag` | Check repository tag |
| `check-repository-tags` | Check repository tags |
| `create-repository` | Creates a new repository |
| `docker-hardened-images` | Lists available [Docker Hardened Images](https://www.docker.com/products/hardened-images/) in specified namespace |
| `get-namespaces` | Get organizations/namespaces for a user |
| `get-repository-dockerfile` | Gets Dockerfile for repository |
| `get-repository-info` | Gets repository info |
| `list-repositories-by-namespace` | Lists repositories under namespace |
| `list-repository-tags` | List repository tags |
| `read-repository-tag` | Read repository tag |
| `search` | Search content on Docker Hub |
| `set-repository-dockerfile` | Sets Dockerfile for repository |
| `update-repository-info` | Updates repository info |


---

# Docker Hub quickstart

*Sección: Docker Hub*

Docker Hub provides a vast library of pre-built images and resources,
accelerating development workflows and reducing setup time. You can build upon
pre-built images from Docker Hub and then use repositories to share and
distribute your own images with your team or millions of other developers.

This guide shows you how to find and run a pre-built image. It then walks you
through creating a custom image and sharing it through Docker Hub.

## Prerequisites

- [Download and install Docker](../../get-started/get-docker.md)
- A verified [Docker](https://app.docker.com/signup) account

## Step 1: Find an image in Docker Hub's library

You can search for content in Docker Hub itself, in the Docker Desktop
Dashboard, or by using the CLI.

To search or browse for content on Docker Hub:

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Navigate to the [Docker Hub Explore page](https://hub.docker.com/explore).

   On the **Explore** page, you can browse by catalog or category, or use the search
   to quickly find content.

2. Under **Categories**, select **Web servers**.

   After the results are displayed, you can further filter the results using the
   filters on the left side of the page.

3. In the filters, select **Docker Official Image**.

   Filtering by Trusted Content ensures that you see only high-quality, secure
   images curated by Docker and verified publishing partners.

4. In the results, select the **nginx** image.

   Selecting the image opens the image's page where you can learn more about how
   to use the image. On the page, you'll also find the `docker pull` command to
   pull the image.

{{< /tab >}}
{{< tab name="Docker Desktop" >}}

1. Open the Docker Desktop Dashboard.
2. Select the **Docker Hub** view.

   In the **Docker Hub** view, you can browse by catalog or category, or use the search
   to quickly find content.

3. Leave the search box empty and then select **Search**.

   The search results are shown with additional filters now next to the search box.

4. Select the search filter icon, and then select **Docker Official Image** and **Web Servers**.
5. In the results, select the **nginx** image.

{{< /tab >}}
{{< tab name="CLI" >}}

1. Open a terminal window.

   > [!TIP]
   >
   > The Docker Desktop Dashboard contains a built-in terminal. At the bottom of
   > the Dashboard, select **>_ Terminal** to open it.

2. In the terminal, run the following command.

   ```console
   $ docker search --filter is-official=true nginx
   ```

   Unlike the Docker Hub and Docker Desktop interfaces, you can't browse by
   category using the `docker search` command. For more details about the
   command, see [docker search](/reference/cli/docker/search/).

{{< /tab >}}
{{< /tabs >}}

Now that you've found an image, it's time to pull and run it on your device.

## Step 2: Pull and run an image from Docker Hub

You can run images from Docker Hub using the CLI or Docker Desktop Dashboard.

{{< tabs >}}
{{< tab name="Docker Desktop" >}}

1. In the Docker Desktop Dashboard, select the **nginx** image in the **Docker
   Hub** view. For more details, see [Step 1: Find an image in Docker Hub's
   library](#step-1-find-an-image-in-docker-hubs-library).

2. On the **nginx** screen, select **Run**.

   If the image doesn't exist on your device, it is automatically pulled from
   Docker Hub. Pulling the image may take a few seconds or minutes depending on
   your connection. After the image has been pulled, a window appears in Docker
   Desktop and you can specify run options.

3. In the **Host port** option, specify `8080`.
4. Select **Run**.

   The container logs appear after the container starts.

5. Select the **8080:80** link to open the server, or visit
   [http://localhost:8080](http://localhost:8080) in your web browser.

6. In the Docker Desktop Dashboard, select the **Stop** button to stop the
   container.


{{< /tab >}}
{{< tab name="CLI" >}}

1. Open a terminal window.

   > [!TIP]
   >
   > The Docker Desktop Dashboard contains a built-in terminal. At the bottom of
   > the Dashboard, select **>_ Terminal** to open it.

2. In your terminal, run the following command to pull and run the Nginx image.

   ```console
   $ docker run -p 8080:80 --rm nginx
   ```

   The `docker run` command automatically pulls and runs the image without the
   need to run `docker pull` first. To learn more about the command and its
   options, see the [`docker run` CLI
   reference](/reference/cli/docker/container/run/). After running the
   command, you should see output similar to the following.

   ```console {collapse=true}
   Unable to find image 'nginx:latest' locally
   latest: Pulling from library/nginx
   a480a496ba95: Pull complete
   f3ace1b8ce45: Pull complete
   11d6fdd0e8a7: Pull complete
   f1091da6fd5c: Pull complete
   40eea07b53d8: Pull complete
   6476794e50f4: Pull complete
   70850b3ec6b2: Pull complete
   Digest: sha256:28402db69fec7c17e179ea87882667f1e054391138f77ffaf0c3eb388efc3ffb
   Status: Downloaded newer image for nginx:latest
   /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
   /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
   /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
   10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
   10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
   /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
   /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
   /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
   /docker-entrypoint.sh: Configuration complete; ready for start up
   2024/11/07 21:43:41 [notice] 1#1: using the "epoll" event method
   2024/11/07 21:43:41 [notice] 1#1: nginx/1.27.2
   2024/11/07 21:43:41 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
   2024/11/07 21:43:41 [notice] 1#1: OS: Linux 6.10.11-linuxkit
   2024/11/07 21:43:41 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
   2024/11/07 21:43:41 [notice] 1#1: start worker processes
   2024/11/07 21:43:41 [notice] 1#1: start worker process 29
   ...
   ```

3. Visit [http://localhost:8080](http://localhost:8080) to view the default
   Nginx page and verify that the container is running.

4. In the terminal, press <kdb>Ctrl+C</kbd> to stop the container.

{{< /tab >}}
{{< /tabs >}}

You've now run a web server without any set up or configuration. Docker Hub
provides instant access to pre-built, ready-to-use container images, letting you
quickly pull and run applications without needing to install or configure
software manually. With Docker Hub's vast library of images, you can experiment
with and deploy applications effortlessly, boosting productivity and making it
easy to try out new tools, set up development environments, or build on top of
existing software.

You can also extend images from Docker Hub, letting you quickly build and
customize your own images to suit specific needs.


## Step 3: Build and push an image to Docker Hub

1. Create a [Dockerfile](../build/concepts/dockerfile.md) to specify your application:

   ```dockerfile
   FROM nginx
   RUN echo "<h1>Hello world from Docker!</h1>" > /usr/share/nginx/html/index.html
   ```

   This Dockerfile extends the Nginx image from Docker Hub to create a
   simple website. With just a few lines, you can easily set up, customize, and
   share a static website using Docker.

2. Run the following command to build your image. Replace `<YOUR-USERNAME>` with your Docker ID.

   ```console
   $ docker build -t <YOUR-USERNAME>/nginx-custom .
   ```

   This command builds your image and tags it so that Docker understands which
   repository to push it to in Docker Hub. To learn more about the command and
   its options, see the [`docker build` CLI
   reference](/reference/cli/docker/buildx/build/). After running the
   command, you should see output similar to the following.

   ```console {collapse=true}
   [+] Building 0.6s (6/6) FINISHED                      docker:desktop-linux
    => [internal] load build definition from Dockerfile                  0.0s
    => => transferring dockerfile: 128B                                  0.0s
    => [internal] load metadata for docker.io/library/nginx:latest       0.0s
    => [internal] load .dockerignore                                     0.0s
    => => transferring context: 2B                                       0.0s
    => [1/2] FROM docker.io/library/nginx:latest                         0.1s
    => [2/2] RUN echo "<h1>Hello world from Docker!</h1>" > /usr/share/  0.2s
    => exporting to image                                                0.1s
    => => exporting layers                                               0.0s
    => => writing image sha256:f85ab68f4987847713e87a95c39009a5c9f4ad78  0.0s
    => => naming to docker.io/mobyismyname/nginx-custom                  0.0s
   ```

3. Run the following command to test your image. Replace `<YOUR-USERNAME>` with
   your Docker ID.

   ```console
   $ docker run -p 8080:80 --rm <YOUR-USERNAME>/nginx-custom
   ```

4. Visit [http://localhost:8080](http://localhost:8080) to view the page. You
   should see `Hello world from Docker!`.

5. In the terminal, press CTRL+C to stop the container.

6. Sign in to Docker Desktop. You must be signed in before pushing an image to
   Docker Hub.

7. Run the following command to push your image to Docker Hub. Replace `<YOUR-USERNAME>` with your Docker ID.

   ```console
   $ docker push <YOUR-USERNAME>/nginx-custom
   ```

    > [!NOTE]
    >
    > You must be signed in to Docker Hub through Docker Desktop or the command line, and you must also name your images correctly, as per the above steps.

   The command pushes the image to Docker Hub and automatically
   creates the repository if it doesn't exist. To learn more about the command,
   see the [`docker push` CLI
   reference](/reference/cli/docker/image/push/). After running the
   command, you should see output similar to the following.

   ```console {collapse=true}
   Using default tag: latest
   The push refers to repository [docker.io/mobyismyname/nginx-custom]
   d0e011850342: Pushed
   e4e9e9ad93c2: Mounted from library/nginx
   6ac729401225: Mounted from library/nginx
   8ce189049cb5: Mounted from library/nginx
   296af1bd2844: Mounted from library/nginx
   63d7ce983cd5: Mounted from library/nginx
   b33db0c3c3a8: Mounted from library/nginx
   98b5f35ea9d3: Mounted from library/nginx
   latest: digest: sha256:7f5223ae866e725a7f86b856c30edd3b86f60d76694df81d90b08918d8de1e3f size: 1985
   ```

  Now that you've created a repository and pushed your image, it's time to view
  your repository and explore its options.

## Step 4: View your repository on Docker Hub and explore options

You can view your Docker Hub repositories in the Docker Hub or Docker Desktop interface.

{{< tabs >}}
{{< tab name="Docker Hub" >}}

1. Go to [Docker Hub](https://hub.docker.com) and sign in.

   After signing in, you should be on the **Repositories** page. If not, then go
   to the [**Repositories**](https://hub.docker.com/repositories/) page.

2. Find the **nginx-custom** repository and select that row.

   After selecting the repository, you should see more details and options for
   your repository.

{{< /tab >}}
{{< tab name="Docker Desktop" >}}

1. Sign in to Docker Desktop.
2. Select the **Images** view.
3. Select the **Hub repositories** tab.

   A list of your Docker Hub repositories appears.

4. Find the **nginx-custom** repository, hover over the row, and then select **View in Hub**.

   Docker Hub opens and you are able to view more details about the image.

{{< /tab >}}
{{< /tabs >}}

You've now verified that your repository exists on Docker Hub, and you've
discovered more options for it. View the next steps to learn more about some of
these options.

## Next steps

Add [repository information](repos/manage/information.md) to help users find and use
your image.


---

# Docker Hub release notes

*Sección: Docker Hub*

Here you can learn about the latest changes, new features, bug fixes, and
known issues for each Docker Hub release.

## 2026-08-20

### New

- The [Docker Verified Publisher Program](repos/manage/trusted-content/dvp-program.md)
  is now available via self-serve. Apply directly on the [DVP application
  page](https://hub.docker.com/publisher-program/apply).

## 2026-06-29

### New

- Docker Hub integrates with Cloudsmith, letting it handle authentication
  for Docker Hub and Docker Hardened Images (DHI) upstreams using a managed
  token. This removes the need to supply your own credentials during setup.
  See Cloudsmith's announcement, [Set up Docker Hub and DHI upstreams with
  Cloudsmith-managed
  authentication](https://cloudsmith.com/changelog/set-up-docker-hub-and-dhi-upstreams-with-cloudsmith-managed-authentication),
  for details.

## 2026-05-20

### Infrastructure updates

- Docker Hub has added Amazon CloudFront as a CDN for image pushes and pulls,
  improving reliability. You may see a new domain,
  `production.cloudfront.docker.com`, in your network logs. TLS certificates for
  this domain are issued by Amazon Trust Services.

  Most users are unaffected. You may need to take action if your environment
  uses an egress firewall with a domain allowlist, a TLS inspection proxy, or a
  managed CA trust store. See the [Docker Desktop
  allowlist](../desktop/setup/allow-list.md) for updated domain
  requirements. If you see TLS errors, ensure your trust store includes the
  [Amazon Trust Services Root CAs](https://www.amazontrust.com/repository/). If
  you're a paid subscriber, you can [contact Docker
  Support](https://hub.docker.com/support/contact/) if you need updated TLS
  certificate details or the issue persists.

## 2026-05-06

### Deprecation notice

- [Docker Hub Automated Builds](./repos/manage/builds/) 
  is being deprecated. Existing accounts will have access until April 1, 2027. 
  See [migration options](./repos/manage/builds/migrate/)
  for guides on migrating to GitHub Actions or Bitbucket Pipelines.

## 2026-02-13

### New

- Administrators can now prevent creating public repositories within
  organization namespaces using the [Disable public
  repositories](settings.md#disable-creation-of-public-repos) setting.

## 2025-02-18

### New

- You can delete images and image indexes using [Image Management](repos/manage/hub-images/manage.md).

## 2024-12-12

### New

- The AI Catalog in Docker Hub is available directly through Docker Desktop.

## 2024-03-23

### New

- You can tag Docker Hub repositories with [categories](repos/manage/information.md#repository-categories).

## 2023-12-11

- The Advanced Image Management feature, along with the corresponding API endpoints, has been retired.
  See [docker/roadmap#534](https://github.com/docker/roadmap/issues/534).

  The following API endpoints have been removed:

  ```text
  /namespaces/{namespace}/repositories/{repository}/images
  /namespaces/{namespace}/repositories/{repository}/images/{digest}/tags
  /namespaces/{namespace}/repositories/{repository}/images-summary
  /namespaces/{namespace}/delete-images
  ```

## 2023-08-28

- Organizations with SSO enabled can assign members to roles, organizations, and teams with [SCIM role mapping](scim.md#set-up-role-mapping).

## 2023-07-26

### New

- Organizations can assign the [editor role](../security/roles-and-permissions/index.md) to members to grant additional permissions without full administrative access.

## 2023-05-09

### New

- Docker Business subscribers can now [create a company](../accounts/company/new-company.md) in Docker Hub to manage organizations and settings.

## 2023-03-07

### New

- You can now automatically sync user updates with your Docker organizations and teams with [Group Mapping](../security/provisioning/scim/group-mapping.md) for SSO and SCIM provisioning.

## 2022-12-12

### New

- The new domain audit feature lets you audit your domains for users who aren't a member of your organization.

## 2022-09-26

### New

- The new [autobuild feature](repos/manage/builds/manage-builds.md#check-your-active-builds) lets you view your in-progress logs every 30 seconds instead of when the build is complete.

## 2022-09-21

### Bug fixes and enhancements

- In Docker Hub, you can now download a [registry.json](../enterprise/security/enforce-sign-in/index.md) file or copy the commands to create a registry.json file to enforce sign-in for your organization.

## 2022-09-19

### Bug fixes and enhancements

- You can now [export a CSV file of members](../accounts/organization/manage/members.md#export-members-csv-file) from organizations that you own.

## 2022-07-22

### Bug fixes and enhancements

- You can now invite members to your organization with a CSV file containing their email addresses. The CSV file can either be a file you create for this specific purpose or one that’s extracted from another in-house system.

## 2022-07-19

### Bug fixes and enhancements

- SCIM is now available for organizations with a Docker Business subscription using an Entra ID (formerly Azure AD) identity provider.

## 2022-06-23

### New

- With [SCIM](scim.md), you can manage users within your Okta identity provider (IdP). In addition, you can enable SCIM on organizations that are part of the Docker Business subscription.

## 2022-05-24

### New

- [Registry Access Management](../enterprise/security/hardened-desktop/registry-access-management.md) is now available for all Docker Business subscriptions. When enabled, your users can access specific registries in Docker Hub.

## 2022-05-03

### New

- Organization owners can [invite new members](../accounts/organization/manage/members.md#invite-members) to an organization via Docker ID or email address.

## 2021-11-15

### New

- You can now purchase or upgrade to a Docker Business subscription using a credit card. To learn more, see [Upgrade your subscription](../subscription-billing/plans/docker.md).

## 2021-08-31

### New

Docker has [announced](https://www.docker.com/blog/updating-product-subscriptions/) updates and extensions to the product subscriptions to increase productivity, collaboration, and added security for our developers and businesses. Docker subscription tiers now include Personal, Pro, Team, and Business.

The updated [Docker Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement) includes a change to the terms for **Docker Desktop**.

- Docker Desktop **remains free** for small businesses (fewer than 250 employees AND less than $10 million in annual revenue), personal use, education, and non-commercial open source projects.
- It requires a paid subscription (**Pro, Team, or Business**), for as little as $5 a month, for professional use in larger enterprises.
- The effective date of these terms is August 31, 2021. There is a grace period until January 31, 2022 for those that will require a paid subscription to use Docker Desktop.
- The Docker Pro and Docker Team subscriptions now **include commercial use** of Docker Desktop.
- The existing Docker Free subscription has been renamed **Docker Personal**.
- **No changes** to Docker Engine or any other upstream **open source** Docker or Moby project.

  To understand how these changes affect you, read the [FAQs](https://www.docker.com/pricing/faq). For more information, see [Docker subscription overview](../subscription-billing/index.md).

## 2021-05-05

### Enhancement

When managing the content of your repositories, you can now filter the results based on the currentness of the tags and more easily identify your untagged images.

For Docker Hub API documentation, see [Docker Hub API Reference](../reference/api/hub/latest.md#operation/GetNamespacesRepositoriesImages).

## 2021-04-13

### Enhancement

The **Billing Details** page now shows any organizations you own, in addition to your personal account. This allows you to clearly identify the billing details of your chosen namespace, and enables you to switch between your personal and your organization accounts to view or update the details.

## 2021-04-09

### Enhancement

You can now specify any email address to receive billing-related emails for your organization. The email address doesn't have to be associated with an organization owner account. You must be an owner of the organization to update any billing details.

To change the email address receiving billing-related emails, log into Docker Hub and navigate to the **Billing** tab of your organization. Select **Payment Methods** > **Billing Information**. Enter the new email address that you'd like to use in the **Email** field. Click **Update** for the changes to take effect.

For details on how to update your billing information, see [Update billing information](../subscription-billing/index.md).

## 2021-03-22

### New feature

**Advanced Image Management dashboard**

Docker introduces the Advanced Image Management dashboard that enables you to view and manage Docker images in your repositories.

## 2021-01-25

### New feature

Docker introduces Audit logs, a new feature that allows team owners to view a list of activities that occur at organization and repository levels. This feature begins tracking the activities from the release date, that is, **from 25 January 2021**.

For more information about this feature and for instructions on how to use it, see [Activity logs](../accounts/organization/activity-logs.md).

## 2020-11-10

### New feature

The **Repositories** view now shows which images have gone stale because they haven't been pulled or pushed recently. For more information, see [repository tags](repos/manage/access/_index.md#view-repository-tags).

## 2020-10-07

### New feature

Docker introduces Hub Vulnerability Scanning which enables you to automatically scan Docker images for vulnerabilities using Snyk. For more information, see [Hub Vulnerability Scanning](repos/manage/vulnerability-scanning.md).

## 2020-05-14

### New features

- Docker has announced a new, per-seat pricing model to accelerate developer workflows for cloud-native development. The previous private repository/concurrent autobuild-based plans have been replaced with new **Pro** and **Team** plans that include unlimited private repositories. For more information, see [Docker subscription](../subscription-billing/index.md).

- Docker has enabled download rate limits for downloads and pull requests on Docker Hub. This caps the number of objects that users can download within a specified timeframe. For more information, see [Usage and limits](usage/index.md).

## 2019-11-04

### Enhancements

- The [repositories page](repos/index.md) and all
  related settings and tabs have been updated and moved from `cloud.docker.com`
  to `hub.docker.com`. You can access the page at its new URL: [https://hub.docker.com/repositories](https://hub.docker.com/repositories).

### Known Issues

- Scan results don't appear for some official images.

## 2019-10-21

### New features

- **Beta:** Docker Hub now supports two-factor authentication (2FA). Enable it in your account settings, under the **[Security](https://hub.docker.com/settings/security)** section.

  > If you lose both your 2FA authentication device and recovery code, you may
  > not be able to recover your account.

### Enhancements

- As a security measure, when two-factor authentication is enabled, the Docker CLI requires a personal access token instead of a password to log in.

### Known Issues

- Scan results don't appear for some official images.

## 2019-10-02

### Enhancements

- You can now manage teams and members straight from your [organization page](https://hub.docker.com/orgs).
  Each organization page now breaks down into these tabs:
  - **New:** Members - manage your members directly from this page (delete,
    add, or open their teams)
  - **New:** Teams - search by team or username, and open up any team page to
    manage the team
  - **New:** Invitees (conditional tab, only if an invite exists) - resend or
    remove invitations from this tab
  - Repositories
  - Settings
  - Billing

### Bug fixes

- Fixed an issue where Kinematic could not connect and log in to Docker Hub.

### Known Issues

- Scan results don't appear for some official images.

## 2019-09-19

### New features

- You can now [create personal access tokens](/security/access-tokens/personal-access-tokens/) in Docker Hub and use them to authenticate from the Docker CLI. Find them in your account settings, under the new **[Security](https://hub.docker.com/settings/security)** section.

### Known Issues

- Scan results don't appear for some official images.

## 2019-09-16

### Enhancements

- The [billing page](../subscription-billing/plans/docker.md) for personal accounts has been updated. You can access the page at its new URL: [https://hub.docker.com/billing/plan](https://hub.docker.com/billing/plan).

### Known Issues

- Scan results don't appear for some official images.

## 2019-09-05

### Enhancements

- The `Tags` tab on an image page now provides additional information for each tag:
  - A list of digests associated with the tag
  - The architecture it was built on
  - The OS
  - The user who most recently updated an image for a specific tag
- The security scan summary for Docker Official Images has been updated.

### Known Issues

- Scan results don't appear for some official images.


---

# Repositories

*Sección: Docker Hub*

A Docker Hub repository is a collection of container images, enabling you to
store, manage, and share Docker images publicly or privately. Each repository
serves as a dedicated space where you can store images associated with a
particular application, microservice, or project. Content in repositories is
organized by tags, which represent different versions of the same application,
allowing users to pull the right version when needed.

In this section, learn how to:

- [Create](create.md) a repository.
- Manage a repository, including how to manage:

   - [Repository information](manage/information.md): Add descriptions,
     overviews, and categories to help users understand the purpose and usage of
     your repository. Clear repository information aids discoverability and
     usability.

   - [Access](manage/access.md): Control who can access your repositories with
     flexible options. Make repositories public or private, add collaborators,
     and, for organizations, manage roles and teams to maintain security and
     control.

   - [Images](manage/hub-images/index.md): Repositories support diverse
     content types, including OCI artifacts, and allow version control through
     tagging. Push new images and manage existing content across repositories
     for flexibility.

   - [Image security insights](manage/vulnerability-scanning.md): Utilize
     continuous Docker Scout analysis and static vulnerability scanning to
     detect, understand, and address security issues within container images.

   - [Webhooks](manage/webhooks.md): Automate responses to repository events
     like image pushes or updates by setting up webhooks, which can trigger
     notifications or actions in external systems, streamlining workflows.

   - [Automated builds](manage/builds/index.md): Integrate with GitHub or
     Bitbucket for automated builds. Every code change triggers an image
     rebuild, supporting continuous integration and delivery.

   - [Trusted content](manage/trusted-content/index.md): Contribute to Docker
     Official Images or manage repositories in the Verified Publisher and
     Sponsored Open Source programs, including tasks like setting logos,
     accessing analytics, and enabling vulnerability scanning.

- [Archive](archive.md) an outdated or unsupported repository.
- [Delete](delete.md) a repository.


---

# Archive or unarchive a repository

*Sección: Docker Hub*

You can archive a repository on Docker Hub to mark it as read-only and indicate
that it's no longer actively maintained. This helps prevent the use of outdated
or unsupported images in workflows. Archived repositories can also be unarchived
if needed.

Docker Hub highlights repositories that haven't been updated in over a year by
displaying an icon ({{< inline-image src="./images/outdated-icon.webp"
alt="outdated icon" >}}) next to them on the [**Repositories**
page](https://hub.docker.com/repositories/). Consider reviewing these
highlighted repositories and archiving them if necessary.

When a repository is archived, the following occurs:

- The repository information can't be modified.
- New images can't be pushed to the repository.
- An **Archived** label is displayed on the public repository page.
- Users can still pull the images.

You can unarchive an archived repository to remove the archived state. When
unarchived, the following occurs:

- The repository information can be modified.
- New images can be pushed to the repository.
- The **Archived** label is removed on the public repository page.

## Archive a repository

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Select **Archive repository**.
6. Enter the name of your repository to confirm.
7. Select **Archive**.

## Unarchive a repository

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Select **Unarchive repository**.


---

# Create a repository

*Sección: Docker Hub*

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.
3. Near the top-right corner, select **Create repository**.
4. Select a **Namespace**.

   You can choose to locate it under your own user account, or under any
   organization where you are an owner or editor.

5. Specify the **Repository Name**.

   The repository name needs to:
    - Be unique
    - Have between 2 and 255 characters
    - Only contain lowercase letters, numbers, hyphens (`-`), and underscores
      (`_`)

   > [!NOTE]
   >
   > You can't rename a Docker Hub repository once it's created.

6. Specify the **Short description**.

   The description can be up to 100 characters. It appears in search results.

7. Select the default visibility.

   - **Public**: The repository appears in Docker Hub search results and can be
     pulled by everyone.
   - **Private**: The repository doesn't appear in Docker Hub search results and
     is only accessible to you and collaborators. In addition, if you selected
     an organization's namespace, then the repository is accessible to those
     with applicable roles or permissions. For more details, see [Roles and
     permissions](/manuals/security/roles-and-permissions.md).

   > [!NOTE]
   >
   > For organizations creating a new repository, if you're unsure which
   > visibility to choose, then Docker recommends that you select **Private**.

8. Select **Create**.

After the repository is created, the **General** page appears. You are now able to manage:

- [Repository information](manage/information.md)
- [Access](manage/access.md)
- [Images](manage/hub-images/index.md)
- [Automated builds](manage/builds/index.md)
- [Webhooks](manage/webhooks.md)
- [Image security insights](manage/vulnerability-scanning.md)


---

# Delete a repository

*Sección: Docker Hub*

> [!WARNING]
>
> Deleting a repository deletes all the images it contains and its build
> settings. This action can't be undone.

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Select **Delete repository**.
6. Enter the name of your repository to confirm.
7. Select **Delete Repository Forever**.


---

# Manage

*Sección: Docker Hub*




---

# Access management

*Sección: Docker Hub*

In this topic learn about the features available to manage access to your
repositories. This includes visibility, collaborators, roles, teams, and
organization access tokens.

## Repository visibility

The most basic repository access is controlled via the visibility. A
repository's visibility can be public or private.

With public visibility, the repository appears in Docker Hub search results and
can be pulled by everyone. To manage push access to public personal
repositories, you can use collaborators. To manage push access to public
organization repositories, you can use roles, teams, or organization access
tokens.

With private visibility, the repository doesn't appear in Docker Hub search
results and is only accessible to those with granted permission. To manage push
and pull access to private personal repositories, you can use collaborators. To
manage push and pull access to private organization repositories, you can use
roles, teams, or organization access tokens.

### Change repository visibility

When creating a repository in Docker Hub, you can set the repository visibility.
In addition, you can set the default repository visibility when a repository is
created in your personal repository settings. The following describes how to
change the visibility after the repository has been created.

To change repository visibility:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.
3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Under **Visibility settings**, select one of the following:

   - **Make public**: The repository appears in Docker Hub search results and can be
     pulled by everyone.
   - **Make private**: The repository doesn't appear in Docker Hub search results
     and is only accessible to you and collaborators. In addition, if the
     repository is in an organization's namespace, then the repository
     is accessible to those with applicable roles or permissions.

6. Type the repository's name to verify the change.
7. Select **Make public** or **Make private**.

## Collaborators

A collaborator is someone you want to give `push` and `pull` access to a
personal repository. Collaborators aren't able to perform any administrative
tasks such as deleting the repository or changing its visibility from private to
public. In addition, collaborators can't add other collaborators.

Only personal repositories can use collaborators. You can add unlimited
collaborators to public repositories, and Docker Pro accounts can add up to 1
collaborator on private repositories.

Organization repositories can't use collaborators, but can use member roles,
teams, or organization access tokens to manage access.

### Manage collaborators

1. Sign in to [Docker Hub](https://hub.docker.com).

2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Collaborators** tab.

5. Add or remove collaborators based on their Docker username.

You can choose collaborators and manage their access to a private
repository from that repository's **Settings** page.

## Organization roles

Organizations can use roles for individuals, giving them different
permissions in the organization. For more details, see [Roles and
permissions](/manuals/security/roles-and-permissions.md).

## Organization teams

Organizations can use teams. A team can be assigned fine-grained repository
access.

### Configure team repository permissions

You must create a team before you are able to configure repository permissions.
For more details, see [Create and manage a
team](../../../accounts/organization/manage/manage-a-team.md).

To configure team repository permissions:

1. Sign in to [Docker Hub](https://hub.docker.com).

2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Permissions** tab.

5. Add, modify, or remove a team's repository permissions.

   - Add: Specify the **Team**, select the **Permission**, and then select **Add**.
   - Modify: Specify the new permission next to the team.
   - Remove: Select the **Remove permission** icon next to the team.

## Organization access tokens (OATs)

Organizations can use OATs. OATs let you assign fine-grained repository access
permissions to tokens. For more details, see [Organization access
tokens](../../../security/access-tokens/organization-access-tokens.md).

## Gated distribution

{{< summary-bar feature_name="Gated distribution" >}}

Gated distribution allows publishers to securely share private container images
with external customers or partners, without giving them full organization
access or visibility into your teams, collaborators, or other repositories.
Content stays in private repositories, and external users can pull from them
without being added to your internal organization.

This feature is ideal for commercial software publishers who want to control who
can pull specific images while preserving a clean separation between internal
users and external consumers.

If you are interested in Gated Distribution contact the <a
href="https://www.docker.com/pricing/contact-sales/"
id="dkr_docs_cs_hub_gated_distribution" class="link" rel="noopener">Docker Sales
Team</a> for more information.

### Distributor members

When you invite users to an organization entitled with gated distribution, you
assign them a role that determines their level of access. For gated
distribution, external users are invited as **distributor members** within a
specific team that you create. This role grants pull-only access to the
repositories assigned to that team, and nothing else in your organization. See
[Roles and permissions](/manuals/security/roles-and-permissions.md)
for details about the access permissions for other roles.

Distributor members can't see other members in their team or organization, and
they can't see any repositories other than the ones their team has been granted
access to. This isolation is what makes the role suitable for distributing gated
images to external users, partners, or customers without exposing internal
collaborators, teams, or repositories.

Because distributor members consume licenses allocated for that role, consider
provisioning a separate organization for gated distribution rather than adding
distributor members to your main organization. This keeps regular members from
inadvertently consuming the licenses set aside for external distribution.

### Invite distributor members via API

Distributor members can only be invited using the Docker Hub API. UI-based
invitations are not supported for this role.

To invite distributor members:

1. Use the [authentication
   API](https://docs.docker.com/reference/api/hub/latest/#tag/authentication-api/operation/AuthCreateAccessToken)
   to generate a bearer token for your Docker Hub account. This token authorizes
   the API requests you use to send invites. Replace `myusername` and
   `dckr_pat_...` with your Docker ID and a [personal access
   token](/manuals/security/access-tokens.md):

   ```console
   $ TOKEN=$(curl -s -X POST "https://hub.docker.com/v2/auth/token" \
       -H "Content-Type: application/json" \
       -d '{"identifier": "myusername", "secret": "dckr_pat_..."}' \
       | jq -r .access_token)
   ```

2. Create a team to group the distributor members and assign them a shared set
   of repository permissions.

   {{< tabs >}}
   {{< tab name="Hub" >}}

   1. Sign in to [Docker Home](https://app.docker.com) and select your
      organization.
   2. Select **Teams**.
   3. Select **Create team**.
   4. Provide the team's information, then select **Create**.

   For more details, see [Create and manage a
   team](../../../accounts/organization/manage/manage-a-team.md).

   {{< /tab >}}
   {{< tab name="API" >}}

   Use the [teams
   API](https://docs.docker.com/reference/api/hub/latest/#tag/groups/paths/~1v2~1orgs~1%7Borg_name%7D~1groups/post):

   ```console
   $ curl -s -X POST "https://hub.docker.com/v2/orgs/example-org/groups" \
       -H "Authorization: Bearer $TOKEN" \
       -H "Content-Type: application/json" \
       -d '{"name": "customer-team", "description": "External distributor members"}'
   ```

   The response includes the new team's `id`. Save it for the next step, for
   example `GROUP_ID=12345`.

   {{< /tab >}}
   {{< /tabs >}}

3. Grant the team read-only access to the repositories you want distributor
   members to access.

   {{< tabs >}}
   {{< tab name="Hub" >}}

   1. Sign in to [Docker Hub](https://hub.docker.com).
   2. Select **My Hub** > **Repositories**.
   3. Select the repository.
   4. Select the **Permissions** tab.
   5. Specify the **Team**, select **Read-only** as the **Permission**, and
      then select **Add**.

   {{< /tab >}}
   {{< tab name="API" >}}

   Use the [repository teams
   API](https://docs.docker.com/reference/api/hub/latest/#tag/repositories/operation/CreateRepositoryGroup),
   passing the team's `id` from the previous step as `group_id`:

   ```console
   $ curl -s -X POST "https://hub.docker.com/v2/repositories/example-org/example-repo/groups" \
       -H "Authorization: Bearer $TOKEN" \
       -H "Content-Type: application/json" \
       -d "{\"group_id\": $GROUP_ID, \"permission\": \"read\"}"
   ```

   {{< /tab >}}
   {{< /tabs >}}

4. Use the [bulk create invites
   endpoint](https://docs.docker.com/reference/api/hub/latest/#tag/invites/paths/~1v2~1invites~1bulk/post)
   to send email invites. In the request body, set `role` to
   `distributor_member`, specify the `team`, and list the invitees' email
   addresses:

   ```console
   $ curl -s -X POST "https://hub.docker.com/v2/invites/bulk" \
       -H "Authorization: Bearer $TOKEN" \
       -H "Content-Type: application/json" \
       -d '{
             "org": "example-org",
             "team": "customer-team",
             "role": "distributor_member",
             "invitees": ["user@example.com"]
           }'
   ```

   This sends email invitations to the specified users and automatically assigns
   them to the team.

5. The invited user receives an email invitation from Docker Hub. When they
   select the link in the email, they sign in with their Docker ID (or create
   one if needed) to accept the invite. Once accepted, they're added to the
   organization as a distributor member with pull-only access to the
   repositories assigned to their team.


---

# Automated builds

*Sección: Docker Hub*

{{< summary-bar feature_name="Automated builds" >}}

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

Docker Hub can automatically build images from source code in an external
repository and automatically push the built image to your Docker repositories.

![An automated build dashboard](images/index-dashboard.png)

When you set up automated builds, also called autobuilds, you create a list of
branches and tags that you want to build into Docker images. When you push code
to a source-code branch, for example in GitHub, for one of those listed image
tags, the push uses a webhook to trigger a new build, which produces a Docker
image. The built image is then pushed to Docker Hub.

> [!NOTE]
>
> You can still use `docker push` to push pre-built images to
repositories with automated builds configured.

If you have automated tests configured, these run after building, but before
pushing to the registry. You can use these tests to create a continuous
integration workflow where a build that fails its tests doesn't push the built
image. Automated tests don't push images to the registry on their own. [Learn about automated image testing](automated-testing.md).

Depending on your [subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsHubRepoBuilds),
you may get concurrent builds, which means that `N` autobuilds can be run at the
same time. `N` is configured according to your subscription. Once `N+1` builds
are running, any additional builds go into a queue to be run later.

The maximum number of pending builds in the queue is 30 and Docker Hub discards further
requests. The number of concurrent builds for Pro is 5 and
for Team and Business is 15.
Automated builds can handle images of up to 10 GB in size.


---

# Advanced options for autobuild and autotest

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

> [!NOTE]
>
> Automated builds require a
> Docker Pro, Team, or Business subscription.

The following options allow you to customize your automated build and automated
test processes.

## Environment variables for building and testing

Several utility environment variables are set by the build process, and are
available during automated builds, automated tests, and while executing
hooks.

> [!NOTE]
>
> These environment variables are only available to the build and test
processes and don't affect your service's run environment.

* `SOURCE_BRANCH`: the name of the branch or the tag that is currently being tested.
* `SOURCE_COMMIT`: the SHA1 hash of the commit being tested.
* `COMMIT_MSG`: the message from the commit being tested and built.
* `DOCKER_REPO`: the name of the Docker repository being built.
* `DOCKERFILE_PATH`: the Dockerfile currently being built.
* `DOCKER_TAG`: the Docker repository tag being built.
* `IMAGE_NAME`: the name and tag of the Docker repository being built. (This variable is a combination of `DOCKER_REPO`:`DOCKER_TAG`.)

If you are using these build environment variables in a
`docker-compose.test.yml` file for automated testing, declare them in your `sut`
service's environment as shown below.

```yaml
services:
  sut:
    build: .
    command: run_tests.sh
    environment:
      - SOURCE_BRANCH
```


## Override build, test or push commands

Docker Hub allows you to override and customize the `build`, `test` and `push`
commands during automated build and test processes using hooks. For example, you
might use a build hook to set build arguments used only during the build
process. You can also set up [custom build phase hooks](#custom-build-phase-hooks)
to perform actions in between these commands.

> [!IMPORTANT]
>
>Use these hooks with caution. The contents of these hook files replace the
basic `docker` commands, so you must include a similar build, test or push
command in the hook or your automated process does not complete.

To override these phases, create a folder called `hooks` in your source code
repository at the same directory level as your Dockerfile. Create a file called
`hooks/build`, `hooks/test`, or `hooks/push` and include commands that the
builder process can execute, such as `docker` and `bash` commands (prefixed
appropriately with `#!/bin/bash`).

These hooks run on an instance of [Ubuntu](https://releases.ubuntu.com/),
which includes interpreters
such as Perl or Python, and utilities such as `git` or `curl`. Refer to the
[Ubuntu documentation](https://ubuntu.com/)
for the full list of available interpreters and utilities.

## Custom build phase hooks

You can run custom commands between phases of the build process by creating
hooks. Hooks allow you to provide extra instructions to the autobuild and
autotest processes.

Create a folder called `hooks` in your source code repository at the same
directory level as your Dockerfile. Place files that define the hooks in that
folder. Hook files can include both `docker` commands, and `bash` commands as
long as they are prefixed appropriately with `#!/bin/bash`. The builder executes
the commands in the files before and after each step.

The following hooks are available:

* `hooks/post_checkout`
* `hooks/pre_build`
* `hooks/post_build`
* `hooks/pre_test`
* `hooks/post_test`
* `hooks/pre_push` (only used when executing a build rule or [Automated build](../../../../reference/api/ai-governance/index.md) )
* `hooks/post_push` (only used when executing a build rule or [Automated build](../../../../reference/api/ai-governance/index.md) )

### Build hook examples

#### Override the "build" phase to set variables

Docker Hub allows you to define build environment variables either in the hook
files, or from the automated build interface, which you can then reference in hooks.

The following example defines a build hook that uses `docker build` arguments to
set the variable `CUSTOM` based on the value of variable defined using the
Docker Hub build settings. `$DOCKERFILE_PATH` is a variable that you provide
with the name of the Dockerfile you want to build, and `$IMAGE_NAME` is the name
of the image being built.

```console
$ docker build --build-arg CUSTOM=$VAR -f $DOCKERFILE_PATH -t $IMAGE_NAME .
```

> [!IMPORTANT]
>
> A `hooks/build` file overrides the basic `docker build` command used by the builder, so you must include a similar build command in the hook or
the automated build fails.

Refer to the [docker build documentation](/reference/cli/docker/buildx/build/#build-arg)
to learn more about Docker build-time variables.

#### Push to multiple repositories

By default the build process pushes the image only to the repository where the
build settings are configured. If you need to push the same image to multiple
repositories, you can set up a `post_push` hook to add additional tags and push
to more repositories.

```console
$ docker tag $IMAGE_NAME $DOCKER_REPO:$SOURCE_COMMIT
$ docker push $DOCKER_REPO:$SOURCE_COMMIT
```

## Source repository or branch clones

When Docker Hub pulls a branch from a source code repository, it performs
a shallow clone, it clones only the tip of the specified branch. This has the advantage
of minimizing the amount of data transfer necessary from the repository and
speeding up the build because it pulls only the minimal code necessary.

As a result, if you need to perform a custom action that relies on a different
branch, such as a `post_push` hook, you can't checkout that branch unless
you do one of the following:

* You can get a shallow checkout of the target branch by doing the following:

    ```console
    $ git fetch origin branch:mytargetbranch --depth 1
    ```

* You can also "unshallow" the clone, which fetches the whole Git history (and
  potentially takes a long time / moves a lot of data) by using the `--unshallow`
  flag on the fetch:

    ```console
    $ git fetch --unshallow origin
    ```


---

# Automated repository tests

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

> [!NOTE]
>
> Automated builds require a
> Docker Pro, Team, or Business subscription.

Docker Hub can automatically test changes to your source code repositories
using containers. You can enable `Autotest` on any Docker Hub repository
to run tests on each pull request to the source code repository to create a
continuous integration testing service.

Enabling `Autotest` builds an image for testing purposes, but does not
automatically push the built image to the Docker repository. If you want to push
built images to your Docker Hub repository, enable [Automated Builds](../../../../reference/api/ai-governance/index.md).

## Set up automated test files

To set up your automated tests, create a `docker-compose.test.yml` file which
defines a `sut` service that lists the tests to be run.
The `docker-compose.test.yml` file should be located in the same directory that
contains the Dockerfile used to build the image.

For example:

```yaml
services:
  sut:
    build: .
    command: run_tests.sh
```

The previous example builds the repository, and runs the `run_tests.sh` file inside
a container using the built image.

You can define any number of linked services in this file. The only requirement
is that `sut` is defined. Its return code determines if tests passed or not.
Tests pass if the `sut` service returns `0`, and fail otherwise.

> [!NOTE]
> 
> Only the `sut` service and all other services listed in
> [`depends_on`](../../../../reference/compose-file/services.md#depends_on) are
> started. If you have services that poll for changes in other services, be sure
> to include the polling services in the [`depends_on`](../../../../reference/compose-file/services.md#depends_on)
> list to make sure all of your services start.

You can define more than one `docker-compose.test.yml` file if needed. Any file
that ends in `.test.yml` is used for testing, and the tests run sequentially.
You can also use [custom build hooks](advanced.md#override-build-test-or-push-commands)
to further customize your test behavior.

> [!NOTE]
>
> If you enable automated builds, they also run any tests defined
in the `test.yml` files.

## Enable automated tests on a repository

To enable testing on a source code repository, you must first create an
associated build-repository in Docker Hub. Your `Autotest` settings are
configured on the same page as [automated builds](../../../../reference/api/ai-governance/index.md), however
you do not need to enable autobuilds to use autotest. Autobuild is enabled per
branch or tag, and you do not need to enable it at all.

Only branches that are configured to use autobuild push images to the
Docker repository, regardless of the Autotest settings.

1. Sign in to Docker Hub and select **My Hub** > **Repositories**.

2. Select the repository you want to enable `Autotest` on.

3. From the repository view, select the **Builds** tab.

4. Select **Configure automated builds**.

5. Configure the automated build settings as explained in [Automated builds](../../../../reference/api/ai-governance/index.md).

    At minimum you must configure:

    * The source code repository
    * The build location
    * At least one build rule

6. Choose your **Autotest** option.

    The following options are available:

    * `Off`: No additional test builds. Tests only run if they're configured
    as part of an automated build.

    * `Internal pull requests`: Run a test build for any pull requests
    to branches that match a build rule, but only when the pull request comes
    from the same source repository.

    * `Internal and external pull requests`: Run a test build for any
    pull requests to branches that match a build rule, including when the
    pull request originated in an external source repository.

    > [!IMPORTANT]
    >
    >For security purposes, autotest on external pull requests is
    limited on public repositories. Private images are not pulled and
    environment variables defined in Docker Hub are not
    available. Automated builds continue to work as usual.

7. Select **Save** to save the settings, or select **Save and build** to save and
run an initial test.

## Check your test results

From the repository's details page, select **Timeline**.

From this tab you can see any pending, in-progress, successful, and failed
builds and test runs for the repository.

You can choose any timeline entry to view the logs for each test run.


---

# Configure automated builds from GitHub and BitBucket

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

> [!NOTE]
>
> Automated builds require a Docker Pro, Team, or Business subscription.


To automate building and testing of your images, you link to your hosted source
code service to Docker Hub so that it can access your source code
repositories. You can configure this link for user accounts or
organizations.

If you are linking a source code provider to create autobuilds for a team, follow the instructions to [create a service account](setup.md#service-users-for-team-autobuilds) for the team before linking the account as described below.

## Link to a GitHub user account

1. Sign in to Docker Hub.

2. Select **My Hub** > **Settings** > **Linked accounts**.

3. Select **Link provider** for the source provider you want to link.

    If you want to unlink your current GitHub account and relink to a new GitHub account, make sure to completely sign out of [GitHub](https://github.com/) before linking via Docker Hub.


4. Review the settings for the **Docker Hub Builder** OAuth application.

    ![Granting access to GitHub account](images/authorize-builder.png)

    > [!NOTE]
    >
    > If you are the owner of any GitHub organizations, you might see
    options to grant Docker Hub access to them from this screen. You can also
    individually edit an organization's third-party access settings to grant or
    revoke Docker Hub's access. See
    [Grant access to a GitHub organization](link-source.md#grant-access-to-a-github-organization)
    to learn more.

5. Select **Authorize docker** to save the link.

### Grant access to a GitHub organization

If you are the owner of a GitHub organization, you can grant or revoke Docker
Hub's access to the organization's repositories. Depending on the GitHub
organization's settings, you may need to be an organization owner.

If the organization has not had specific access granted or revoked before, you
can often grant access at the same time as you link your user account. In this
case, a **Grant access** button appears next to the organization name in the
link accounts screen, as shown below. If this button does not appear, you must
manually grant the application's access.

To manually grant Docker Hub access to a GitHub organization:

1. Link your user account using the instructions above.

2. From your GitHub Account settings, locate the **Organization settings**
section at the lower left.

3. Select the organization you want to give Docker Hub access to.

4. Select **Third-party access**.

    The page displays a list of third party applications and their access
    status.

5. Select the pencil icon next to **Docker Hub Builder**.

6. Select **Grant access** next to the organization.

### Revoke access to a GitHub organization

To revoke Docker Hub's access to an organization's GitHub repositories:

1. From your GitHub Account settings, locate the **Organization settings** section at the lower left.

2. Select the organization you want to revoke Docker Hub's access to.

3. From the Organization Profile menu, select **Third-party access**.
    The page displays a list of third party applications and their access status.

4. Select the pencil icon next to Docker Hub Builder.

5. On the next page, select **Deny access**.

### Unlink a GitHub user account

To revoke Docker Hub's access to your GitHub account, you must unlink it both
from Docker Hub, and from your GitHub account.

1. Select **My Hub** > **Settings** > **Linked accounts**.

2. Select **Unlink provider** next to the source provider you want to remove.

3. Go to your GitHub account's **Settings** page.

4. Select **Applications** in the left navigation bar.

5. Select the `...` menu to the right of the Docker Hub Builder application and select **Revoke**.

> [!NOTE]
>
> Each repository that is configured as an automated build source
contains a webhook that notifies Docker Hub of changes in the repository.
This webhook is not automatically removed when you revoke access to a source
code provider.

## Link to a Bitbucket user account

1. Sign in to Docker Hub using your Docker ID.

2. Select **My Hub** > **Settings** > **Linked accounts**.

3. Select **Link provider** for the source provider you want to link.

4. If necessary, sign in to Bitbucket.

5. On the page that appears, select **Grant access**.

### Unlink a Bitbucket user account

To permanently revoke Docker Hub's access to your Bitbucket account, you must
unlink it both from Docker Hub, and revoke authorization in your Bitbucket account.

1. Sign in to Docker Hub.

2. Select **My Hub** > **Settings** > **Linked accounts**.

3. Select **Unlink provider** next to the source provider you want to remove.

> [!IMPORTANT]
> After unlinking the account on Docker Hub, you must also revoke the authorization on the Bitbucket end.

To revoke authorization in your Bitbucket account:

1. Go to your Bitbucket account and navigate to [**Bitbucket settings**](https://bitbucket.org/account/settings/app-authorizations/).

2. On the page that appears, select **OAuth**.

3. Select **Revoke** next to the Docker Hub line.

![Bitbucket Authorization revocation page](images/bitbucket-revoke.png)

> [!NOTE]
>
> Each repository that is configured as an automated build source
contains a webhook that notifies Docker Hub of changes in the repository. This
webhook is not automatically removed when you revoke access to a source code
provider.


---

# Manage autobuilds

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

> [!NOTE]
>
> Automated builds require a Docker Pro, Team, or Business subscription.


## Cancel or retry a build

While a build is in queue or running, a **Cancel** icon appears next to its build
report link on the **General** tab and on the **Builds** tab. You can also select
**Cancel** on the **Build report** page, or from the **Timeline** tab's logs
display for the build.

![List of builds showing the cancel icon](images/build-cancelicon.png)

## Check your active builds

A summary of a repository's builds appears both on the repository **General**
tab, and in the **Builds** tab. The **Builds** tab also displays a color coded
bar chart of the build queue times and durations. Both views display the
pending, in progress, successful, and failed builds for any tag of the
repository.

![Active builds](images/index-active.png)

From either location, you can select a build job to view its build report. The
build report shows information about the build job. This includes the source
repository and branch, or tag, the build logs, the build duration, creation time and location, and the user account the build occurred in.

> [!NOTE]
>
> You can now view the progress of your builds every 30 seconds when you refresh the **Builds** page. With the in-progress build logs, you can debug your builds before they're finished.

![Build report](./images/index-report.png)

## Disable an automated build

Automated builds are enabled per branch or tag, and can be disabled and
re-enabled. You might do this when you want to only build manually for
a while, for example when you are doing major refactoring in your code. Disabling autobuilds doesn't disable [autotests](automated-testing.md).

To disable an automated build:

1. In [Docker Hub](https://hub.docker.com), go to **My Hub** >  **Repositories**, select a repository, and select the **Builds** tab.

2. Select **Configure automated builds** to edit the repository's build settings.

3. In the **Build Rules** section, locate the branch or tag you no longer want
to automatically build.

4. Select the **Autobuild** toggle next to the configuration line. When disabled the toggle is gray.

5. Select **Save**.


---

# Migrate from Autobuilds

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.

This guide explains how to migrate your Docker Hub Autobuilds setup to
Continuous Integration (CI) workflows, focusing on GitHub Actions and Bitbucket
Pipelines as these are the built-in CI services for the two version control
services supported via Autobuilds.

## Step 1: Create access tokens

To grant your CI workflows the ability to pull and push images to and from
Docker Hub, you first need to create access tokens:

- For a personal repository: Create a [Personal
  Access Token](../../../../security/access-tokens/personal-access-tokens.md) with **Read & Write**
  permissions.

- For an organization repository: Create an [Organization Access
  Token](../../../../security/access-tokens/organization-access-tokens.md) with the following
  permissions:
  - **Read public repositories**
  - **Image Pull** on any private repositories that the build needs to pull from
  - **Image Push** on the repository that the built image will be pushed to

The same token can be used for all CI workflows under the account's namespace
provided it has adequate permissions to all relevant Docker Hub repositories.

Store the token securely in a password manager or your CI/CD platform's secrets
manager. Never commit tokens to source code repositories.

## Step 2: Extract your Autobuilds configuration

For each Docker Hub repository currently configured to use Autobuilds, you need
to extract its configuration to set up your CI workflows to duplicate the
existing functionality. The only way to extract the configuration is via the
Docker Hub web interface.

1. Sign in to [Docker Hub](https://hub.docker.com).

2. Navigate to your repository by going to **My Hub** > ***Your namespace*** >
   **Repositories** > ***Your Repository***.

3. Go to the **Builds** tab and select **Configure automated builds**.

   If there is no existing build configuration, then this repository is not
   configured for Autobuilds.

4. Note the following configuration details:

   - **Source Repository**: The GitHub or Bitbucket repository. The organization
     is the namespace and the repository is the repository name. This is where
     you need to add your workflow.

   - **Autotest**: If Autotest is enabled for Pull Requests (either internal
     only or internal and external), then extra steps are needed in your
     workflow to run the Autotest step.

   - **Repository Links**: Not supported and can be ignored. If chain builds are
     required, see the documentation for your CI service on how to chain builds
     together.

   - **Build Rules**: Specify the triggers, tags, and paths of your builds.
     Ignore any entry where **Autobuild** is toggled off.

   - **Build Environment Variables**: User-defined variables injected as
     environment variables into your build. You need to add these to your
     workflow. If the environment variables contain secrets, add them to your CI
     service's secrets manager. Then update your Dockerfile or build scripts to
     reference these secrets using your CI platform's syntax. See your CI
     service documentation on how to handle secrets.

### Example configuration

The following image shows an example Autobuilds configuration.

![Example Autobuilds configuration](./images/autobuild-example.png)

Based on the pictured example, you would note the following items for this
Autobuilds configuration:

- Source code repository: GitHub repository `docker/docker-rust-hello`
- Autotest: Disabled
- Build rule 1: Build and push the image with tag `latest` when a new commit to
  the `main` branch is detected. The Dockerfile is at `./Dockerfile` and the
  build context is the root of the cloned code.
- Build rule 2: Build and push the image with tag `v{\1}` when a new commit
  to a tag matching the regex `^v([0-9.]+)$` is detected. The Dockerfile is at
  `./Dockerfile` and the build context is the root of the cloned code.
- Environment variable: Key `ENV_KEY` with value `ENV_VALUE`

## Step 3: Migrate to your CI/CD platform

Select the tab that matches your source code repository hosting platform.

{{< tabs >}}
{{< tab name="GitHub Actions" >}}

If your source code repository is hosted on GitHub, see the [Docker
Autobuilds example repository](https://github.com/docker/autobuilds-actions).

All files except those under the `.github/workflows` directory are for example
purposes only.

The repository's readme details how to migrate from Autobuilds to GitHub Actions
using one of the two provided workflows:

- The `simple-build` workflow builds and pushes a Docker image to your Docker
  Hub repository.
- The `full-autobuilds` workflow contains all the steps commonly used within an
  Autobuilds run, including building, tagging, running Docker Compose tests, and
  running optional bash hook files.

### Steps to migrate

1. Follow the instructions in the [example repository
   readme](https://github.com/docker/autobuilds-actions) to configure a CI GitHub
   Action workflow in your GitHub repository.

2. The workflows contain comments on what each step does and where changes
   should be made. Important changes to make include:

   - Set the `DOCKER_REPOSITORY_NAME` environment variable to the full name of your Docker Hub repository
   - Set your image tagging policy
   - Set the workflow triggers

   Links to relevant documentation are provided in the readme and the workflow comments.

3. After you have completed migrating to GitHub Actions, delete the build
   configuration from your Docker Hub repository:

   1. Navigate to the repository's **Builds** tab.

   2. Select **Configure automated builds**.

   3. Select **Delete Build Configuration**.

{{< /tab >}}
{{< tab name="Bitbucket Pipelines" >}}

If your source code repository is hosted on Bitbucket, see the [Docker
Autobuilds Bitbucket example
repository](https://bitbucket.org/docker-io/autobuilds-pipeline).

All files except the `bitbucket-pipelines.yml` file are for example purposes only.

The repository's readme details how to migrate from Autobuilds to Bitbucket
Pipelines using the provided example `bitbucket-pipelines.yml` configuration
file.

The pipeline example contains three separate pipelines:

- `branches/main`: Shows how to build, test, and push an image on changes to a specific branch
- `tags/*`: Shows how to build, test, and push an image on tag pushes, including
  tagging the image the same as the Git tag
- `pull-requests/*`: Shows how to build and test, but not push, an image from a pull request

### Steps to migrate

1. Follow the instructions in the [example repository
   readme](https://bitbucket.org/docker-io/autobuilds-pipeline) to configure
   a Bitbucket Pipeline in your Bitbucket repository.

2. Comments in the pipeline configuration explain what each part does and where
   changes need to be made. Important changes to make include:

   - Set the `DOCKER_REPOSITORY_NAME` environment variable to the full name of
     your Docker Hub repository
   - Set your image tagging policy (see where the `DOCKER_TAG` variable is set in each pipeline)
   - Set the pipeline triggers for branches, tags, and/or pull-requests

   Links to relevant documentation are provided in the readme and the workflow comments.

3. After you have completed migrating to Bitbucket Pipelines, delete the Build
   configuration from your Docker Hub repository:

   1. Navigate to the repository's **Builds** tab.

   2. Select **Configure automated builds**.

   3. Select **Delete Build Configuration**.

{{< /tab >}}
{{< /tabs >}}


---

# Set up automated builds

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

> [!NOTE]
>
> Automated builds require a
> Docker Pro, Team, or Business subscription.

## Configure automated builds

You can configure repositories in Docker Hub so that they automatically
build an image each time you push new code to your source provider. If you have
[automated tests](automated-testing.md) configured, the new image is only pushed
when the tests succeed.

1. In [Docker Hub](https://hub.docker.com), go to **My Hub** > **Repositories**, and select a repository to view its details.

2. Select the **Builds** tab.

3. Select either GitHub or Bitbucket to connect where the image's source code is stored.

   > [!NOTE]
   >
   > You may be redirected to the settings page to [link the code repository
   > service](link-source.md). Otherwise, if you are editing the build settings
   > for an existing automated build, select **Configure automated builds**.

4. Select the **source repository** to build the Docker images from.

   > [!NOTE]
   >
   > You might need to specify an organization or user from
   > the source code provider. Once you select a user, source code
   > repositories appear in the **Select repository** drop-down list.

5. Optional. Enable [autotests](automated-testing.md#enable-automated-tests-on-a-repository).

6. Review the default **Build Rules**.

    Build rules control what Docker Hub builds into images from the contents
    of the source code repository, and how the resulting images are tagged
    within the Docker repository.

    A default build rule is set up for you, which you can edit or delete. This
    default rule sets builds from the `Branch` in your source code repository
    called `master` or `main`, and creates a Docker image tagged with `latest`.
    For more information, see [set up build rules](#set-up-build-rules).

7. Optional. Select the **plus** icon to add and [configure more build rules](#set-up-build-rules).

8. For each branch or tag, enable or disable the **Autobuild** toggle.

    Only branches or tags with autobuild enabled are built, tested, and have
    the resulting image pushed to the repository. Branches with autobuild
    disabled are built for test purposes (if enabled at the repository
    level), but the built Docker image isn't pushed to the repository.

9. For each branch or tag, enable or disable the **Build Caching** toggle.

    [Build caching](../../../../build/building/best-practices.md#leverage-build-cache)
    can save time if you are building a large image frequently or have
    many dependencies. Leave the build caching disabled to
    make sure all of your dependencies are resolved at build time, or if
    you have a large layer that's quicker to build locally.

10. Select **Save** to save the settings, or select **Save and build** to save and
   run an initial test.

    > [!NOTE]
    >
    > A webhook is automatically added to your source code repository to notify
    > Docker Hub on every push. Only pushes to branches that are listed as the
    > source for one or more tags, trigger a build.

### Set up build rules

By default when you set up automated builds, a basic build rule is created for you.
This default rule watches for changes to the `master` or `main` branch in your source code
repository, and builds the `master` or `main` branch into a Docker image tagged with
`latest`.

In the **Build Rules** section, enter one or more sources to build.

For each source:

* Select the **Source type** to build either a tag or a branch. This
  tells the build system what to look for in the source code repository.

* Enter the name of the **Source** branch or tag you want to build.

  The first time you configure automated builds, a default build rule is set up
  for you. This default set builds from the `Branch` in your source code called
  `master`, and creates a Docker image tagged with `latest`.

  You can also use a regex to select which source branches or tags to build.
  To learn more, see
  [regexes](#regexes-and-automated-builds).

* Enter the tag to apply to Docker images built from this source.

  If you configured a regex to select the source, you can reference the
  capture groups and use its result as part of the tag. To learn more, see
  [regexes](#regexes-and-automated-builds).

* Specify the **Dockerfile location** as a path relative to the root of the source code repository. If the Dockerfile is at the repository root, leave this path set to `/`.

> [!NOTE]
>
> When Docker Hub pulls a branch from a source code repository, it performs a
> shallow clone - only the tip of the specified branch. Refer to
> [Advanced options for autobuild and autotest](advanced.md#source-repository-or-branch-clones)
> for more information.

### Environment variables for builds

You can set the values for environment variables used in your build processes
when you configure an automated build. Add your build environment variables by
selecting the **plus** icon next to the **Build environment variables** section, and
then entering a variable name and the value.

When you set variable values from the Docker Hub UI, you can use them by the
commands you set in `hooks` files. However, they're stored so that only users who have `admin` access to the Docker Hub repository can see their values. This
means you can use them to store access tokens or other information that
should remain secret.

> [!NOTE]
>
> The variables set on the build configuration screen are used during
> the build processes only and shouldn't get confused with the environment
> values used by your service, for example to create service links.

## Advanced automated build options

At the minimum you need a build rule composed of a source branch, or tag, and a
destination Docker tag to set up an automated build. You can also:

- Change where the build looks for the Dockerfile
- Set a path to the files the build should use (the build context)
- Set up multiple static tags or branches to build from
- Use regular expressions (regexes) to dynamically select source code to build and
create dynamic tags

All of these options are available from the **Build configuration** screen for
each repository. In [Docker Hub](https://hub.docker.com), select **My Hub** > **Repositories**, and select the name of the repository you want to edit. Select the **Builds** tab, and then select **Configure Automated builds**.

### Tag and branch builds

You can configure your automated builds so that pushes to specific branches or tags trigger a build.

1. In the **Build Rules** section, select the **plus** icon to add more sources to build.

2.  Select the **Source type** to build either a tag or a branch.

    > [!NOTE]
    >
    > This tells the build system what type of source to look for in the code
    > repository.

3. Enter the name of the **Source** branch or tag you want to build.

    > [!NOTE]
    >
    > You can enter a name, or use a regex to match which source branch or tag
    > names to build. To learn more, see [regexes](#regexes-and-automated-builds).

4. Enter the tag to apply to Docker images built from this source.

   > [!NOTE]
   >
   > If you configured a regex to select the source, you can reference the
   > capture groups and use its result as part of the tag. To learn more, see
   > [regexes](#regexes-and-automated-builds).

5. Repeat steps 2 through 4 for each new build rule you set up.

### Set the build context and Dockerfile location

Depending on how you arrange the files in your source code repository, the
files required to build your images may not be at the repository root. If that's
the case, you can specify a path where the build looks for the files.

The build context is the path to the files needed for the build, relative to
the root of the repository. Enter the path to these files in the **Build context** field. Enter `/` to set the build context as the root of the source code repository.

> [!NOTE]
>
> If you delete the default path `/` from the **Build context** field and leave
> it blank, the build system uses the path to the Dockerfile as the build
> context. However, to avoid confusion it's recommended that you specify the
> complete path.

You can specify the **Dockerfile location** as a path relative to the build
context. If the Dockerfile is at the root of the build context path, leave the
Dockerfile path set to `/`. If the build context field is blank, set the path
to the Dockerfile from the root of the source repository.

### Regexes and automated builds

You can specify a regular expression (regex) so that only matching branches or
tags are built. You can also use the results of the regex to create the Docker
tag that's applied to the built image.

You can use up to nine regular expression capture groups, or expressions enclosed in parentheses, to select a source to build, and reference
these in the **Docker Tag** field using `{\1}` through `{\9}`.

<!-- Capture groups Not a priority
#### Regex example: build from version number branch and tag with version number

You could also use capture groups to build and label images that come from various
sources. For example, you might have

`/(alice|bob)-v([0-9.]+)/` -->

### Build images with BuildKit

Autobuilds use the BuildKit build system by default. If you want to use the legacy
Docker build system, add the [environment variable](../../../../reference/api/ai-governance/index.md#environment-variables-for-builds)
`DOCKER_BUILDKIT=0`. Refer to the [BuildKit](../../../../build/buildkit/index.md)
page for more information on BuildKit.

## Autobuild for teams

When you create an automated build repository in your own user account, you
can start, cancel, and retry builds, and edit and delete your own repositories.

These same actions are also available for team repositories from Docker Hub if
you are an owner. If you are a member of a
team with `write` permissions you can start, cancel, and retry builds in your
team's repositories, but you cannot edit the team repository settings or delete
the team repositories. If your user account has `read` permission, or if you're
a member of a team with `read` permission, you can view the build configuration
including any testing settings.

| Action/Permission     | Read | Write | Admin | Owner |
| --------------------- | ---- | ----- | ----- | ----- |
| view build details    |  x   |   x   |   x   |   x   |
| start, cancel, retry  |      |   x   |   x   |   x   |
| edit build settings   |      |       |   x   |   x   |
| delete build          |      |       |       |   x   |

### Service users for team autobuilds

> [!NOTE]
>
> Only owners can set up automated builds for teams.

When you set up automated builds for teams, you grant Docker Hub access to
your source code repositories using OAuth tied to a specific user account. This
means that Docker Hub has access to everything that the linked source provider
account can access.

For organizations and teams, it's recommended you create a dedicated service account to grant access to the source provider. This ensures that no
builds break as individual users' access permissions change, and that an
individual user's personal projects aren't exposed to an entire organization.

This service account should have access to any repositories to be built,
and must have administrative access to the source code repositories so it can
manage deploy keys. If needed, you can limit this account to only a specific
set of repositories required for a specific build.

If you are building repositories with linked private submodules (private
dependencies), you also need to add an override `SSH_PRIVATE` environment
variable to automated builds associated with the account. For more information, see [Troubleshoot](troubleshoot.md#build-repositories-with-linked-private-submodules)

1. Create a service user account on your source provider, and generate SSH keys for it.
2. Create a "build" team in your organization.
3. Ensure that the new "build" team has access to each repository and submodule you need to build.

    1. On GitHub or Bitbucket, go to the repository's **Settings** page.
    2. Add the new "build" team to the list of approved users.

        - GitHub: Add the team in **Collaborators and Teams**.
        - Bitbucket: Add the team in  **Access management**.

4. Add the service user to the "build" team on the source provider.

5. Sign in to Docker Hub as an owner, switch to the organization, and follow the instructions to [link to source code repository](link-source.md) using the service account.

    > [!NOTE]
    >
    > You may need to sign out of your individual account on the source code provider to create the link to the service account.

6. Optional. Use the SSH keys you generated to set up any builds with private submodules, using the service account and [the previous instructions](troubleshoot.md#build-repositories-with-linked-private-submodules).

## What's Next?

- [Customize your build process](advanced.md) with environment variables, hooks, and more
- [Add automated tests](automated-testing.md)
- [Manage your builds](manage-builds.md)
- [Troubleshoot](troubleshoot.md)


---

# Troubleshoot your autobuilds

*Sección: Docker Hub*

> [!WARNING]
> Docker Hub Automated Builds is a deprecated feature.
> It will be fully retired on April 1, 2027.
> See the [migration guide](migrate.md) to move to a supported CI/CD workflow.

> [!NOTE]
>
> Automated builds require a
> Docker Pro, Team, or Business subscription.

## Failing builds

If a build fails, a **Retry** icon appears next to the build report line on the
**General** and **Builds** tabs. The **Build report** page and **Timeline logs** also display a **Retry** button.

![Timeline view showing the retry build button](images/retry-build.png)

> [!NOTE]
>
> If you are viewing the build details for a repository that belongs to an
> organization, the **Cancel** and **Retry** buttons only appear if you have `Read & Write` access to the repository.

Automated builds have a 4-hour execution time limit. If a build reaches this time limit, it's
automatically cancelled, and the build logs display the following message:

```text
2022-11-02T17:42:27Z The build was cancelled or exceeded the maximum execution time.
```

This log message is the same as when you actively cancel a build. To identify
whether a build was automatically cancelled, check the build duration.


## Build repositories with linked private submodules

Docker Hub sets up a deploy key in your source code repository that allows it
to clone the repository and build it. This key only works for a single,
specific code repository. If your source code repository uses private Git
submodules, or requires that you clone other private repositories to build,
Docker Hub cannot access these additional repositories, your build cannot complete,
and an error is logged in your build timeline.

To work around this, you can set up your automated build using the `SSH_PRIVATE`
environment variable to override the deployment key and grant Docker Hub's build
system access to the repositories.

> [!NOTE]
>
> If you are using autobuild for teams, use the process below
> instead, and configure a service user for your source code provider. You can
> also do this for an individual account to limit Docker Hub's access to your
> source repositories.

1. Generate a SSH keypair that you use for builds only, and add the public key to your source code provider account.

    This step is optional, but allows you to revoke the build-only keypair without removing other access.

2. Copy the private half of the keypair to your clipboard.
3. In Docker Hub, navigate to the build page for the repository that has linked private submodules. (If necessary, [follow the steps here](../../../../reference/api/ai-governance/index.md#configure-automated-builds) to configure the automated build.)
4. At the bottom of the screen, select the **plus** icon next to **Build Environment variables**.
5. Enter `SSH_PRIVATE` as the name for the new environment variable.
6. Paste the private half of the keypair into the **Value** field.
7. Select **Save**, or **Save and Build** to validate that the build now completes.

> [!NOTE]
>
> You must configure your private git submodules using git clone over SSH
> (`git@submodule.tld:some-submodule.git`) rather than HTTPS.


---

# Export organization repositories to CSV

*Sección: Docker Hub*

This guide shows you how to export a complete list of repositories from your
Docker Hub organization, including private repositories. You'll use a
Personal Access Token (PAT) from an administrator account to authenticate with
the Docker Hub API and export repository details to a CSV file for reporting or
analysis.

The exported data includes repository name, visibility status, last updated
date, pull count, and star count.

## Prerequisites

Before you begin, ensure you have:

- Administrator access to a Docker Hub organization
- `curl` installed for making API requests
- `jq` installed for JSON parsing
- A spreadsheet application to view the CSV

## Create a personal access token

[Create a personal access token](/security/access-tokens/personal-access-tokens/) from
a user account that has access to the organization's repositories. When creating
the token, select at minimum **Read-only** access permissions to list
repositories.

> [!IMPORTANT]
>
> Use a PAT from a user account that is a member of the organization. Users
> with owner roles can export all organization repositories. Members can only
> export repositories they have permission to access.

## Authenticate with the Docker Hub API

Exchange your personal access token for a JWT bearer token that you'll use
for subsequent API requests.

1. Set your Docker Hub username, organization name, and personal access token as variables:

   ```bash
   USERNAME="<your-docker-username>"
   ORG="<org-name>"
   PAT="<your_personal_access_token>"
   ```

2. Call the authentication endpoint to get a JWT:

   ```bash
   TOKEN=$(
     curl -s https://hub.docker.com/v2/auth/token \
       -H 'Content-Type: application/json' \
       -d "{\"identifier\":\"$USERNAME\",\"secret\":\"$PAT\"}" \
     | jq -r '.access_token'
   )
   ```

3. Verify the token was retrieved successfully:

   ```console
   $ echo "Got JWT: ${#TOKEN} chars"
   ```

You'll use this JWT as a Bearer token in the `Authorization` header for all
subsequent API calls.

## Retrieve all repositories

The Docker Hub API paginates repository lists. This script retrieves all pages
and combines the results.

1. Set the page size and initial API endpoint:

   ```bash
   PAGE_SIZE=100
   URL="https://hub.docker.com/v2/namespaces/$ORG/repositories?page_size=$PAGE_SIZE"
   ```

2. Paginate through all results:

   ```bash
   ALL=$(
     while [ -n "$URL" ] && [ "$URL" != "null" ]; do
       RESP=$(curl -s "$URL" -H "Authorization: Bearer $TOKEN")
       echo "$RESP" | jq -c '.results[]'
       URL=$(echo "$RESP" | jq -r '.next')
     done | jq -s '.'
   )
   ```

3. Verify the number of repositories retrieved:

   ```console
   $ echo "$ALL" | jq 'length'
   ```

The script continues requesting the `next` URL from each response until
pagination is complete.

## Export to CSV

Generate a CSV file with repository details that you can open in
spreadsheet applications.

Run the following command to create `repos.csv`:

```bash
echo "$ALL" | jq -r '
  (["namespace","name","is_private","last_updated","pull_count","star_count"] | @csv),
  (.[] | [
    .namespace, .name, .is_private, .last_updated, (.pull_count//0), (.star_count//0)
  ] | @csv)
' > repos.csv
```

Verify the export completed:

```console
$ echo "Rows:" $(wc -l < repos.csv)
```

Open the `repos.csv` file in your preferred
spreadsheet application to view and analyze your repository data.

## Troubleshooting

### Only public repositories appear

The Docker Hub account associated with your personal access token may not have
access to private repositories in the organization.

To fix this:

1. Verify the account is a member of the organization
2. Check that the account has appropriate permissions (owner or member role)
3. Ensure the personal access token has sufficient access permissions
4. Regenerate the JWT and retry the export

### API returns 403 or missing fields

Ensure you're using the JWT from the `/v2/auth/token` endpoint as a
Bearer token in the `Authorization` header, not the personal access
token directly.

Verify your authentication:

```console
$ curl -s "https://hub.docker.com/v2/namespaces/$ORG/repositories?page_size=1" \
  -H "Authorization: Bearer $TOKEN" | jq
```

If this returns an error, re-run the authentication step to get a fresh JWT.


---

# Image management

*Sección: Docker Hub*

Docker Hub provides powerful features for managing and organizing your
repository content, ensuring that your images and artifacts are accessible,
version-controlled, and easy to share. This section covers key image management
tasks, including tagging, pushing images, transferring images between
repositories, and supported software artifacts.


- [Tags](tags.md): Tags help you version and organize different iterations of
  your images within a single repository. This topic explains tagging and
  provides guidance on how to create, view, and delete tags in Docker Hub.
- [Image Management](manage.md): View, filter, and delete images and image
  indexes in your repository.
- [Software artifacts](oci-artifacts.md): Docker Hub supports OCI (Open
  Container Initiative) artifacts, allowing you to store, manage, and distribute
  a range of content beyond standard Docker images, including Helm charts,
  vulnerability reports, and more. This section provides an overview of OCI
  artifacts as well as some examples of pushing them to Docker Hub.
- [Push images to Hub](push.md): Docker Hub enables you to push local images
  to it, making them available for your team or the Docker community. Learn how
  to configure your images and use the `docker push` command to upload them to
  Docker Hub.
- [Move images between repositories](move.md): Organizing content across
  different repositories can help streamline collaboration and resource
  management. This topic details how to move images from one Docker Hub
  repository to another, whether for personal consolidation or to share images
  with an organization.


---

# Bulk migrate images

*Sección: Docker Hub*

This guide shows you how to migrate Docker images in bulk between Docker Hub
organizations or namespaces. Whether you're consolidating repositories, changing
organization structure, or moving images to a new account, these techniques help
you migrate efficiently while preserving image integrity.

The topic is structured to build up in scale:

1. [Migrate a single image tag](#migrate-a-single-image-tag)
2. [Migrate all tags for a repository](#migrate-all-tags-for-a-repository)
3. [Migrate multiple repositories](#migrate-multiple-repositories)

The recommended tool for this workflow is `crane`. An equivalent alternative
using `regctl` is also shown. Both tools perform registry-to-registry copies
without pulling images locally and preserve multi-architecture images.

`crane` is recommended for its simplicity and focused image-copying workflow.
`regctl` is also a good choice, particularly if you already use it for broader
registry management tasks beyond image copying.

> [!NOTE]
>
> The main workflows in this topic operate on tagged images only. Untagged
> manifests or content no longer reachable from tags are not migrated. In
> practice, these are usually unused artifacts, but be aware of this limitation
> before migration. While you can migrate specific untagged manifests using
> [digest references](#migrate-by-digest), there is no API to enumerate untagged
> manifests in a repository.

## Prerequisites

Before you begin, ensure you have:

- One of the following installed and available in your `$PATH`:
  - [`crane`](https://github.com/google/go-containerregistry)
  - [`regctl`](https://regclient.org/usage/regctl/)
- Push access to both the source and destination organizations
- Registry authentication configured for your chosen tool

## Authenticate to registries

Both tools authenticate directly against registries:

- `crane` uses Docker credential helpers and `~/.docker/config.json`. See the
  [crane documentation](https://github.com/google/go-containerregistry/tree/main/cmd/crane/doc).
- `regctl` uses its own configuration file and can import Docker credentials.
  See the [regctl documentation](https://github.com/regclient/regclient/tree/main/docs).

Follow the authentication instructions for your registry and tool of choice.

## Migrate a single image tag

This is the simplest and most common migration scenario.

The following example script copies the image manifest directly between
registries and preserves multi-architecture images when present. Repeat this
process for each tag you want to migrate. Replace the environment variable
values with your source and destination organization names, repository name, and
tag.

```bash
#!/usr/bin/env bash
set -euo pipefail

SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
TAG="1.2.3"

SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"

# Using crane (recommended)
crane cp "${SRC_IMAGE}" "${DEST_IMAGE}"

# Using regctl (alternative)
# regctl image copy "${SRC_IMAGE}" "${DEST_IMAGE}"
```

### Migrate by digest

To migrate a specific image by digest instead of tag, use the digest in the
source reference. This is useful when you need to migrate an exact image
version, even if the tag has been updated. Replace the environment variable
values with your source and destination organization names, repository name,
digest, and tag. You can choose between `crane` and `regctl` for the copy
operation.

```bash
#!/usr/bin/env bash
set -euo pipefail

SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
DIGEST="sha256:abcd1234..."
TAG="stable"

SRC_IMAGE="${SRC_ORG}/${REPO}@${DIGEST}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"

# Using crane
crane cp "${SRC_IMAGE}" "${DEST_IMAGE}"

# Using regctl
# regctl image copy "${SRC_IMAGE}" "${DEST_IMAGE}"
```

## Migrate all tags for a repository

To migrate every tagged image in a repository, use the Docker Hub API to
enumerate tags and copy each one. The following example script retrieves all
tags for a given repository and migrates them in a loop. This approach scales to
repositories with many tags without overwhelming local resources. Note that
there is a rate limit on Docker Hub requests, so you may need to add delays or
pagination handling for large repositories.

Replace the environment variable values with your source and destination
organization names and repository name. If your source repository is private,
also set `HUB_USER` and `HUB_TOKEN` with credentials that have pull access. You
can also choose between `crane` and `regctl` for the copy operation.

```bash
#!/usr/bin/env bash
set -euo pipefail

# Use environment variables if set, otherwise use defaults
SRC_ORG="${SRC_ORG:-oldorg}"
DEST_ORG="${DEST_ORG:-neworg}"
REPO="${REPO:-myapp}"

# Optional: for private repositories
# HUB_USER="your-username"
# HUB_TOKEN="your-access-token"
# AUTH="-u ${HUB_USER}:${HUB_TOKEN}"
AUTH=""

TOOL="crane"   # or: TOOL="regctl"

TAGS_URL="https://hub.docker.com/v2/repositories/${SRC_ORG}/${REPO}/tags?page_size=100"

while [[ -n "${TAGS_URL}" && "${TAGS_URL}" != "null" ]]; do
  RESP=$(curl -fsSL ${AUTH} "${TAGS_URL}")

  echo "${RESP}" | jq -r '.results[].name' | while read -r TAG; do
    [[ -z "${TAG}" ]] && continue

    SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
    DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"

    echo "Migrating ${SRC_IMAGE} → ${DEST_IMAGE}"

    case "${TOOL}" in
      crane)
        crane cp "${SRC_IMAGE}" "${DEST_IMAGE}"
        ;;
      regctl)
        regctl image copy "${SRC_IMAGE}" "${DEST_IMAGE}"
        ;;
    esac
  done

  TAGS_URL=$(echo "${RESP}" | jq -r '.next')
done
```

> [!NOTE]
>
> Docker Hub automatically creates the destination repository on first push if
> your account has permission.

## Migrate multiple repositories

To migrate several repositories, create a list and run the single-repository
script for each one.

For example, create a `repos.txt` file with repository names:

```text
api
web
worker
```

Save the script from the previous section as `migrate-single-repo.sh`. Then, run
the following example script that processes each repository in the file. Replace
the environment variable values with your source and destination organization
names.

```bash
#!/usr/bin/env bash
set -euo pipefail

SRC_ORG="oldorg"
DEST_ORG="neworg"

while read -r REPO; do
  [[ -z "${REPO}" ]] && continue
  echo "==== Migrating repo: ${REPO}"
  SRC_ORG="${SRC_ORG}" DEST_ORG="${DEST_ORG}" REPO="${REPO}" ./migrate-single-repo.sh
done < repos.txt
```

## Verify migration integrity

After copying, verify that source and destination match by comparing digests.

### Basic digest verification

The following example script retrieves the image digest for a specific tag from
both source and destination and compares them. If the digests match, the
migration is successful. Replace the environment variable values with your
source and destination organization names, repository name, and tag. You can
choose between `crane` and `regctl` for retrieving digests.

```bash
#!/usr/bin/env bash
set -euo pipefail

SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
TAG="1.2.3"

SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"

# Using crane
SRC_DIGEST=$(crane digest "${SRC_IMAGE}")
DEST_DIGEST=$(crane digest "${DEST_IMAGE}")

# Using regctl (alternative)
# SRC_DIGEST=$(regctl image digest "${SRC_IMAGE}")
# DEST_DIGEST=$(regctl image digest "${DEST_IMAGE}")

echo "Source:      ${SRC_DIGEST}"
echo "Destination: ${DEST_DIGEST}"

if [[ "${SRC_DIGEST}" == "${DEST_DIGEST}" ]]; then
  echo "✓ Migration verified: digests match"
else
  echo "✗ Migration failed: digests do not match"
  exit 1
fi
```

### Multi-arch verification

For multi-architecture images, also verify the manifest list to ensure all
platforms were copied correctly. Replace the environment variable values with
your source and destination organization names, repository name, and tag. You
can choose between `crane` and `regctl` for retrieving manifests.

```bash
#!/usr/bin/env bash
set -euo pipefail

SRC_ORG="oldorg"
DEST_ORG="neworg"
REPO="myapp"
TAG="1.2.3"

SRC_IMAGE="${SRC_ORG}/${REPO}:${TAG}"
DEST_IMAGE="${DEST_ORG}/${REPO}:${TAG}"

# Using crane
SRC_MANIFEST=$(crane manifest "${SRC_IMAGE}")
DEST_MANIFEST=$(crane manifest "${DEST_IMAGE}")

# Using regctl (alternative)
# SRC_MANIFEST=$(regctl image manifest --format raw-body "${SRC_IMAGE}")
# DEST_MANIFEST=$(regctl image manifest --format raw-body "${DEST_IMAGE}")

# Check if it's a manifest list (multi-arch)
if echo "${SRC_MANIFEST}" | jq -e '.manifests' > /dev/null 2>&1; then
  echo "Multi-arch image detected"
  
  # Compare platform list
  SRC_PLATFORMS=$(echo "${SRC_MANIFEST}" | jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture)"' | sort)
  DEST_PLATFORMS=$(echo "${DEST_MANIFEST}" | jq -r '.manifests[] | "\(.platform.os)/\(.platform.architecture)"' | sort)
  
  if [[ "${SRC_PLATFORMS}" == "${DEST_PLATFORMS}" ]]; then
    echo "✓ Platform list matches:"
    echo "${SRC_PLATFORMS}"
  else
    echo "✗ Platform lists do not match"
    echo "Source platforms:"
    echo "${SRC_PLATFORMS}"
    echo "Destination platforms:"
    echo "${DEST_PLATFORMS}"
    exit 1
  fi
else
  echo "Single-arch image"
fi
```

## Complete the migration

After migrating your images, complete these additional steps:

1. Copy repository metadata in the Docker Hub UI or via API:

   - README content
   - Repository description
   - Topics and tags

2. Configure repository settings to match the source:

   - Visibility (public or private)
   - Team permissions and access controls

3. Reconfigure integrations in the destination organization:

   - Webhooks
   - Automated builds
   - Security scanners

4. Update image references in your projects:

   - Change `FROM oldorg/repo:tag` to `FROM neworg/repo:tag` in Dockerfiles
   - Update deployment configurations
   - Update documentation

5. Deprecate the old location:
   - Update the source repository description to point to the new location
   - Consider adding a grace period before making the old repository private or
     read-only


---

# Immutable tags on Docker Hub

*Sección: Docker Hub*

{{< summary-bar feature_name="Immutable tags" >}}

Immutable tags provide a way to ensure that specific image versions remain unchanged once they are published to Docker Hub. This feature helps maintain consistency and reliability in your container deployments by preventing accidental overwrites of important image versions.

## What are immutable tags?

Immutable tags are image tags that, once pushed to Docker Hub, cannot be overwritten or deleted. This ensures that a specific version of an image remains exactly the same throughout its lifecycle, providing:

- Version consistency
- Reproducible builds
- Protection against accidental overwrites
- Better security and compliance

## Enable immutable tags

To enable immutable tags for your repository:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.
3. Select the repository where you want to enable immutable tags.
4. Go to **Settings** > **General**.
5. Under **Tag mutability settings**, select one of the following options:
   - **All tags are mutable (Default)**:  
     Tags can be changed to reference a different image. This lets you retarget a tag without creating a new one.
   - **All tags are immutable**:  
     Tags cannot be updated to point to a different image after creation. This ensures consistency and prevents accidental changes. This includes the `latest` tag.
   - **Specific tags are immutable**:  
     Define specific tags that cannot be updated after creation using regex values.
6. Select **Save**.

Once enabled, all tags are locked to their specific images, ensuring that each tag always points to the same image version and cannot be modified.

> [!NOTE]
> This implementation of regular expressions follows the [Go regexp package](https://pkg.go.dev/regexp), which is based on the RE2 engine. For more information, visit [RE2 Regular Expression Syntax](https://github.com/google/re2/wiki/Syntax).

## Working with immutable tags

When immutable tags are enabled:

- You cannot push a new image with the same tag name
- You must use a new tag name for each new image version

To push an image, create a new tag for your updated image and push it to the repository.


---

# Image Management

*Sección: Docker Hub*

{{< summary-bar feature_name="Image management" >}}

Images and image indexes are the foundation of container images within a
repository. The following diagram shows the relationship between images and
image indexes.

  ![a pretty wide image](./images/image-index.svg)

This structure enables multi-architecture support through a single reference. It
is important to note that images are not always referenced by an image index.
The following objects are shown in the diagram.

- Image index: An image that points to multiple architecture-specific images
  (like AMD and ARM), letting a single reference work across different
  platforms.
- Image: Individual container images that contain the actual configuration and
  layers for a specific architecture and operating system.

## Manage repository images and image indexes

Use the following steps to delete one or more items via the graphical user
interface. To delete in bulk, see the [deletion API
endpoint](/reference/api/registry/latest/#tag/delete).

> [!NOTE]
> Images associated with [immutable tags](immutable-tags.md) can't be
> deleted. Only items associated with mutable tags can be deleted.

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.
3. In the list, select a repository.
4. Select **Image Management**.
5. Search, filter, or sort the items.
   - Search: In the search box above the list, specify your search.
   - Filter: In the **Filter by** drop-down, select **Tagged**, **Image index**,
     or **Image**.
   - Sort: Select the column title for **Size**, **Last pushed**, or **Last
     pulled**.

   > [!NOTE]
   >
   > Images that haven't been pulled in over 6 months are marked as **Stale** in
   > the **Status** column.

6. Optional. Delete one or more items.
   1. Select the checkboxes next to the items in the list. Selecting any
      top-level index also removes any underlying images that aren't referenced
      elsewhere.
   2. Select **Preview and delete**.
   3. In the window that appears, verify the items that will be deleted and the
      amount of storage you will reclaim.
   4. Select **Delete forever**.

   > [!NOTE]
   >
   > Deletion operations may take some time to complete. Timeout errors may
   > occur during the deletion process. The system automatically retries the
   > deletion in the background, and the items will be removed without requiring
   > any action from you.


---

# Move images between repositories

*Sección: Docker Hub*

Consolidating and organizing your Docker images across repositories can
streamline your workflows, whether you're managing personal projects or
contributing to an organization. This topic explains how to move images between
Docker Hub repositories, ensuring that your content remains accessible and
organized under the correct accounts or namespaces.

> [!NOTE]
>
> For bulk migrations, multi-arch images, or scripted workflows, see [Bulk
> migrate Docker images](bulk-migrate.md).

## Personal to personal

When consolidating personal repositories, you can pull private images from the initial repository and push them into another repository owned by you. To avoid losing your private images, perform the following steps:

1. [Sign up](https://app.docker.com/signup) for a new Docker account with a personal subscription. (Be sure to verify your account after you've signed up.)
2. Sign in to [Docker](https://app.docker.com/login) using your original Docker account
3. Pull your images:

   ```console
   $ docker pull namespace1/docker101tutorial
   ```

4. Tag your private images with your newly created Docker username, for example:

   ```console
   $ docker tag namespace1/docker101tutorial new_namespace/docker101tutorial
   ```

5. Using `docker login` from the CLI, sign in with your newly created Docker account, and push your newly tagged private images to your new Docker account namespace:

   ```console
   $ docker push new_namespace/docker101tutorial
   ```

The private images that existed in your previous account are now available in your new account.

## Personal to an organization

To avoid losing your private images, you can pull your private images from your
personal account and push them to an organization that's owned by you.

1. Navigate to [Docker Hub](https://hub.docker.com) and select **My Hub**.
2. Select the applicable organization and verify that your user account is a member of the organization.
3. Sign in to [Docker Hub](https://hub.docker.com) using your original Docker account, and pull your images:

   ```console
   $ docker pull namespace1/docker101tutorial
   ```

4. Tag your images with your new organization namespace:

   ```console
   $ docker tag namespace1/docker101tutorial <new_org>/docker101tutorial
   ```

5. Push your newly tagged images to your new org namespace:

   ```console
   $ docker push new_org/docker101tutorial
   ```

The private images that existed in your user account are now available for your organization.


---

# Software artifacts on Docker Hub

*Sección: Docker Hub*

You can use Docker Hub to store any kind of software artifact, not just
container images. A software artifact is any item produced during the software
development process that contributes to the creation, maintenance, or
understanding of the software. Docker Hub supports OCI artifacts by leveraging
the config property on the image manifest.

## What are OCI artifacts?

OCI artifacts are any arbitrary files related to a software application. Some
examples include:

- Helm charts
- Software Bill of Materials (SBOM)
- Digital signatures
- Provenance data
- Attestations
- Vulnerability reports

Docker Hub supporting OCI artifacts means you can use one repository for storing
and distributing container images as well as other assets.

A common use case for OCI artifacts is
[Helm charts](https://helm.sh/docs/topics/charts/). Helm charts is a packaging
format that defines a Kubernetes deployment for an application. Since Kubernetes
is a popular runtime for containers, it makes sense to host application images
and deployment templates all in one place.

## Using OCI artifacts with Docker Hub

You manage OCI artifacts on Docker Hub in a similar way you would container
images.

Pushing and pulling OCI artifacts to and from a registry is done using a
registry client. [ORAS CLI](https://oras.land/docs/installation)
is a command-line tool that provides the capability of managing
OCI artifacts in a registry. If you use Helm charts, the
[Helm CLI](https://helm.sh/docs/intro/install/) provides built-in
functionality for pushing and pulling charts to and from a registry.

Registry clients invoke HTTP requests to the Docker Hub registry API. The
registry API conforms to a standard protocol defined in the
[OCI distribution specification](https://github.com/opencontainers/distribution-spec).

## Examples

This section shows some examples on using OCI artifacts with Docker Hub.

### Push a Helm chart

The following procedure shows how to push a Helm chart as an OCI artifact to
Docker Hub.

Prerequisites:

- Helm version 3.0.0 or later

Steps:

1. Create a new Helm chart

   ```console
   $ helm create demo
   ```

   This command generates a boilerplate template chart.

2. Package the Helm chart into a tarball.

   ```console
   $ helm package demo
   Successfully packaged chart and saved it to: demo-0.1.0.tgz
   ```

3. Sign in to Docker Hub with Helm, using your Docker credentials.

   ```console
   $ helm registry login registry-1.docker.io -u <YOUR_DOCKER_USERNAME>
   ```

4. Push the chart to a Docker Hub repository.

   ```console
   $ helm push demo-0.1.0.tgz oci://registry-1.docker.io/<YOUR_DOCKER_USERNAME>
   ```

   This uploads the Helm chart tarball to a `demo` repository in the `<YOUR_DOCKER_USERNAME>`
   namespace. Running this command creates a `<YOUR_DOCKER_USERNAME>/demo` repository
   if one does not already exist.

5. Go to the repository page on Docker Hub. The **Tags** section of the page
   shows the Helm chart tag.

   ![List of repository tags](./images/oci-helm.png)

6. Select the tag name to go to the page for that tag.

   The page lists a few useful commands for working with Helm charts.

   ![Tag page of a Helm chart artifact](./images/oci-helm-tagview.png)

### Push a volume

The following procedure shows how to push container volume as an OCI artifact to
Docker Hub.

Prerequisites:

- ORAS CLI version 0.15 or later

Steps:

1. Create a dummy file to use as volume content.

   ```console
   $ touch myvolume.txt
   ```

2. Sign in to Docker Hub using the ORAS CLI.

   ```console
   $ oras login -u <YOUR_DOCKER_USERNAME> registry-1.docker.io
   ```

3. Push the file to Docker Hub.

   ```console
   $ oras push registry-1.docker.io/<YOUR_DOCKER_USERNAME>/demo:0.0.1 \
     --artifact-type=application/vnd.docker.volume.v1+tar.gz \
     myvolume.txt:text/plain
   ```

   This uploads the volume to a `demo` repository in the `<YOUR_DOCKER_USERNAME>` namespace. The
   `--artifact-type` flag specifies a special media type that makes Docker Hub
   recognize the artifact as a container volume.

4. Go to the repository page on Docker Hub. The **Tags** section on that page
   shows the volume tag.

   ![Repository page showing a volume in the tag list](./images/oci-volume.png)

### Push a generic artifact file

The following procedure shows how to push a generic OCI artifact to Docker Hub.

Prerequisites:

- ORAS CLI version 0.15 or later

Steps:

1. Create your artifact file.

   ```console
   $ touch myartifact.txt
   ```

2. Sign in to Docker Hub using the ORAS CLI.

   ```console
   $ oras login -u <YOUR_DOCKER_USERNAME> registry-1.docker.io
   ```

3. Push the file to Docker Hub.

   ```console
   $ oras push registry-1.docker.io/<YOUR_DOCKER_USERNAME>/demo:0.0.1 myartifact.txt:text/plain
   ```

4. Go to the repository page on Docker Hub. The **Tags** section on that page
   shows the artifact tag.

   ![Repository page showing an artifact in the tag list](./images/oci-artifact.png)


---

# Push images to a repository

*Sección: Docker Hub*

To add content to a repository on Docker Hub, you need to tag your Docker image
and then push it to your repository. This process lets you share your
images with others or use them in different environments.

1. Tag your Docker image.

   The `docker tag` command assigns a tag to your Docker image, which includes
   your Docker Hub namespace and the repository name. The general syntax is:

   ```console
   $ docker tag [SOURCE_IMAGE[:TAG]] [NAMESPACE/REPOSITORY[:TAG]]
   ```

   Example:

   If your local image is called `my-app` and you want to tag it for the
   repository `my-namespace/my-repo` with the tag `v1.0`, run:

   ```console
   $ docker tag my-app my-namespace/my-repo:v1.0
   ```

2. Push the image to Docker Hub.

   Use the `docker push` command to upload your tagged image to the specified
   repository on Docker Hub.

   Example:

   ```console
   $ docker push my-namespace/my-repo:v1.0
   ```

   This command pushes the image tagged `v1.0` to the `my-namespace/my-repo` repository.

3. Verify the image on Docker Hub.

   Sign in to [Docker Hub](https://hub.docker.com) and navigate to your
   repository (`my-namespace/my-repo` in this example). Select the **Tags**
   tab to confirm that your tag (`v1.0` in this example) appears in the list.


---

# Tags on Docker Hub

*Sección: Docker Hub*

Tags let you manage multiple versions of images within a single Docker Hub
repository. By adding a specific `:<tag>` to each image, such as
`docs/base:testing`, you can organize and differentiate image versions for
various use cases. If no tag is specified, the image defaults to the `latest`
tag.

## Tag a local image

To tag a local image, use one of the following methods:

- When you build an image, use `docker build -t <org-or-user-namespace>/<repo-name>[:<tag>`.
- Re-tag an existing local image with `docker tag <existing-image> <org-or-user-namespace>/<repo-name>[:<tag>]`.
- When you commit changes, use `docker commit <existing-container> <org-or-user-namespace>/<repo-name>[:<tag>]`.

Then, you can push this image to the repository designated by its name or tag:

```console
$ docker push <org-or-user-namespace>/<repo-name>:<tag>
```

The image is then uploaded and available for use in Docker Hub.

## View repository tags

You can view the available tags and the size of the associated image.

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Tags** tab.

You can select a tag's digest to see more details.

## Delete repository tags

Only the repository owner or other team members with granted permissions can
delete tags.

> [!NOTE]
> If your repository has [immutable tags](immutable-tags.md) enabled, those
> tags can't be deleted. Only mutable tags can be deleted.

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Tags** tab.

5. Select the corresponding checkbox next to the tags to delete.

6. Select **Delete**.

   A confirmation dialog appears.

7. Select **Delete**.


---

# Repository information

*Sección: Docker Hub*

Each repository can include a description, an overview, and categories to help
users understand its purpose and usage. Adding clear repository information
ensures that others can find your images and use them effectively.

You can only modify the repository information of repositories that aren't
archived. If a repository is archived, you must unarchive it to modify the
information. For more details, see [Unarchive a repository](../archive.md#unarchive-a-repository).

## Repository description

The description appears in search results when using the `docker search` command
and in the search results on Docker Hub.

Consider the following repository description best practices.

- Summarize the purpose. Clearly state what the image does in a concise and
  specific manner. Make it clear if it's for a particular application, tool, or
  platform, or has a distinct use case.
- Highlight key features or benefits. Briefly mention the primary benefits or
  unique features that differentiate the image. Examples include high
  performance, ease of use, lightweight build, or compatibility with specific
  frameworks or operating systems.
- Include relevant keywords. Use keywords that users may search for to increase
  visibility, such as technology stacks, use cases, or environments.
- Keep it concise. The description can be a maximum of 100 characters. Aim to
  stay within one or two sentences for the description to ensure it's easy to
  read in search results. Users should quickly understand the image's value.
- Focus on the audience. Consider your target audience (developers, system
  administrators, etc.) and write the description to address their needs
  directly.

Following these practices can help make the description more engaging and
effective in search results, driving more relevant traffic to your repository.

### Add or update a repository description

1. Sign in to [Docker Hub](https://hub.docker.com).

2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the pencil icon under the description field.

5. Specify a description.

   The description can be up to 100 characters long.

6. Select **Update**.

## Repository overview

An overview describes what your image does and how to run it. It displays in the
public view of your repository when the repository has at least one image. If
automated builds are enabled, the overview will be synced from the source code
repository's `README.md` file on each successful build.

Consider the following repository overview best practices.

- Describe what the image is, the features it offers, and why it should be used.
  Can include examples of usage or the team behind the project.
- Explain how to get started with running a container using the image. You can
  include a minimal example of how to use the image in a Dockerfile.
- List the key image variants and tags to use them, as well as use cases for the
  variants.
- Link to documentation or support sites, communities, or mailing lists for
  additional resources.
- Provide contact information for the image maintainers.
- Include the license for the image and where to find more details if needed.

### Add or update a repository overview

1. Sign in to [Docker Hub](https://hub.docker.com).

2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Under **Repository overview**, select **Edit** or **Add overview**.

   The **Write** and **Preview** tabs appear.

5. Under **Write**, specify your repository overview.

   You can use basic Markdown and use the **Preview** tab to preview the formatting.

6. Select **Update**.

## Repository categories

You can tag Docker Hub repositories with categories, representing the primary
intended use cases for your images. This lets users more easily find and
explore content for the problem domain that they're interested in.

### Available categories

The Docker Hub content team maintains a curated list of categories.

{{% include "hub-categories.md" %}}

### Auto-generated categories

> [!NOTE]
>
> Auto-generated categories only apply to Docker Verified Publishers and
> Docker-Sponsored Open Source program participants.

For repositories that pre-date the Categories feature in Docker Hub,
categories have been automatically generated and applied, using OpenAI, based
on the repository title and description.

As an owner of a repository that has been auto-categorized, you can manually
edit the categories if you think they're inaccurate. See [Manage categories for
a repository](#manage-categories-for-a-repository).

The auto-generated categorization was a one-time effort to help seed categories
onto repositories created before the feature existed. Categories are not
assigned to new repositories automatically.

### Manage categories for a repository

You can tag a repository with up to three categories.

To edit the categories of a repository:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the pencil icon under the description field.
5. Select the categories you want to apply.
6. Select **Update**.

If you're missing a category, use the
[Give feedback link](https://docker.qualtrics.com/jfe/form/SV_03CrMyAkCWVylKu)
to let us know what categories you'd like to see.


---

# Trusted content

*Sección: Docker Hub*

Docker's trusted content programs ensure that container images meet the highest
standards for security, quality, and reliability. These programs provide
opportunities for publishers and contributors to share their images with
millions of developers worldwide while gaining valuable insights into their
content's usage. By participating, you can enhance your content's visibility,
build credibility, and access tools to optimize its impact within the container
ecosystem.

In this section, learn about:

- [Docker Official Images](official-images.md): Learn how to contribute,
  propose, and maintain Docker Official Images to serve as reliable foundations
  for containerized applications.
- [Docker-Sponsored Open Source (DSOS) Program](dsos-program.md): Discover how
  open source projects can gain perks like verified badges, insights, and access
  to Docker Scout, enhancing visibility and trust on Docker Hub.
- [Docker Verified Publisher (DVP) Program](dvp-program.md): Explore how to
  join the DVP program to showcase trusted, high-quality images with a verified
  badge, gain priority in search results, access insights, and enhance security
  through vulnerability analysis.
- [Insights and analytics](insights-analytics.md): Access detailed metrics on
  image and extension usage, including pull counts, geolocation, and client
  data, to understand user behavior and optimize your content.

For Docker Hardened Images guidance, including how to contribute, see
[Contribute to the catalog](/dhi/how-to/build/#contribute-to-the-catalog) in the
dedicated DHI docs section.


---

# Docker-Sponsored Open Source Program

*Sección: Docker Hub*

[Docker-Sponsored Open Source images](https://hub.docker.com/search?badges=open_source) are published and maintained by open-source projects sponsored by Docker through the program.

Images that are part of this program have a special badge on Docker Hub making it easier for users to identify projects that Docker has verified as trusted, secure, and active open-source projects.

![Docker-Sponsored Open Source badge](../../../images/sponsored-badge-iso.png)

The Docker-Sponsored Open Source (DSOS) Program provides several features and benefits to non-commercial open source developers.

The program grants the following perks to eligible projects:

- Repository logo
- Verified Docker-Sponsored Open Source badge
- Insights and analytics
- Access to [Docker Scout](#docker-scout) for software supply chain management
- Removal of rate limiting for developers
- Improved discoverability on Docker Hub

These benefits are valid for one year and publishers can renew annually if the project still meets the program requirements. Program members and all users pulling public images from the project namespace get access to unlimited pulls and unlimited egress.

### Repository logo

DSOS organizations can upload custom images for individual repositories on Docker Hub.
This lets you override the default organization-level logo on a per-repository basis.

Only a user with an owner or editor role for the organization can change the repository logo.

#### Image requirements

- The supported filetypes for the logo image are JPEG and PNG.
- The minimum allowed image size in pixels is 120×120.
- The maximum allowed image size in pixels is 1000×1000.
- The maximum allowed image file size is 5MB.

#### Set the repository logo

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Go to the page of the repository that you want to change the logo for.
3. Select the upload logo button, represented by a camera icon
   ({{< inline-image src="../../../images/upload_logo_sm.png" alt="camera icon" >}})
   overlaying the current repository logo.
4. In the dialog that opens, select the PNG image that you want to upload to
   set it as the logo for the repository.

#### Remove the logo

Select the **Clear** button ({{< inline-image src="../../../images/clear_logo_sm.png"
alt="clear button" >}}) to remove a logo.

Removing the logo makes the repository default to using the organization logo, if set, or the following default logo if not.

![Default logo which is a 3D grey cube](../../../images/default_logo_sm.png)

### Verified Docker-Sponsored Open Source badge

Docker verifies that developers can trust images with this badge on Docker Hub as an active open source project.

![Fluent org with a Docker-Sponsored Open Source badge](../../../images/sponsored-badge.png)

### Insights and analytics

The [insights and analytics](/docker-hub/publish/insights-analytics) service provides usage metrics for how
the community uses Docker images, granting insight into user behavior.

The usage metrics show the number of image pulls by tag or by digest, and breakdowns by
geolocation, cloud provider, client, and more.

You can select the time span for which you want to view analytics data. You can also export the data in either a summary or raw format.

### Docker Scout

DSOS projects can enable Docker Scout on up to 100 repositories for free. Docker
Scout provides automatic image analysis, policy evaluation for improved supply
chain management, integrations with third-party systems like CI platforms and
source code management, and more.

You can enable Docker Scout on a per-repository basis. For information about
how to use this product, refer to the [Docker Scout documentation](/scout/).

### Who's eligible for the Docker-Sponsored Open Source program?

To qualify for the program, a publisher must share the project namespace in public repositories, meet [the Open Source Initiative definition](https://opensource.org/docs/osd), and be in active development with no pathway to commercialization.

Find out more by heading to the
[Docker-Sponsored Open Source Program](https://www.docker.com/community/open-source/application/) application page.


---

# Docker Verified Publisher Program

*Sección: Docker Hub*

[The Docker Verified Publisher
Program](https://hub.docker.com/search?badges=verified_publisher) is a paid
subscription program that provides high-quality images from commercial
publishers verified by Docker.

These images help development teams build secure software supply chains,
minimizing exposure to malicious content early in the process to save time and
money later.

## Who's eligible to become a verified publisher?

Any independent software vendor who distributes software on Docker Hub can join
the Verified Publisher Program. To apply, see the [Verified Publisher Program
application](https://hub.docker.com/publisher-program/apply).

> [!NOTE]
>
> DVP entitlements are applied per namespace (organization). If you operate
> multiple Docker Hub namespaces, each requires a separate DVP application and
> verification process.

## Program benefits

The Docker Verified Publisher Program (DVP) provides several features and
benefits to Docker Hub publishers. The program grants the following perks based
on participation tier:

- [Enterprise-grade infrastructure](#enterprise-grade-infrastructure): High
  availability hosting with 99.9% uptime
- [Verified publisher badge](#verified-publisher-badge): Special badge
  identifying high-quality commercial publishers
- [Repository logo](#repository-logo): Upload custom logos for individual
  repositories
- [Insights and analytics](#insights-and-analytics): Detailed usage metrics and
  community engagement data
- [Vulnerability analysis](#vulnerability-analysis): Automated security scanning
  with Docker Scout
- [Priority search ranking](#priority-search-ranking): Enhanced discoverability
  in Docker Hub search results

### Enterprise-grade infrastructure

The Docker Verified Publisher Program runs on Docker Hub's enterprise-scale
infrastructure, serving millions of developers globally. Your published content
benefits from:

- High availability and uptime: Docker's systems are designed for failover
  across multiple availability zones, with load-balanced autoscaling, enabling
  99.9% uptime.
- Global delivery and fast downloads: Docker leverages a global CDN and caching
  infrastructure to achieve cache hit ratios more than 99%, reducing reliance
  on origin traffic and ensuring fast access for developers everywhere.
- Durability: Docker maintains a documented backup policy and performs full
  daily backups of production data.

You simply push your images to Docker Hub as usual, and Docker takes care of the
rest, serving your image to millions of developers worldwide.

![DVP flow in Docker Hub](./images/dvp-hub-flow.svg)

To learn more, see [Availability at
Docker](https://www.docker.com/trust/availability/).

### Verified publisher badge

Images that are part of this program have a special badge on Docker Hub making
it easier for users to identify projects that Docker has verified as
high-quality commercial publishers.

![Docker-Sponsored Open Source
badge](../../../images/verified-publisher-badge.png)

### Repository logo

DVP organizations can upload custom images for individual repositories on Docker
Hub. This lets you override the default organization-level logo on a
per-repository basis.

To manage the repository logo, see [Manage repository logo](#manage-repository-logo).

### Vulnerability analysis

[Docker Scout](/scout/) provides automatic vulnerability analysis
for DVP images published to Docker Hub.
Scanning images ensures that the published content is secure, and proves to
developers that they can trust the image.

You can enable analysis on a per-repository basis. For more about using this
feature, see [Basic vulnerability
scanning](/docker-hub/repos/manage/vulnerability-scanning/).

### Priority search ranking

Verified publisher images receive enhanced visibility in Docker Hub search
results, making it easier for developers to discover your content. This improved
discoverability helps drive adoption of your images within the developer
community.

### Insights and analytics

The insights and analytics service provides usage metrics for how
the community uses Docker images, granting insight into user behavior.

There is both a [web interface](insights-analytics.md) and an
[API](/reference/api/dvp/latest/) for accessing the analytics data.

The usage metrics show the number of image pulls by tag or by digest,
geolocation, cloud provider, client, and more.

## Support

The program doesn't change support for your organization. Support follows your
organization's Docker subscription, or your program tier if you don't have a paid
Docker subscription. For details, see [support response
times](../../../../support/index.md#support-response-times).

## Manage repository logo

After joining the Docker Verified Publisher Program, you can set a custom logo
for each repository in your organization. The following requirements apply:

- The supported filetypes for the logo image are JPEG and PNG.
- The minimum allowed image size in pixels is 120×120.
- The maximum allowed image size in pixels is 1000×1000.
- The maximum allowed image file size is 5MB.

Only a user with an owner or editor role for the organization can change the repository logo.

### Set the repository logo

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Go to the page of the repository that you want to change the logo for.
3. Select the upload logo button, represented by a camera icon ({{< inline-image
   src="../../../images/upload_logo_sm.png" alt="camera icon" >}}) overlaying the
current repository logo.
4. In the dialog that opens, select the PNG image that you want to upload to
   set it as the logo for the repository.

### Remove the logo

Select the **Clear** button ({{< inline-image src="../../../images/clear_logo_sm.png"
alt="clear button" >}}) to remove a logo.

Removing the logo makes the repository default to using the organization logo,
if set, or the following default logo if not.

![Default logo which is a 3D grey cube](../../../images/default_logo_sm.png)


---

# Insights and analytics

*Sección: Docker Hub*

Insights and analytics provides usage analytics for [Docker Verified Publisher
(DVP)](https://www.docker.com/partners/programs/) and [Docker-Sponsored Open
Source (DSOS)](https://www.docker.com/community/open-source/application/#)
images on Docker Hub. This includes self-serve access to image and extension
usage metrics for a desired time span. You can see the number of image pulls by
tag or by digest, geolocation, cloud provider, client, and more.

- [DVP program](#dvp-program): Usage analytics for Docker Verified Publisher
  organizations, including tiered reports and report configuration.
- [DSOS & Legacy DVP programs](#dsos--legacy-dvp-programs): Usage analytics for
  Docker-Sponsored Open Source publishers, and for existing customers on the
  deprecated Legacy DVP program.

The Legacy DVP program applies to existing customers who have not yet renewed
to DVP Core. The DVP Legacy program is deprecated and will be retired. Contact
your Docker sales representative or
[Docker](https://www.docker.com/partners/programs/) for more information.

## DVP program

All members of an organization have access to the analytics data. Members can
access analytics data in the [Docker Hub](https://hub.docker.com/) web interface.

### Available reports

The following reports are available for download as CSV files, based on your
organization's DVP subscription tier:

- Starter tier
  - [Summary](#summary-report)
- Growth tier
  - [Summary](#summary-report)
  - [Trends](#trends-report)
  - [Domain-level reports](#domain-level-reports)
  - [Benchmark](#benchmark-report)

The Domain-level reports and Benchmark report each provide a different slice
of reporting on consuming domains:

- Domain-level reports show how those domains use your own images, and which
  other images they use alongside yours.
- Benchmark shows how those domains use the specific images you've configured to
  benchmark against, such as a single repository.

After your organization is provisioned for DVP analytics, it takes up to one
week for the first reports to become available.

#### Summary report

The summary report provides high-level usage metrics aggregated across all your
Docker Hub content, organized by namespace and repository. This report gives you
a comprehensive overview of your image portfolio performance, helping you
understand which repositories, tags, and specific image versions are most
popular with your users.

You can use this report to answer questions like:

- Which of my repositories are getting the most usage?
- How do different image tags compare in terms of adoption?
- What's the ratio of actual downloads versus version checks across my
  portfolio?
- Which specific image digests are being pulled most frequently?
- How has overall usage changed over time for my entire image collection?

To access the report:

1. Sign in to [Docker Hub](https://hub.docker.com/).
2. Select **My Hub** in the top navigation.
3. Select your organization in the left navigation.
4. Select **Analytics** > **Overview** in the left navigation.
5. Download the report by doing one of the following:
   - Select **Download Weekly Summary**.
   - Select the **Download Monthly Summary**.
   - Expand the **Summary reports for the year** drop-down and then select
     **Download report** for the desired week or month.

The summary report is a CSV file that contains the following data points:

| Field              | Description                                                                                                                                                           |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DATE_GRANULARITY` | Weekly or monthly granularity of the data. Indicates whether the data is aggregated by week or month.                                                                 |
| `DATE_REFERENCE`   | The start date of the week or month in YYYY-MM-DD format (e.g., `2025-09-29` for the week starting September 29, 2025).                                               |
| `PUBLISHER_NAME`   | The name of the Docker organization that owns the repository (e.g., `demonstrationorg`).                                                                              |
| `LEVEL`            | The aggregation level of the data - either `repository` (summary for entire repository), `tag` (summary for specific tag), or `digest` (summary for specific digest). |
| `REFERENCE`        | The specific reference being summarized - the repository name, tag name, or digest hash depending on the level.                                                       |
| `DATA_DOWNLOADS`   | The number of actual image downloads.                                                                                                                                 |
| `VERSION_CHECKS`   | The number of version checks performed (HEAD requests to check for updates without downloading the full image).                                                       |
| `EVENT_COUNT`      | The total number of events, calculated as the sum of data downloads and version checks.                                                                               |

#### Trends report

The trends report helps you understand how adoption of your container images
evolves over time. It provides visibility into pull activity across repositories
and tags, enabling you to identify adoption patterns, version migration trends,
and usage environments (e.g., local development, CI/CD, production).

You can use this report to answer questions like:

- Which versions are gaining or losing traction?
- Is a new release being adopted?
- How does usage vary across cloud providers?

To access the report:

1. Sign in to [Docker Hub](https://hub.docker.com/).
2. Select **My Hub** in the top navigation.
3. Select your organization in the left navigation.
4. Select **Analytics** > **Trends** in the left navigation.
5. Select **DATA BY WEEK** or **DATA BY MONTH** to choose the data granularity.
6. Select **Download report** for the desired week or month.

The trends report is a CSV file that contains the following data points:

| Field                          | Description                                                                                                             |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
| `DATE_GRANULARITY`             | Weekly or monthly granularity of the data.                                                                              |
| `DATE_REFERENCE`               | The start date of the week or month.                                                                                    |
| `PUBLISHER_NAME`               | The name of the organization that owns the repository.                                                                  |
| `IMAGE_REPOSITORY`             | The full name of the image repository (e.g., `demonstrationorg/scout-demo`).                                            |
| `NAMESPACE`                    | The Docker organization or namespace that owns the repository.                                                          |
| `IP_COUNTRY`                   | The country code (ISO 3166-1 alpha-2) where the pull request originated from (e.g., `US`, `CA`).                        |
| `CLOUD_SERVICE_PROVIDER`       | The cloud service provider used for the pull request (e.g., `gcp`, `aws`, `azure`) or `no csp` for non-cloud providers. |
| `USER_AGENT`                   | The client application or tool used to pull the image (e.g., `docker`, `docker-scout`, `node-fetch`, `regclient`).      |
| `TAG`                          | The specific image tag that was pulled, or `\\N` if no specific tag was used.                                           |
| `DATA_DOWNLOADS`               | The number of data downloads for the specified criteria.                                                                |
| `VERSION_CHECKS`               | The number of version checks (HEAD requests) performed without downloading the full image.                              |
| `PULLS`                        | The total number of pull requests (data downloads + version checks).                                                    |
| `UNIQUE_AUTHENTICATED_USERS`   | The number of unique authenticated users who performed pulls.                                                           |
| `UNIQUE_UNAUTHENTICATED_USERS` | The number of unique unauthenticated users who performed pulls.                                                         |

#### Domain-level reports

Domain-level reports provide detailed insights into how specific consuming
domains use your Docker Verified Publisher (DVP) images, both on their own and
alongside other container images. These reports help you understand usage
patterns, deployment environments, adoption trends, and technology stack
combinations across your customer base and potential prospects.

You can use these reports to answer questions like:

- How are specific consuming domains using my images across different
  environments?
- What deployment patterns do I see across local development, CI/CD, and
  production?
- Which consuming domains are heavy users of my images?
- How does usage vary by geography and cloud providers for consuming domains?
- Which consuming domains are using my image alongside specific complementary
  technologies?
- What technology stacks are adopted by enterprise customers in my target
  market?
- Which organizations might be good candidates for partnership discussions?
- How can I identify potential customers who are already using related
  technologies?

##### Technographic report

The technographic report provides a detailed view of which specific consuming
domains are using your DVP images together with other container images. This
report gives you visibility into the actual organizations adopting your
technology stack combinations, enabling targeted business development and
partnership opportunities.

To access the report:

1. Sign in to [Docker Hub](https://hub.docker.com/).
2. Select **My Hub** in the top navigation.
3. Select your organization in the left navigation.
4. Select **Analytics** > **Technographic** in the left navigation.
5. Select **DATA BY WEEK** or **DATA BY MONTH** to choose the data granularity.
6. Select **Download report** for the desired week or month.

The technographic report is a CSV file that contains the following
data points:

| Field              | Description                                                                                        |
| ------------------ | ---------------------------------------------------------------------------------------------------- |
| `DATE_GRANULARITY` | Weekly or monthly granularity of the data.                                                         |
| `DATE_REFERENCE`   | The start date of the week or month in YYYY-MM-DD format.                                          |
| `PUBLISHER_NAME`   | The name of the organization that owns the DVP repository.                                         |
| `DOMAIN`           | The consuming domain that pulled both your DVP image and the paired image (e.g., `example.com`). |
| `DVPP_IMAGE`       | Your Docker Verified Publisher image repository name.                                              |
| `PAIRED_IMAGE`     | The other image repository that was used together with your DVP image by this domain.              |

Each row represents a unique combination of a consuming domain, your DVP
image, and another image that were used together during the specified time
period.

> [!NOTE]
>
> To protect privacy and ensure data quality, this report excludes personal
> email domains, disposable email services, and university domains. Only
> business and organizational domains are included in the analysis.

##### Consuming domains report

The consuming domains report provides detailed insights into how specific
consuming domains use your Docker Verified Publisher (DVP) images. This
report helps you understand usage patterns, deployment environments, and
adoption trends across your customer base and potential prospects.

To access the report:

1. Sign in to [Docker Hub](https://hub.docker.com/).
2. Select **My Hub** in the top navigation.
3. Select your organization in the left navigation.
4. Select **Analytics** > **Consuming Domains** in the left navigation.
5. Select **DATA BY WEEK** or **DATA BY MONTH** to choose the data granularity.
6. Select **Download report** for the desired week or month.

The consuming domains report is a CSV file that contains the following data
points:

| Field                        | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DATE_GRANULARITY`           | Weekly or monthly granularity of the data.                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `DATE_REFERENCE`             | The start date of the week or month in YYYY-MM-DD format.                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `PUBLISHER_NAME`             | The name of the organization that owns the DVP repository.                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `DOMAIN`                     | The consuming domain (e.g., `docker.com`) associated with the image pulls.                                                                                                                                                                                                                                                                                                                                                                                                              |
| `IP_COUNTRY`                 | The country code (ISO 3166-1 alpha-2) where the pull request originated from.                                                                                                                                                                                                                                                                                                                                                                                                           |
| `CLOUD_SERVICE_PROVIDER`     | The cloud service provider used for the pull request or `no csp` for non-cloud providers.                                                                                                                                                                                                                                                                                                                                                                                               |
| `USER_AGENT`                 | The client application or tool used to pull the image.                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `INFERRED_USE_CASE`          | The inferred deployment environment based on user agent and cloud provider analysis. Values include: <br>• `Local Dev`: Local development environment (e.g., Docker Desktop, direct `docker` commands) <br>• `CI/CD`: Continuous integration/deployment pipelines (e.g., containerd, build tools, registry mirroring) <br>• `Prod`: Production environments (e.g., Kubernetes, container orchestration platforms) <br>• `Unknown`: Unable to determine the use case from available data |
| `IMAGE_REPOSITORY`           | The specific DVP image repository that was pulled.                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `DATA_DOWNLOADS`             | The number of actual image layer downloads for this combination.                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `VERSION_CHECKS`             | The number of version checks (HEAD requests) performed without downloading the full image.                                                                                                                                                                                                                                                                                                                                                                                              |
| `PULLS`                      | The total number of pull requests (data downloads + version checks).                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `UNIQUE_AUTHENTICATED_USERS` | The number of unique authenticated users from this domain who performed pulls.                                                                                                                                                                                                                                                                                                                                                                                                          |

> [!NOTE]
>
> Use case inference is determined by analyzing user agent patterns and cloud
> service provider usage. Local development tools used on cloud infrastructure
> are reclassified as CI/CD, and CI/CD tools used on cloud infrastructure are
> reclassified as production to better reflect actual deployment patterns.

#### Benchmark report

The benchmark report shows how consuming domains interact with the specific
images you've configured to benchmark against, such as a single repository.
The report is generated per repository, so each benchmark repository
you configure produces its own report.

To access the report:

1. Sign in to [Docker Hub](https://hub.docker.com/).
2. Select **My Hub** in the top navigation.
3. Select your organization in the left navigation.
4. Select **Analytics** > **Benchmark** in the left navigation.
5. Select **DATA BY WEEK** or **DATA BY MONTH** to choose the data granularity.
6. Select **Download report** for the desired week or month.

The benchmark report is a CSV file that contains the following data points:

| Field                         | Description                                                                                 |
| ----------------------------- | -------------------------------------------------------------------------------------------- |
| `DATE_GRANULARITY`            | Weekly or monthly granularity of the data.                                                   |
| `DATE_REFERENCE`              | The start date of the week or month in YYYY-MM-DD format.                                    |
| `PUBLISHER_NAME`              | The name of the organization that owns the DVP repository.                                   |
| `DOMAIN`                      | The consuming domain associated with the pulls.                                              |
| `IP_COUNTRY`                  | The country code (ISO 3166-1 alpha-2) where the pull request originated from.                |
| `CLOUD_SERVICE_PROVIDER`      | The cloud service provider used for the pull request, or `no csp` for non-cloud providers.    |
| `USER_AGENT`                  | The client application or tool used to pull the image.                                       |
| `INFERRED_USE_CASE`           | The inferred deployment environment, using the same rules as the [consuming domains report](#consuming-domains-report). |
| `IMAGE_REPOSITORY`            | The benchmark-configured image repository that was pulled.                                   |
| `DATA_DOWNLOADS`              | The number of actual image layer downloads for this combination.                             |
| `VERSION_CHECKS`              | The number of version checks (HEAD requests) performed without downloading the full image.    |
| `PULLS`                       | The total number of pull requests (data downloads + version checks).                         |
| `UNIQUE_AUTHENTICATED_USERS`  | The number of unique authenticated users from this domain who performed pulls.               |

To configure which repositories are benchmarked, see [Configure DVP analytics
settings](#configure-dvp-analytics-settings).

### Configure DVP analytics settings

Organization owners and editors can configure DVP analytics settings through the
Admin Console to control consuming domain and benchmark report allocations for
your verified publisher namespaces.

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
2. Select **Admin Console** > **Verified Publisher**.
3. Configure the settings:
   - **Consuming domains**: Set the number of consuming domains to track for
     reporting purposes. This setting determines how many domains appear in
     your [Domain-level reports](#domain-level-reports). You can only set this
     number up to the maximum included in your DVP subscription.
   - **Benchmark report allocations**: If your organization has benchmark
     reports enabled, enter the number of consuming domains to include in the
     benchmark report for each namespace listed.
4. Select **Save** to apply your changes.

Changes to your report configuration take effect at the next reporting
cadence, either the next weekly or monthly report.

## DSOS & Legacy DVP programs

> [!IMPORTANT]
>
> The Legacy DVP program applies to existing customers who have not yet renewed
> to DVP Core. The DVP Legacy program is deprecated and will be retired. Contact
> your Docker sales representative or
> [Docker](https://www.docker.com/partners/programs/) for more information.

### View the image's analytics data

You can find analytics data for your repositories on the **Insights and
analytics** dashboard at the following URL:
`https://hub.docker.com/orgs/{namespace}/insights/images`. The dashboard
contains a visualization of the usage data and a table where you can download
the data as CSV files.

To view data in the chart:

- Select the data granularity: weekly or monthly
- Select the time interval: 3, 6, or 12 months
- Select one or more repositories in the list

![Insights and analytics chart visualization](../../../images/chart.png)

> [!TIP]
>
> Hovering your cursor over the chart displays a tooltip, showing precise data
> for points in time.

#### Share analytics data

You can share the visualization with others using the **Share** icon at the top
of the chart. This is a convenient way to share statistics with others in your
organization.

![Chart share icon](../../../images/chart-share-icon.png)

Selecting the icon generates a link that's copied to your clipboard. The link
preserves the display selections you made. When someone follows the link, the
**Insights and analytics** page opens and displays the chart with the same
configuration as you had set up when creating the link.

### Extension analytics data

If you have published Docker Extensions in the Extension marketplace, you can
also get analytics about your extension usage, available as CSV files. You can
download extension CSV reports from the **Insights and analytics** dashboard at
the following URL:
`https://hub.docker.com/orgs/{namespace}/insights/extensions`. If your Docker
namespace contains extensions known in the marketplace, you will see an
**Extensions** tab listing CSV files for your extension(s).

### Exporting analytics data

You can export the analytics data either from the web dashboard, or using the
[DVP Data API](../../../../reference/api/dvp/latest.md). All members of an organization
have access to the analytics data.

The data is available as a downloadable CSV file, in a weekly (Monday through
Sunday) or monthly format. Monthly data is available from the first day of the
following calendar month. You can import this data into your own systems, or you
can analyze it manually as a spreadsheet.

#### Export data

Export usage data for your organization's images using the Docker Hub website by
following these steps:

1.  Sign in to [Docker Hub](https://hub.docker.com/) and select **My Hub**.

2.  Choose your organization and select **Analytics**.

3.  Set the time span for which you want to export analytics data.

    The downloadable CSV files for summary and raw data appear on the right-hand
    side.

    ![Filtering options and download links for analytics data](../../../images/download-analytics-data.png)

#### Export data using the API

The HTTP API endpoints are available at:
`https://hub.docker.com/api/publisher/analytics/v1`. Learn how to export data
using the API in the [DVP Data API documentation](../../../../reference/api/dvp/latest.md).

### Data points

Export data in either raw or summary format. Each format contains different data
points and with different structure.

The following sections describe the available data points for each format. The
**Date added** column shows when the field was first introduced.

#### Image pulls raw data

The raw data format contains the following data points. Each row in the CSV file
represents an image pull.

| Data point                    | Description                                                                                                  | Date added        |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------ | ----------------- |
| Action                        | Request type, see [Action classification rules][1]. One of `pull_by_tag`, `pull_by_digest`, `version_check`. | January 1, 2022   |
| Action day                    | The date part of the timestamp: `YYYY-MM-DD`.                                                                | January 1, 2022   |
| Country                       | Request origin country.                                                                                      | January 1, 2022   |
| Digest                        | Image digest.                                                                                                | January 1, 2022   |
| HTTP method                   | HTTP method used in the request, see [registry API documentation][2] for details.                            | January 1, 2022   |
| Host                          | The cloud service provider used in an event.                                                                 | January 1, 2022   |
| Namespace                     | Docker [organization][3] (image namespace).                                                                  | January 1, 2022   |
| Reference                     | Image digest or tag used in the request.                                                                     | January 1, 2022   |
| Repository                    | Docker [repository][4] (image name).                                                                         | January 1, 2022   |
| Tag (included when available) | Tag name that's only available if the request referred to a tag.                                             | January 1, 2022   |
| Timestamp                     | Date and time of the request: `YYYY-MM-DD 00:00:00`.                                                         | January 1, 2022   |
| Type                          | The industry from which the event originates. One of `business`, `isp`, `hosting`, `education`, `null`.      | January 1, 2022   |
| User agent tool               | The application a user used to pull an image (for example, `docker` or `containerd`).                        | January 1, 2022   |
| User agent version            | The version of the application used to pull an image.                                                        | January 1, 2022   |
| Domain                        | Request origin domain, see [Privacy](#privacy).                                                              | October 11, 2022  |
| Owner                         | The name of the organization that owns the repository.                                                       | December 19, 2022 |

[1]: #image-pulls-action-classification-rules
[2]: /registry/spec/api/
[3]: /admin/organization/setup/orgs/
[4]: /docker-hub/repos/

#### Image pulls summary data

There are two levels of summary data available:

- Repository-level, a summary of every namespace and repository
- Tag- or digest-level, a summary of every namespace, repository, and reference
  (tag or digest)

The summary data formats contain the following data points for the selected time
span:

| Data point        | Description                                             | Date added        |
| ----------------- | ------------------------------------------------------- | ----------------- |
| Unique IP address | Number of unique IP addresses, see [Privacy](#privacy). | January 1, 2022   |
| Pull by tag       | GET request, by digest or by tag.                       | January 1, 2022   |
| Pull by digest    | GET or HEAD request by digest, or HEAD by digest.       | January 1, 2022   |
| Version check     | HEAD by tag, not followed by a GET                      | January 1, 2022   |
| Owner             | The name of the organization that owns the repository.  | December 19, 2022 |

#### Image pulls action classification rules

An action represents the multiple request events associated with a
`docker pull`. Pulls are grouped by category to make the data more meaningful
for understanding user behavior and intent. The categories are:

- Version check
- Pull by tag
- Pull by digest

Automated systems frequently check for new versions of your images. Being able
to distinguish between "version checks" in CI versus actual image pulls by a
user grants you more insight into your users' behavior.

The following table describes the rules applied for determining intent behind
pulls. To provide feedback or ask questions about these rules,
[fill out the Google Form](https://forms.gle/nb7beTUQz9wzXy1b6).

| Starting event | Reference | Followed by                                                     | Resulting action | Use case(s)                                                                                                    | Notes                                                                                                                                                                                                                                                                                 |
| :------------- | :-------- | :-------------------------------------------------------------- | :--------------- | :------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| HEAD           | tag       | N/A                                                             | Version check    | User already has all layers existing on local machine                                                          | This is similar to the use case of a pull by tag when the user already has all the image layers existing locally, however, it differentiates the user intent and classifies accordingly.                                                                                              |
| GET            | tag       | N/A                                                             | Pull by tag      | User already has all layers existing on local machine and/or the image is single-arch                          |                                                                                                                                                                                                                                                                                       |
| GET            | tag       | Get by different digest                                         | Pull by tag      | Image is multi-arch                                                                                            | Second GET by digest must be different from the first.                                                                                                                                                                                                                                |
| HEAD           | tag       | GET by same digest                                              | Pull by tag      | Image is multi-arch but some or all image layers already exist on the local machine                            | The HEAD by tag sends the most current digest, the following GET must be by that same digest. There may occur an additional GET, if the image is multi-arch (see the next row in this table). If the user doesn't want the most recent digest, then the user performs HEAD by digest. |
| HEAD           | tag       | GET by the same digest, then a second GET by a different digest | Pull by tag      | Image is multi-arch                                                                                            | The HEAD by tag sends the most recent digest, the following GET must be by that same digest. Since the image is multi-arch, there is a second GET by a different digest. If the user doesn't want the most recent digest, then the user performs HEAD by digest.                      |
| HEAD           | tag       | GET by same digest, then a second GET by different digest       | Pull by tag      | Image is multi-arch                                                                                            | The HEAD by tag sends the most current digest, the following GET must be by that same digest. Since the image is multi-arch, there is a second GET by a different digest. If the user doesn't want the most recent digest, then the user performs HEAD by digest.                     |
| GET            | digest    | N/A                                                             | Pull by digest   | User already has all layers existing on local machine and/or the image is single-arch                          |                                                                                                                                                                                                                                                                                       |
| HEAD           | digest    | N/A                                                             | Pull by digest   | User already has all layers existing on their local machine                                                    |                                                                                                                                                                                                                                                                                       |
| GET            | digest    | GET by different digest                                         | Pull by digest   | Image is multi-arch                                                                                            | The second GET by digest must be different from the first.                                                                                                                                                                                                                            |
| HEAD           | digest    | GET by same digest                                              | Pull by digest   | Image is single-arch and/or image is multi-arch but some part of the image already exists on the local machine |                                                                                                                                                                                                                                                                                       |
| HEAD           | digest    | GET by same digest, then a second GET by different digest       | Pull by Digest   | Image is multi-arch                                                                                            |                                                                                                                                                                                                                                                                                       |

#### Extension Summary data

There are two levels of extension summary data available:

- Core summary, with basic extension usage information: number of extension
  installs, uninstalls, and total install all times

The core-summary-data file contains the following data points for the selected time
span:

| Data point      | Description                                      | Date added  |
| --------------- | ------------------------------------------------ | ----------- |
| Installs        | Number of installs for the extension             | Feb 1, 2024 |
| TotalInstalls   | Number of installs for the extension all times   | Feb 1, 2024 |
| Uninstalls      | Number of uninstalls for the extension           | Feb 1, 2024 |
| TotalUninstalls | Number of uninstalls for the extension all times | Feb 1, 2024 |
| Updates         | Number of updates for the extension              | Feb 1, 2024 |

- Premium summary, with advanced extension usage information: installs,
  uninstalls by unique users, extension opening by unique users.

The core-summary-data file contains the following data points for the selected time
span:

| Data point       | Description                                       | Date added  |
| ---------------- | ------------------------------------------------- | ----------- |
| Installs         | Number of installs for the extension              | Feb 1, 2024 |
| UniqueInstalls   | Number of unique users installing the extension   | Feb 1, 2024 |
| Uninstalls       | Number of uninstalls for the extension            | Feb 1, 2024 |
| UniqueUninstalls | Number of unique users uninstalling the extension | Feb 1, 2024 |
| Usage            | Number of openings of the extension tab           | Feb 1, 2024 |
| UniqueUsers      | Number of unique users openings the extension tab | Feb 1, 2024 |

### Changes in data over time

The insights and analytics service is continuously improved to increase the
value it brings to publishers. Some changes might include adding new data
points, or improving existing data to make it more useful.

Changes in the dataset, such as added or removed fields, generally only apply
from the date of when the field was first introduced, and going forward.

Refer to the tables in the [Data points](#data-points) section to see from which
date a given data point is available.

## Privacy

This section contains information about privacy-protecting measures that ensures
consumers of content on Docker Hub remain completely anonymous.

> [!IMPORTANT]
>
> Docker never shares any Personally Identifiable Information (PII) as part of
> analytics data.

The image pulls summary dataset includes unique IP address count. This data point only
includes the number of distinct unique IP addresses that request an image.
Individual IP addresses are never shared.

The image pulls raw dataset includes user IP domains as a data point. This is
the domain name associated with the IP address used to pull an image. If the IP
type is `business`, the domain represents the company or organization associated
with that IP address (for example, `docker.com`). For any other IP type that's
not `business`, the domain represents the internet service provider or hosting
provider used to make the request. On average, only about 30% of all pulls
classify as the `business` IP type (this varies between publishers and images).


---

# Docker Official Images

*Sección: Docker Hub*

> [!NOTE]
>
> Docker is retiring Docker Content Trust (DCT) for Docker Official Images
> (DOI). You should start planning to transition to a different image signing
> and verification solution (like [Sigstore](https://www.sigstore.dev/) or
> [Notation](https://github.com/notaryproject/notation#readme)). Docker will
> publish migration guides soon to help you in that effort. Timelines for the
> complete deprecation of DCT are being finalized and will be published soon.
>
> For more details, see
> https://www.docker.com/blog/retiring-docker-content-trust/.

Docker, Inc. sponsors a dedicated team that's responsible for reviewing and
publishing all content in Docker Official Images. This team works in
collaboration with upstream software maintainers, security experts, and the
broader Docker community.

While it's preferable to have upstream software authors maintaining their
Docker Official Images, this isn't a strict requirement. Creating
and maintaining images for Docker Official Images is a collaborative process.
It takes place [openly on GitHub](https://github.com/docker-library/official-images)
where participation is encouraged. Anyone can provide feedback, contribute
code, suggest process changes, or even propose a new Official Image.

## Creating a Docker Official Image

From a high level, an Official Image starts out as a proposal in the form
of a set of GitHub pull requests. The following GitHub repositories detail the proposal requirements:

- [Docker Official Images repository on GitHub](https://github.com/docker-library/official-images#readme)
- [Documentation for Docker Official Images](https://github.com/docker-library/docs#readme)

The Docker Official Images team, with help from community contributors, formally
review each proposal and provide feedback to the author. This initial review
process can be lengthy, often requiring a bit of back-and-forth before the proposal is accepted.

There are subjective considerations during the review process. These
subjective concerns boil down to the basic question: "is this image generally
useful?" For example, the [Python](https://hub.docker.com/_/python/)
Docker Official Image is "generally useful" to the larger Python developer
community, whereas an obscure text adventure game written in Python last week is
not.

Once a new proposal is accepted, the author is responsible for keeping their
images and documentation up-to-date and responding to user feedback. Docker is
responsible for building and publishing the images on Docker Hub. Updates to
Docker Official Images follow the same pull request process as for new images,
although the review process for updates is more streamlined. The Docker Official
Images team ultimately acts as a gatekeeper for all changes, which helps
ensures consistency, quality, and security.

## Submitting feedback for Docker Official Images

All Docker Official Images contain a **User Feedback** section in their
documentation which covers the details for that specific repository. In most
cases, the GitHub repository which contains the Dockerfiles for an Official
Image also has an active issue tracker.

General feedback and support questions about Docker Official Images
should be directed to the `#general` channel in the [Docker Community Slack](https://dockr.ly/comm-slack).

If you're a maintainer or contributor to Docker Official Images and you're
looking for help or advice, use the `#docker-library` channel on [Libera.Chat IRC](https://libera.chat).


---

# Image security insights

*Sección: Docker Hub*

Strengthen the security of your Docker images with Docker Hub's image security
insights. Docker Hub lets you perform either point-in-time static vulnerability
scanning or always up-to-date image analysis using Docker Scout.

## Docker Scout image analysis

After turning on Docker Scout image analysis, Docker Scout automatically
analyzes images in your Docker Hub repository.

Image analysis extracts the Software Bill of Material (SBOM) and other image
metadata, and evaluates it against vulnerability data from security advisories.

The following sections describe how to turn on or off Docker Scout image
analysis for a Docker Hub repository. For more details about the image analysis,
see [Docker Scout](../../../scout/index.md).

### Turn on Docker Scout image analysis

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Under **Image security insight settings**, select **Docker Scout image analysis**.
6. Select **Save**.

### Turn off Docker Scout image analysis

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Under **Image security insight settings**, select **None**.
6. Select **Save**.


## Static vulnerability scanning

> [!NOTE]
>
> Docker Hub static vulnerability scanning requires a Docker Pro, Team, or
> Business subscription.

When you push an image to a Docker Hub repository after turning on static
scanning, Docker Hub automatically scans the image to identify vulnerabilities.
The scan results shows the security state of your images at the time when the
scan was run.

Scan results include:

- The source of the vulnerability, such as Operating System (OS) packages and
  libraries
- The version in which it was introduced
- A recommended fixed version, if available, to remediate the vulnerabilities
  discovered.

### Changes to static scanning in Docker Hub

From February 27th, 2023, Docker changed the technology that supports the
Docker Hub static scanning feature. The static scanning is now powered natively
by Docker, instead of a third-party.

As a result of this change, scanning now detects vulnerabilities at a more
granular level than before. This in turn means that vulnerability reports may
show a higher number of vulnerabilities. If you used vulnerability scanning
before February 27th, 2023, you may see that new vulnerability reports list a
higher number of vulnerabilities, due to a more thorough analysis.

There is no action required on your part. Scans continue to run as usual
with no interruption or changes to pricing. Historical data continues to be
available.

### Turn on static vulnerability scanning

Repository owners and administrators can enable static vulnerability scanning
on a repository. If you are a member of a Team or a Business subscription,
ensure the repository you would like to enable scanning on is part of the Team
or a Business tier.

When scanning is active on a repository, anyone with push access can trigger a
scan by pushing an image to Docker Hub.

To enable static vulnerability scanning:

> [!NOTE]
>
> Static vulnerability scanning supports scanning images which are of AMD64
> architecture, Linux OS, and are less than 10 GB in size.

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Under **Image security insight settings**, select **Static scanning**.
6. Select **Save**.

### Scan an image

To scan an image for vulnerabilities, push the image to Docker Hub, to the
repository for which you have turned on scanning.

### View the vulnerability report

To view the vulnerability report:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.
   It may take a couple of minutes for the vulnerability report to appear in
   your repository.

   ![Vulnerability scan report](images/vuln-scan-report.png)

4. Select the **Tags** tab, then **Digest**, then **Vulnerabilities** to view the
   detailed scan report.

   The scan report displays vulnerabilities identified by the scan, sorting them
   according to their severity, with highest severity listed at the top. It
   displays information about the package that contains the vulnerability, the
   version in which it was introduced, and whether the vulnerability is fixed in
   a later version.

   ![Vulnerability scan details](images/vuln-scan-details.png)

For more information on this view, see
[Image details view](../../../scout/explore/image-details-view.md).

### Inspect vulnerabilities

The vulnerability report sorts vulnerabilities based on their severity. It
displays information about the package that contains the vulnerability, the
version in which it was introduced, and whether the vulnerability has been fixed
in a later version.

The vulnerability scan report also allows development teams and security leads
to compare the vulnerability counts across tags to see whether the
vulnerabilities are decreasing or increasing over time.

### Fix vulnerabilities

Once a list of vulnerabilities have been identified, there are a couple of
actions you can take to remediate the vulnerabilities. For example, you can:

1. Specify an updated base image in the Dockerfile, check your application-level
   dependencies, rebuild the Docker image, and then push the new image to Docker
   Hub.
2. Rebuild the Docker image, run an update command on the OS packages, and push
   a newer version of image to Docker Hub.
3. Edit the Dockerfile to manually remove or update specific libraries that
   contain vulnerabilities, rebuild the image, and push the new image to Docker
   Hub

Docker Scout can provide you with concrete and contextual remediation steps for
improving image security. For more information, see
[Docker Scout](../../../scout/index.md).

### Turn off static vulnerability scanning

Repository owners and administrators can disable static vulnerability scanning
on a repository. To disable scanning:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub** > **Repositories**.

   A list of your repositories appears.

3. Select a repository.

   The **General** page for the repository appears.

4. Select the **Settings** tab.
5. Under **Image security insight settings**, select **None**.
6. Select **Save**.


---

# Webhooks

*Sección: Docker Hub*

You can use webhooks to cause an action in another service in response to a push event in the repository. Webhooks are POST requests sent to a URL you define in Docker Hub.

## Prerequisites

For a personal repository, only the repository owner can create webhooks.
Collaborators can't create webhooks.

For an organization repository, you must be an organization owner or editor,
or a team member with admin permissions on the repository. For more details,
see [Organization teams](access.md#organization-teams).

To create a webhook using the Docker Hub API, authenticate with one of the
following:

- A [personal access token](../../../security/access-tokens/personal-access-tokens.md)
  with delete permissions
- An [organization access token](../../../security/access-tokens/organization-access-tokens.md)
  with the `scope-webhook-edit` scope or higher

## Create a webhook

To create a webhook:
1. In your chosen repository, select the **Webhooks** tab.
2. Provide a name for the webhook.
3. Provide a destination webhook URL. This is where webhook POST requests are delivered. The URL must be 255 characters or fewer.
4. Select **Create**.

## View webhook delivery history

To view the history of the webhook:
1. Hover over your webhook under the **Current Webhooks section**.
2. Select the **Menu options** icon.
3. Select **View History**.

You can then view the delivery history, and whether delivering the POST request was successful or not.

## Example webhook payload

Webhook payloads have the following JSON format:

```json
{
  "callback_url": "https://registry.hub.docker.com/u/svendowideit/testhook/hook/2141b5bi5i5b02bec211i4eeih0242eg11000a/",
  "push_data": {
    "pushed_at": 1417566161,
    "pusher": "trustedbuilder",
    "tag": "latest"
  },
  "repository": {
    "comment_count": 0,
    "date_created": 1417494799,
    "description": "",
    "dockerfile": "#\n# BUILD\u0009\u0009docker build -t svendowideit/apt-cacher .\n# RUN\u0009\u0009docker run -d -p 3142:3142 -name apt-cacher-run apt-cacher\n#\n# and then you can run containers with:\n# \u0009\u0009docker run -t -i -rm -e http_proxy http://192.168.1.2:3142/ debian bash\n#\nFROM\u0009\u0009ubuntu\n\n\nVOLUME\u0009\u0009[/var/cache/apt-cacher-ng]\nRUN\u0009\u0009apt-get update ; apt-get install -yq apt-cacher-ng\n\nEXPOSE \u0009\u00093142\nCMD\u0009\u0009chmod 777 /var/cache/apt-cacher-ng ; /etc/init.d/apt-cacher-ng start ; tail -f /var/log/apt-cacher-ng/*\n",
    "full_description": "Docker Hub based automated build from a GitHub repo",
    "is_official": false,
    "is_private": true,
    "is_trusted": true,
    "name": "testhook",
    "namespace": "svendowideit",
    "owner": "svendowideit",
    "repo_name": "svendowideit/testhook",
    "repo_url": "https://registry.hub.docker.com/u/svendowideit/testhook/",
    "star_count": 0,
    "status": "Active"
  }
}
```

> [!NOTE]
>
> The `callback_url` field is a legacy field and is no longer supported.


---

# Settings

*Sección: Docker Hub*

You can configure the following settings in Docker Hub:

- [Default privacy](#default-privacy): Settings for all repositories within each
  namespace
- [Notifications](#notifications): Personal settings for autobuild notifications

## Default privacy

You can configure the following default privacy settings for all repositories in
a namespace:

- [Disable creation of public repos](#disable-creation-of-public-repos): Prevent
  organization users from creating public repositories (organization namespaces
  only)
- [Configure default repository privacy](#configure-default-repository-privacy):
  Set the default repository privacy for new repositories


### Disable creation of public repos

{{< summary-bar feature_name="Disable public repositories" >}}

Organization owners and editors can prevent creating public repositories within
organization namespaces. You cannot configure this setting for personal account
namespaces.

> [!NOTE]
>
> Enabling this feature does not affect existing public repositories. Any public
> repositories that already exist will remain public. To make them private, you
> must change their visibility in the individual repository settings.

To configure the disable public repositories setting for an organization
namespace:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub**.
3. Select your organization from the top-left account drop-down.
4. Select **Settings** > **Default privacy**.
5. Toggle **Disable public repositories** to your desired setting.
6. Select **Save**.

### Configure default repository privacy

Use the default repository privacy setting to automatically set privacy for
repositories created via `docker push` commands when the repository doesn't
exist yet. In this case, Docker Hub automatically creates the repository with
the default repository privacy for that namespace.

> [!NOTE]
>
> You cannot configure the default repository privacy setting when **Disable
> public repositories** is enabled.

To configure the default repository privacy for a namespace:

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub**.
3. Select your organization or account from the top-left account drop-down.
4. Select **Settings** > **Default privacy**.
5. In **Default repository privacy**, select the desired default privacy setting:

   - **Public**: All new repositories appear in Docker Hub search results and can be
     pulled by everyone.
   - **Private**: All new repositories don't appear in Docker Hub search results
     and are only accessible to you and collaborators. In addition, if the
     repository is created in an organization's namespace, then the repository
     is accessible to those with applicable roles or permissions.

6. Select **Save**.

## Notifications

You can send notifications to your email for all your repositories using
autobuilds.

### Configure autobuild notifications

1. Sign in to [Docker Hub](https://hub.docker.com).
2. Select **My Hub**.
3. Select your personal account from the top-left account drop-down.
4. Select **Settings** > **Notifications**.
5. Select the notifications to receive by email:

   - **Off**: No notifications.
   - **Only failures**: Only notifications about failed builds.
   - **Everything**: Notifications for successful and failed builds.

6. Select **Save**.


---

# Troubleshoot Docker Hub

*Sección: Docker Hub*

If you experience issues with Docker Hub, refer to the following solutions.

## You have reached your pull rate limit (429 response code)

### Error message

When this issue occurs, you receive following error message in the Docker CLI or
in the Docker Engine logs:

```text
You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits
```

### Possible causes

- You have reached your pull rate limit as an authenticated Docker Personal
  user.
- You have reached your pull rate limit as an unauthenticated user based on your
  IPv4 address or IPv6 /64 subnet.

### Solution

You can use one of the following solutions:

- [Authenticate](usage/pulls.md#authentication) or
  [upgrade](../subscription-billing/manage/plans.md#upgrade-plans) your Docker
  account.
- [View your pull rate limit](usage/pulls.md#view-hourly-pull-rate-and-limit),
  wait until your pull rate limit decreases, and then try again.

## Too many requests (429 response code)

### Error message

When this issue occurs, you receive following error message in the Docker CLI or
in the Docker Engine logs:

```text
Too Many Requests
```

### Possible causes

- You have reached the [Abuse rate limit](usage/index.md#abuse-rate-limit).

### Solution

1. Check for broken CI/CD pipelines accessing Docker Hub and fix them.
2. Implement a retry with back-off solution in your automated scripts to ensure
   that you're not resending thousands of requests per minute.

## 500 response code

### Error message

When this issue occurs, the following error message is common in the Docker CLI
or in the Docker Engine logs:

```text
Unexpected status code 500
```

### Possible causes

- There is a temporary Docker Hub service issue.

### Solution

1. View the [Docker System Status Page](https://www.dockerstatus.com/) and
   verify that all services are operational.
2. Try accessing Docker Hub again. It may be a temporary issue.
3. [Contact Docker Support](https://www.docker.com/support/) to report the issue.


---

# Docker Hub usage and limits

*Sección: Docker Hub*

The following table provides an overview of the included usage and limits for each
user type, subject to fair use:


| User type                | Pull rate limit per 6 hours             | Number of public repositories | Number of private repositories |
|--------------------------|-----------------------------------------|-------------------------------|--------------------------------|
| Business (authenticated) | Unlimited                               | Unlimited                     | Unlimited                      |
| Team (authenticated)     | Unlimited                               | Unlimited                     | Unlimited                      |
| Pro (authenticated)      | Unlimited                               | Unlimited                     | Unlimited                      |
| Personal (authenticated) | 200                                     | Unlimited                     | Up to 1                        |
| Unauthenticated users    | 100 per IPv4 address or IPv6 /64 subnet | Not applicable                | Not applicable                 |

For more details, see [Pull usage and limits](pulls.md).

## Fair use

When utilizing the Docker Platform, users should be aware that excessive data
transfer, pull rates, or data storage can lead to throttling, or additional
charges. To ensure fair resource usage and maintain service quality, we reserve
the right to impose restrictions or apply additional charges to accounts
exhibiting excessive data and storage consumption.

### Abuse rate limit

Docker Hub has an abuse rate limit to protect the application and
infrastructure. This limit applies to all requests to Hub properties including
web pages, APIs, and image pulls. The limit is applied per IPv4 address or per
IPv6 /64 subnet, and while the limit changes over time depending on load and
other factors, it's in the order of thousands of requests per minute. The abuse
limit applies to all users equally regardless of account level.

You can differentiate between the pull rate limit and abuse rate limit by
looking at the error code. The abuse limit returns a simple `429 Too Many
Requests` response. The pull limit returns a longer error message that includes
a link to documentation.


---

# Best practices for optimizing Docker Hub usage

*Sección: Docker Hub*

Use the following steps to help optimize and manage your Docker Hub usage for
both individuals and organizations:

1. [View your Docker Hub usage](https://hub.docker.com/usage).

2. Use the Docker Hub usage data to identify which accounts consume the most
   data, determine peak usage times, and identify which images are related to
   the most data usage. In addition, look for usage trends, such as the
   following:

   - Inefficient pull behavior: Identify frequently accessed repositories to
     assess whether you can optimize caching practices or consolidate usage to
     reduce pulls.
   - Inefficient automated systems: Check which automated tools, such as CI/CD
     pipelines, may be causing higher pull rates, and configure them to avoid
     unnecessary image pulls.

3. Optimize image pulls by:

   - Using caching: Implement local image caching via
     [mirroring](/docker-hub/mirror/) or within your CI/CD pipelines to reduce
     redundant pulls.
   - Automating manual workflows: Avoid unnecessary pulls by configuring automated
     systems to pull only when a new version of an image is available.

4. Optimize your storage by:

    - Regularly auditing and [removing entire repositories](../repos/delete.md) with untagged, unused, or outdated images.
    - Using [Image Management](../repos/manage/hub-images/manage.md) to remove stale and outdated images within a repository.

5. For organizations, monitor and enforce organizational policies by doing the
   following:

   - Routinely [view Docker Hub usage](https://hub.docker.com/usage) to monitor usage.
   - [Enforce sign-in](/security/for-admins/enforce-sign-in/) to ensure that you
     can monitor the usage of your users and users receive higher usage limits.
   - Look for duplicate user accounts in Docker and remove accounts from your organization
   as needed.


---

# Docker Hub pull usage and limits

*Sección: Docker Hub*

Unauthenticated and Docker Personal users are subject to a 6-hour pull rate limit
on Docker Hub. In contrast, Docker Pro, Team, and Business users benefit from
an unlimited pull rate.

The following pull usage and limits apply based on your subscription, subject to
fair use:

| User type                | Pull rate limit per 6 hours             |
| ------------------------ | --------------------------------------- |
| Business (authenticated) | Unlimited                               |
| Team (authenticated)     | Unlimited                               |
| Pro (authenticated)      | Unlimited                               |
| Personal (authenticated) | 200                                     |
| Unauthenticated Users    | 100 per IPv4 address or IPv6 /64 subnet |

## Pull definition

A pull is defined as the following:

- A Docker pull includes both a version check and any download that
  occurs as a result of the pull. Depending on the client, a `docker pull` can
  verify the existence of an image or tag without downloading it by performing
  a version check.
- Version checks do not count towards usage pricing.
- A pull for a normal image makes one pull for a [single
  manifest](https://github.com/opencontainers/image-spec/blob/main/manifest.md).
- A pull for a multi-arch image will count as one pull for each
  different architecture.

## Pull attribution

Pulls from authenticated users can be attributed to either a personal or an
[organization namespace](../../faqs/accounts.md#whats-an-organization-name-or-namespace).

Attribution is based on the following:

- Private pulls: Pulls for private repositories are attributed to the
  repository's namespace owner.
- Public pulls: When pulling images from a public repository, attribution is
  determined based on domain affiliation and organization membership.
- Verified domain ownership: When pulling an image from an account linked to a
  verified domain, the attribution is set to be the owner of that
  [domain](../../faqs/security.md).
- Single organization membership:
  - If the owner of the verified domain is a company and the user is part of
    only one organization within that
    [company](../../faqs/accounts.md),
    the pull is attributed to that specific organization.
  - If the user is part of only one organization, the pull is attributed to
    that specific organization.
- Multiple organization memberships: If the user is part of multiple
  organizations under the company, the pull is attributed to the user's personal
  namespace.

### Authentication

To ensure correct attribution of your pulls, you must authenticate with Docker
Hub. The following sections provide information on how to sign in to Docker Hub
to authenticate your pulls.

#### Docker Desktop

If you are using Docker Desktop, you can sign in to Docker Hub from the Docker
Desktop menu.

Select **Sign in / Create Docker ID** from the Docker Desktop menu and follow
the on-screen instructions to complete the sign-in process.

#### Docker Engine

If you're using a standalone version of Docker Engine, run the `docker login`
command from a terminal to authenticate with Docker Hub. For information on how
to use the command, see [docker login](/reference/cli/docker/login/).

#### Docker Swarm

If you're running Docker Swarm, you must use the `--with-registry-auth` flag to
authenticate with Docker Hub. For more information, see [Create a
service](/reference/cli/docker/service/create/#with-registry-auth). If you
are using a Docker Compose file to deploy an application stack, see [docker
stack deploy](/reference/cli/docker/stack/deploy/).

#### GitHub Actions

If you're using GitHub Actions to build and push Docker images to Docker Hub,
see [login action](https://github.com/docker/login-action#dockerhub). If you are
using another Action, you must add your username and access token in a similar
way for authentication.

#### Kubernetes

If you're running Kubernetes, follow the instructions in [Pull an Image from a
Private
Registry](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/)
for information on authentication.

#### Third-party platforms

If you're using any third-party platforms, follow your provider’s instructions on using registry authentication.

> [!NOTE]
>
> When pulling images via a third-party platform, the platform may use the same
> IPv4 address or IPv6 /64 subnet to pull images for multiple users. Even if you
> are authenticated, pulls attributed to a single IPv4 address or IPv6 /64 subnet
> may cause [abuse rate limiting](index.md#abuse-rate-limit).

- [Artifactory](https://www.jfrog.com/confluence/display/JFROG/Advanced+Settings#AdvancedSettings-RemoteCredentials)
- [AWS CodeBuild](https://aws.amazon.com/blogs/devops/how-to-use-docker-images-from-a-private-registry-in-aws-codebuild-for-your-build-environment/)
- [AWS ECS/Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/private-auth.html)
- [Azure Pipelines](https://learn.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml)
- [Chipper CI](https://docs.chipperci.com/builds/docker/#rate-limit-auth)
- [CircleCI](https://circleci.com/docs/guides/execution-managed/private-images/)
- [Codefresh](https://codefresh.io/docs/docs/docker-registries/external-docker-registries/docker-hub/)
- [Drone.io](https://docs.drone.io/pipeline/docker/syntax/images/#pulling-private-images)
- [GitLab](https://docs.gitlab.com/ee/user/packages/container_registry/#authenticate-with-the-container-registry)
- [LayerCI](https://layerci.com/docs/advanced-workflows#logging-in-to-docker)
- [TeamCity](https://www.jetbrains.com/help/teamcity/integrating-teamcity-with-docker.html#Conforming+with+Docker+download+rate+limits)

## View monthly pulls and included usage

You can view your monthly pulls on the [Usage page](https://hub.docker.com/usage/pulls) in Docker Hub.

On that page, you can also send a report to your email that contains a comma
separated file with the following detailed information.

| CSV column           | Definition                                                                                                                                                                                                         | Usage guidance                                                                                                                                                                      |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `datehour`           | The date and hour (`yyyy/mm/dd/hh`) of the pull that resulted in the data transfer.                                                                                                                                | This helps in identifying peak usage times and patterns.                                                                                                                            |
| `user_name`          | The Docker ID of the user that pulled the image                                                                                                                                                                    | This lets organization owners track data consumption per user and manage resources effectively.                                                                                     |
| `repository`         | The name of the repository of the image that was pulled.                                                                                                                                                           | This lets you identify which repositories are most frequently accessed and consume most of the data transfer.                                                                       |
| `access_token_name`  | Name of the access token that was used for authentication with Docker CLI. `generated` tokens are automatically generated by the Docker client when a user signs in.                                               | Personal access tokens are usually used to authenticate automated tools (Docker Desktop, CI/CD tools, etc.). This is useful for identifying which automated system issued the pull. |
| `ips`                | The IP address that was used to pull the image. This field is aggregated, so more than one IP address may appear, representing all the IPs used to pull an image within the same date and hour.                    | This helps you understand the origin of the data transfer, which is useful for diagnosing and identifying patterns in automated or manual pulls.                                    |
| `repository_privacy` | The privacy state of the image repository that was pulled. This can either be `public` or `private`.                                                                                                               | This distinguishes between public and private repositories to identify which data transfer threshold the pull impacts.                                                              |
| `tag`                | The tag for the image. The tag is only available if the pull included a tag.                                                                                                                                       | This helps in identifying the image. Tags are often used to identify specific versions or variants of an image.                                                                     |
| `digest`             | The unique image digest for the image.                                                                                                                                                                             | This helps in identifying the image.                                                                                                                                                |
| `version_checks`     | The number of version checks accumulated for the date and hour of each image repository. Depending on the client, a pull can do a version check to verify the existence of an image or tag without downloading it. | This helps identify the frequency of version checks, which you can use to analyze usage trends and potential unexpected behaviors.                                                  |
| `pulls`              | The number of pulls accumulated for the date and hour of each image repository.                                                                                                                                    | This helps identify the frequency of repository pulls, which you can use to analyze usage trends and potential unexpected behaviors.                                                |

## View pull rate and limit

The pull rate limit is calculated on a 6-hour basis. There is no pull rate
limit for users or automated systems with a paid subscription. Unauthenticated
and Docker Personal users using Docker Hub will experience rate limits on image
pulls.

When you issue a pull and you are over the limit, Docker Hub returns a
`429` response code with the following body when the manifest is requested:

```text
You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits
```

This error message appears in the Docker CLI or in the Docker Engine logs.

To view your current pull rate and limit:

> [!NOTE]
>
> To check your limits, you need `curl` and `jq` installed.

1. Get a token.
   - To get a token anonymously, if you are pulling anonymously:

     ```console
     $ TOKEN=$(curl "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
     ```

   - To get a token with a user account, if you are authenticated, insert your
     username and password in the following command:

     ```console
     $ TOKEN=$(curl --user 'username:password' "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
     ```

2. Get the headers that contain your limits. These headers are returned on both
   GET and HEAD requests. Using GET emulates a real pull and counts towards the
   limit. Using HEAD won't.

   ```console
   $ curl --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest
   ```

3. Examine the headers. You should see the following headers.

   ```text
   ratelimit-limit: 100;w=21600
   ratelimit-remaining: 20;w=21600
   docker-ratelimit-source: 192.0.2.1
   ```

   In the previous example, the pull limit is 100 pulls per 21600 seconds (6
   hours), and there are 20 pulls remaining.

   If you don't see any `ratelimit` header, it could be because the image or your IP
   is unlimited in partnership with a publisher, provider, or an open source
   organization. It could also mean that the user you are pulling as is part of a
   paid Docker subscription. Pulling that image won't count toward pull rate limits if you
   don't see these headers.


---

# Docker Engine

*Sección: Engine*

Docker Engine is an open source containerization technology for building and
containerizing your applications. Docker Engine acts as a client-server
application with:

- A server with a long-running daemon process
  [`dockerd`](/reference/cli/dockerd).
- APIs which specify interfaces that programs can use to talk to and instruct
  the Docker daemon.
- A command line interface (CLI) client
  [`docker`](/reference/cli/docker/).

The CLI uses [Docker APIs](../reference/api/engine/index.md) to control or interact with the Docker
daemon through scripting or direct CLI commands. Many other Docker applications
use the underlying API and CLI. The daemon creates and manages Docker objects,
such as images, containers, networks, and volumes.

For more details, see
[Docker Architecture](/get-started/docker-overview.md#docker-architecture).

{{< grid >}}

## Licensing

Commercial use of Docker Engine obtained via Docker Desktop
within larger enterprises (exceeding 250 employees OR with annual revenue surpassing
$10 million USD), requires a [paid subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsEngine).
Apache License, Version 2.0. See [LICENSE](https://github.com/moby/moby/blob/master/LICENSE) for the full license.


---

# CLI

*Sección: Engine*




---

# Completion

*Sección: Engine*

You can generate a shell completion script for the Docker CLI using the `docker
completion` command. The completion script gives you word completion for
commands, flags, and Docker objects (such as container and volume names) when
you hit `<Tab>` as you type into your terminal.

You can generate completion scripts for the following shells:

- [Bash](#bash)
- [Zsh](#zsh)
- [fish](#fish)

## Bash

To get Docker CLI completion with Bash, you first need to install the
`bash-completion` package which contains a number of Bash functions for shell
completion.

```bash
# Install using APT:
sudo apt install bash-completion

# Install using Homebrew (Bash version 4 or later):
brew install bash-completion@2
# Homebrew install for older versions of Bash:
brew install bash-completion

# With pacman:
sudo pacman -S bash-completion
```

After installing `bash-completion`, source the script in your shell
configuration file (in this example, `.bashrc`):

```bash
# On Linux:
cat <<EOT >> ~/.bashrc
if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi
EOT

# On macOS / with Homebrew:
cat <<EOT >> ~/.bash_profile
[[ -r "$(brew --prefix)/etc/profile.d/bash_completion.sh" ]] && . "$(brew --prefix)/etc/profile.d/bash_completion.sh"
EOT
```

And reload your shell configuration:

```console
$ source ~/.bashrc
```

Now you can generate the Bash completion script using the `docker completion` command:

```console
$ mkdir -p ~/.local/share/bash-completion/completions
$ docker completion bash > ~/.local/share/bash-completion/completions/docker
```

## Zsh

The Zsh [completion system](http://zsh.sourceforge.net/Doc/Release/Completion-System.html)
takes care of things as long as the completion can be sourced using `FPATH`.

If you use Oh My Zsh, you can install completions without modifying `~/.zshrc`
by storing the completion script in the `~/.oh-my-zsh/completions` directory.

```console
$ mkdir -p ~/.oh-my-zsh/completions
$ docker completion zsh > ~/.oh-my-zsh/completions/_docker
```

If you're not using Oh My Zsh, store the completion script in a directory of
your choice and add the directory to `FPATH` in your `.zshrc`.

```console
$ mkdir -p ~/.docker/completions
$ docker completion zsh > ~/.docker/completions/_docker
```

```console
$ cat <<"EOT" >> ~/.zshrc
FPATH="$HOME/.docker/completions:$FPATH"
autoload -Uz compinit
compinit
EOT
```

## Fish

fish shell supports a [completion system](https://fishshell.com/docs/current/#tab-completion) natively.
To activate completion for Docker commands, copy or symlink the completion script to your fish shell `completions/` directory:

```console
$ mkdir -p ~/.config/fish/completions
$ docker completion fish > ~/.config/fish/completions/docker.fish
```


---

# Filter commands

*Sección: Engine*

You can use the `--filter` flag to scope your commands. When filtering, the
commands only include entries that match the pattern you specify.

## Using filters

The `--filter` flag expects a key-value pair separated by an operator.

```console
$ docker COMMAND --filter "KEY=VALUE"
```

The key represents the field that you want to filter on.
The value is the pattern that the specified field must match.
The operator can be either equals (`=`) or not equals (`!=`).

For example, the command `docker images --filter reference=alpine` filters the
output of the `docker images` command to only print `alpine` images.

```console
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
ubuntu       24.04     33a5cc25d22c   36 minutes ago   101MB
ubuntu       22.04     152dc042452c   36 minutes ago   88.1MB
alpine       3.21      a8cbb8c69ee7   40 minutes ago   8.67MB
alpine       latest    7144f7bab3d4   40 minutes ago   11.7MB
busybox      uclibc    3e516f71d880   48 minutes ago   2.4MB
busybox      glibc     7338d0c72c65   48 minutes ago   6.09MB
$ docker images --filter reference=alpine
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
alpine       3.21      a8cbb8c69ee7   40 minutes ago   8.67MB
alpine       latest    7144f7bab3d4   40 minutes ago   11.7MB
```

The available fields (`reference` in this case) depend on the command you run.
Some filters expect an exact match. Others handle partial matches. Some filters
let you use regular expressions.

Refer to the [CLI reference description](#reference) for each command to learn
about the supported filtering capabilities for each command.

## Combining filters

You can combine multiple filters by passing multiple `--filter` flags. The
following example shows how to print all images that match `alpine:latest` or
`busybox` - a logical `OR`.

```console
$ docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
ubuntu       24.04     33a5cc25d22c   2 hours ago   101MB
ubuntu       22.04     152dc042452c   2 hours ago   88.1MB
alpine       3.21      a8cbb8c69ee7   2 hours ago   8.67MB
alpine       latest    7144f7bab3d4   2 hours ago   11.7MB
busybox      uclibc    3e516f71d880   2 hours ago   2.4MB
busybox      glibc     7338d0c72c65   2 hours ago   6.09MB
$ docker images --filter reference=alpine:latest --filter=reference=busybox
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
alpine       latest    7144f7bab3d4   2 hours ago   11.7MB
busybox      uclibc    3e516f71d880   2 hours ago   2.4MB
busybox      glibc     7338d0c72c65   2 hours ago   6.09MB
```

### Multiple negated filters

Some commands support negated filters on [labels](../manage-resources/labels.md).
Negated filters only consider results that don't match the specified patterns.
The following command prunes all containers that aren't labeled `foo`.

```console
$ docker container prune --filter "label!=foo"
```

There's a catch in combining multiple negated label filters. Multiple negated
filters create a single negative constraint - a logical `AND`. The following 
command prunes all containers except those labeled both `foo` and `bar`.
Containers labeled either `foo` or `bar`, but not both, will be pruned.

```console
$ docker container prune --filter "label!=foo" --filter "label!=bar"
```

## Reference

For more information about filtering commands, refer to the CLI reference
description for commands that support the `--filter` flag:

- [`docker config ls`](/reference/cli/docker/config/ls/)
- [`docker container prune`](/reference/cli/docker/container/prune/)
- [`docker image prune`](/reference/cli/docker/image/prune/)
- [`docker image ls`](/reference/cli/docker/image/ls/)
- [`docker network ls`](/reference/cli/docker/network/ls/)
- [`docker network prune`](/reference/cli/docker/network/prune/)
- [`docker node ls`](/reference/cli/docker/node/ls/)
- [`docker node ps`](/reference/cli/docker/node/ps/)
- [`docker plugin ls`](/reference/cli/docker/plugin/ls/)
- [`docker container ls`](/reference/cli/docker/container/ls/)
- [`docker search`](/reference/cli/docker/search/)
- [`docker secret ls`](/reference/cli/docker/secret/ls/)
- [`docker service ls`](/reference/cli/docker/service/ls/)
- [`docker service ps`](/reference/cli/docker/service/ps/)
- [`docker stack ps`](/reference/cli/docker/stack/ps/)
- [`docker system prune`](/reference/cli/docker/system/prune/)
- [`docker volume ls`](/reference/cli/docker/volume/ls/)
- [`docker volume prune`](/reference/cli/docker/volume/prune/)


---

# Format command and log output

*Sección: Engine*

Docker supports [Go templates](https://golang.org/pkg/text/template/) which you
can use to manipulate the output format of certain commands and log drivers.

Docker provides a set of basic functions to manipulate template elements.
All of these examples use the `docker inspect` command, but many other CLI
commands have a `--format` flag, and many of the CLI command references
include examples of customizing the output format.

> [!NOTE]
>
> When using the `--format` flag, you need to observe your shell environment.
> In a POSIX shell, you can run the following with a single quote:
>
> ```console
> $ docker inspect --format '{{join .Args " , "}}'
> ```
>
> Otherwise, in a Windows shell (for example, PowerShell), you need to use single quotes, but
> escape the double quotes inside the parameters as follows:
>
> ```console
> $ docker inspect --format '{{join .Args \" , \"}}'
> ```
>

## join

`join` concatenates a list of strings to create a single string.
It puts a separator between each element in the list.

```console
$ docker inspect --format '{{join .Args " , "}}' container
```

## table

`table` specifies which fields you want to see its output.

```console
$ docker image list --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}\t{{.Size}}"
```

## json

`json` encodes an element as a json string.

```console
$ docker inspect --format '{{json .Mounts}}' container
```

## lower

`lower` transforms a string into its lowercase representation.

```console
$ docker inspect --format "{{lower .Name}}" container
```

## split

`split` slices a string into a list of strings separated by a separator.

```console
$ docker inspect --format '{{split .Image ":"}}' container
```

## title

`title` capitalizes the first character of a string.

```console
$ docker inspect --format "{{title .Name}}" container
```

## upper

`upper` transforms a string into its uppercase representation.

```console
$ docker inspect --format "{{upper .Name}}" container
```

## pad

`pad` adds whitespace padding to a string. You can specify the number of spaces to add before and after the string.

```console
$ docker image list --format '{{pad .Repository 5 10}}'
```

This example adds 5 spaces before the image repository name and 10 spaces after.

## truncate

`truncate` shortens a string to a specified length. If the string is shorter than the specified length, it remains unchanged.

```console
$ docker image list --format '{{truncate .Repository 15}}'
```

This example displays the image repository name, truncating it to the first 15 characters if it's longer.

## `println`

`println` prints each value on a new line.

```console
$ docker inspect --format='{{range .NetworkSettings.Networks}}{{println .IPAddress}}{{end}}' container
```

## Hint

To find out what data can be printed, show all content as json:

```console
$ docker container ls --format='{{json .}}'
```


---

# OpenTelemetry for the Docker CLI

*Sección: Engine*

{{< summary-bar feature_name="Docker CLI OpenTelemetry" >}}

The Docker CLI supports [OpenTelemetry](https://opentelemetry.io/docs/) instrumentation
for emitting metrics about command invocations. This is disabled by default.
You can configure the CLI to start emitting metrics to the endpoint that you
specify. This allows you to capture information about your `docker` command
invocations for more insight into your Docker usage.

Exporting metrics is opt-in, and you control where data is being sent by
specifying the destination address of the metrics collector.

## What is OpenTelemetry?

OpenTelemetry, or OTel for short, is an open observability framework for
creating and managing telemetry data, such as traces, metrics, and logs.
OpenTelemetry is vendor- and tool-agnostic, meaning that it can be used with a
broad variety of Observability backends.

Support for OpenTelemetry instrumentation in the Docker CLI means that the CLI can emit
information about events that take place, using the protocols and conventions
defined in the Open Telemetry specification.

## How it works

The Docker CLI doesn't emit telemetry data by default. Only if you've set an
environment variable on your system will Docker CLI attempt to emit OpenTelemetry
metrics, to the endpoint that you specify.

```bash
DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT=<endpoint>
```

The variable specifies the endpoint of an OpenTelemetry collector, where telemetry data
about `docker` CLI invocation should be sent. To capture the data, you'll need
an OpenTelemetry collector listening on that endpoint.

The purpose of a collector is to receive the telemetry data, process it, and
exports it to a backend. The backend is where the telemetry data gets stored.
You can choose from a number of different backends, such as Prometheus or
InfluxDB.

Some backends provide tools for visualizing the metrics directly.
Alternatively, you can also run a dedicated frontend with support for
generating more useful graphs, such as Grafana.

## Setup

To get started capturing telemetry data for the Docker CLI, you'll need to:

- Set the `DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT` environment variable to point to an OpenTelemetry collector endpoint
- Run an OpenTelemetry collector that receives the signals from CLI command invocations
- Run a backend for storing the data received from the collector

The following Docker Compose file bootstraps a set of services to get started with OpenTelemetry.
It includes an OpenTelemetry collector that the CLI can send metrics to,
and a Prometheus backend that scrapes the metrics off the collector.

```yaml {collapse=true,title=compose.yaml}
name: cli-otel
services:
  prometheus:
    image: prom/prometheus
    command:
      - "--config.file=/etc/prometheus/prom.yml"
    ports:
      # Publish the Prometheus frontend on localhost:9091
      - 9091:9090
    restart: always
    volumes:
      # Store Prometheus data in a volume:
      - prom_data:/prometheus
      # Mount the prom.yml config file
      - ./prom.yml:/etc/prometheus/prom.yml
  otelcol:
    image: otel/opentelemetry-collector
    restart: always
    depends_on:
      - prometheus
    ports:
      - 4317:4317
    volumes:
      # Mount the otelcol.yml config file
      - ./otelcol.yml:/etc/otelcol/config.yaml

volumes:
  prom_data:
```

This service assumes that the following two configuration files exist alongside
`compose.yaml`:

- ```yaml {collapse=true,title=otelcol.yml}
  # Receive signals over gRPC and HTTP
  receivers:
    otlp:
      protocols:
        grpc:
        http:

  # Establish an endpoint for Prometheus to scrape from
  exporters:
    prometheus:
      endpoint: "0.0.0.0:8889"

  service:
    pipelines:
      metrics:
        receivers: [otlp]
        exporters: [prometheus]
  ```

- ```yaml {collapse=true,title=prom.yml}
  # Configure Prometheus to scrape the OpenTelemetry collector endpoint
  scrape_configs:
    - job_name: "otel-collector"
      scrape_interval: 1s
      static_configs:
        - targets: ["otelcol:8889"]
  ```

With these files in place:

1. Start the Docker Compose services:

   ```console
   $ docker compose up
   ```

2. Configure Docker CLI to export telemetry to the OpenTelemetry collector.

   ```console
   $ export DOCKER_CLI_OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
   ```

3. Run a `docker` command to trigger the CLI into sending a metric signal to
   the OpenTelemetry collector.

   ```console
   $ docker version
   ```

4. To view telemetry metrics created by the CLI, open the Prometheus expression
   browser by going to <http://localhost:9091/graph>.

5. In the **Query** field, enter `command_time_milliseconds_total`, and execute
   the query to see the telemetry data.

## Available metrics

Docker CLI exports a single metric, `command.time`, which measures
the execution duration of a command in milliseconds. This metric has the
following attributes:

- `command.name`: the name of the command
- `command.status.code`: the exit code of the command
- `command.stderr.isatty`: true if stderr is attached to a TTY
- `command.stdin.isatty`: true if stdin is attached to a TTY
- `command.stdout.isatty`: true if stdout is attached to a TTY


---

# Use a proxy server with the Docker CLI

*Sección: Engine*

This page describes how to configure the Docker CLI to use proxies via
environment variables in containers.

This page doesn't describe how to configure proxies for Docker Desktop.
For instructions, see [configuring Docker Desktop to use HTTP/HTTPS proxies](../../desktop/settings-and-maintenance/settings.md#proxies).

If you're running Docker Engine without Docker Desktop, refer to
[Configure the Docker daemon to use a proxy](../daemon/proxy.md)
to learn how to configure a proxy server for the Docker daemon (`dockerd`) itself.

If your container needs to use an HTTP, HTTPS, or FTP proxy server, you can
configure it in different ways:

- [Configure the Docker client](#configure-the-docker-client)
- [Set proxy using the CLI](#set-proxy-using-the-cli)

> [!NOTE]
>
> Unfortunately, there's no standard that defines how web clients should handle proxy 
> environment variables, or the format for defining them.
>
> If you're interested in the history of these variables, check out this blog
> post on the subject, by the GitLab team:
> [We need to talk: Can we standardize NO_PROXY?](https://about.gitlab.com/blog/2021/01/27/we-need-to-talk-no-proxy/).

## Configure the Docker client

You can add proxy configurations for the Docker client using a JSON
configuration file, located in `~/.docker/config.json`.
Builds and containers use the configuration specified in this file.

```json
{
 "proxies": {
   "default": {
     "httpProxy": "http://proxy.example.com:3128",
     "httpsProxy": "https://proxy.example.com:3129",
     "noProxy": "*.test.example.com,.example.org,127.0.0.0/8"
   }
 }
}
```

> [!WARNING]
>
> Proxy settings may contain sensitive information. For example, some proxy servers
> require authentication information to be included in their URL, or their
> address may expose IP-addresses or hostnames of your company's environment.
>
> Environment variables are stored as plain text in the container's configuration,
> and as such can be inspected through the remote API or committed to an image
> when using `docker commit`.

The configuration becomes active after saving the file, you don't need to
restart Docker. However, the configuration only applies to new containers and
builds, and doesn't affect existing containers.

The following table describes the available configuration parameters.

| Property     | Description                                                                         |
| :----------- | :---------------------------------------------------------------------------------- |
| `httpProxy`  | Sets the `HTTP_PROXY` and `http_proxy` environment variables and build arguments.   |
| `httpsProxy` | Sets the `HTTPS_PROXY` and `https_proxy` environment variables and build arguments. |
| `ftpProxy`   | Sets the `FTP_PROXY` and `ftp_proxy` environment variables and build arguments.     |
| `noProxy`    | Sets the `NO_PROXY` and `no_proxy` environment variables and build arguments.       |
| `allProxy`   | Sets the `ALL_PROXY` and `all_proxy` environment variables and build arguments.     |

These settings are used to configure proxy environment variables for containers
only, and not used as proxy settings for the Docker CLI or the Docker Engine
itself.
Refer to the [environment variables](/reference/cli/docker/#environment-variables)
and [configure the Docker daemon to use a proxy server](../daemon/proxy.md)
sections for configuring proxy settings for the CLI and daemon.

### Run containers with a proxy configuration

When you start a container, its proxy-related environment variables are set
to reflect your proxy configuration in `~/.docker/config.json`.

For example, assuming a proxy configuration like the example
shown in the [earlier section](#configure-the-docker-client), environment
variables for containers that you run are set as follows:

```console
$ docker run --rm alpine sh -c 'env | grep -i  _PROXY'
https_proxy=http://proxy.example.com:3129
HTTPS_PROXY=http://proxy.example.com:3129
http_proxy=http://proxy.example.com:3128
HTTP_PROXY=http://proxy.example.com:3128
no_proxy=*.test.example.com,.example.org,127.0.0.0/8
NO_PROXY=*.test.example.com,.example.org,127.0.0.0/8
```

### Build with a proxy configuration

When you invoke a build, proxy-related build arguments are pre-populated
automatically, based on the proxy settings in your Docker client configuration
file.

Assuming a proxy configuration like the example shown in the
[earlier section](#configure-the-docker-client), environment
are set as follows during builds:

```console
$ docker build \
  --no-cache \
  --progress=plain \
  - <<EOF
FROM alpine
RUN env | grep -i _PROXY
EOF
```

```console
#5 [2/2] RUN env | grep -i _PROXY
#5 0.100 HTTPS_PROXY=https://proxy.example.com:3129
#5 0.100 no_proxy=*.test.example.com,.example.org,127.0.0.0/8
#5 0.100 NO_PROXY=*.test.example.com,.example.org,127.0.0.0/8
#5 0.100 https_proxy=https://proxy.example.com:3129
#5 0.100 http_proxy=http://proxy.example.com:3128
#5 0.100 HTTP_PROXY=http://proxy.example.com:3128
#5 DONE 0.1s
```

### Configure proxy settings per daemon

The `default` key under `proxies` in `~/.docker/config.json` configures the proxy
settings for all daemons that the client connects to.
To configure the proxies for individual daemons,
use the address of the daemon instead of the `default` key.

The following example configures both a default proxy config,
and a no-proxy override for the Docker daemon on address
`tcp://docker-daemon1.example.com`:

```json
{
 "proxies": {
   "default": {
     "httpProxy": "http://proxy.example.com:3128",
     "httpsProxy": "https://proxy.example.com:3129",
     "noProxy": "*.test.example.com,.example.org,127.0.0.0/8"
   },
   "tcp://docker-daemon1.example.com": {
     "noProxy": "*.internal.example.net"
   }
 }
}
```

## Set proxy using the CLI

Instead of [configuring the Docker client](#configure-the-docker-client),
you can specify proxy configurations on the command-line when you invoke the
`docker build` and `docker run` commands.

Proxy configuration on the command-line uses the `--build-arg` flag for builds,
and the `--env` flag for when you want to run containers with a proxy.

```console
$ docker build --build-arg HTTP_PROXY="http://proxy.example.com:3128" .
$ docker run --env HTTP_PROXY="http://proxy.example.com:3128" redis
```

For a list of all the proxy-related build arguments that you can use with the
`docker build` command, see
[Predefined ARGs](../../build/concepts/dockerfile.md#predefined-args).
These proxy values are only available in the build container.
They're not included in the build output.

## Proxy as environment variable for builds

Don't use the `ENV` Dockerfile instruction to specify proxy settings for builds.
Use build arguments instead.

Using environment variables for proxies embeds the configuration into the image.
If the proxy is an internal proxy, it might not be accessible for containers
created from that image.

Embedding proxy settings in images also poses a security risk, as the values
may include sensitive information.


---

# Containers

*Sección: Engine*




---

# GPU access

*Sección: Engine*

## Access an NVIDIA GPU

### Prerequisites

Visit the official [NVIDIA drivers page](https://www.nvidia.com/Download/index.aspx)
to download and install the proper drivers. Reboot your system once you have
done so.

Verify that your GPU is running and accessible.

### Install NVIDIA Container Toolkit

Follow the official NVIDIA Container Toolkit [installation instructions](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html).

### Expose GPUs for use

Include the `--gpus` flag when you start a container to access GPU resources.

To expose all available GPUs:

```console
$ docker run -it --rm --gpus all ubuntu nvidia-smi
```

The output looks like the following:

```text
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.288.01             Driver Version: 535.288.01   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |         Memory-Usage | GPU-Util  Compute M. |
|                                         |                      |               MIG M. |
|=========================================+======================+======================|
|   0  NVIDIA L4                      Off | 00000000:31:00.0 Off |                    0 |
| N/A   40C    P0              27W /  72W |      0MiB / 23034MiB |      4%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

+---------------------------------------------------------------------------------------+
| Processes:                                                                            |
|  GPU   GI   CI        PID   Type   Process name                            GPU Memory |
|        ID   ID                                                             Usage      |
|=======================================================================================|
|  No running processes found                                                           |
+---------------------------------------------------------------------------------------+
```

The leftmost column in the GPU table shows the index of each GPU (`0` for the
NVIDIA L4 in the previous example). Use these index numbers to target specific GPUs
with the `device` option.

To expose a single GPU by index:

```console
$ docker run -it --rm --gpus device=0 ubuntu nvidia-smi
```

To expose a GPU by its UUID, first list UUIDs with `nvidia-smi -L`:

```console
$ nvidia-smi -L
GPU 0: NVIDIA L4 (UUID: GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a)
```

Then pass the UUID to `--gpus`:

```console
$ docker run -it --rm --gpus device=GPU-3a23c669-1f69-c64e-cf85-44e9b07e7a2a ubuntu nvidia-smi
```

On systems with multiple GPUs, you can expose several by index. The `device`
value must be quoted because it contains a comma:

```console
$ docker run -it --rm --gpus '"device=0,2"' ubuntu nvidia-smi
```

This exposes the GPUs at index `0` and `2` — the first and third GPUs listed in
`nvidia-smi` output.

> [!NOTE]
>
> NVIDIA GPUs can only be accessed by systems running a single engine.

### Set NVIDIA capabilities

You can set capabilities manually. For example, on Ubuntu you can run the
following:

```console
$ docker run --gpus 'all,capabilities=utility' --rm ubuntu nvidia-smi
```

This enables the `utility` driver capability which adds the `nvidia-smi` tool to
the container.

Capabilities and other configurations can be set in images via environment
variables. For valid variables, see the
[nvidia-container-toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/docker-specialized.html)
documentation. These variables can be set in a Dockerfile.

You can also use CUDA images, which set these variables automatically. See the
official [CUDA images](https://catalog.ngc.nvidia.com/orgs/nvidia/containers/cuda)
NGC catalog page.


---

# Run multiple processes in a container

*Sección: Engine*

A container's main running process is the `ENTRYPOINT` and/or `CMD` at the
end of the `Dockerfile`. It's best practice to separate areas of concern by
using one service per container. That service may fork into multiple
processes (for example, Apache web server starts multiple worker processes).
It's ok to have multiple processes, but to get the most benefit out of Docker,
avoid one container being responsible for multiple aspects of your overall
application. You can connect multiple containers using user-defined networks and
shared volumes.

The container's main process is responsible for managing all processes that it
starts. In some cases, the main process isn't well-designed, and doesn't handle
"reaping" (stopping) child processes gracefully when the container exits. If
your process falls into this category, you can use the `--init` option when you
run the container. The `--init` flag inserts a tiny init-process into the
container as the main process, and handles reaping of all processes when the
container exits. Handling such processes this way is superior to using a
full-fledged init process such as `sysvinit` or `systemd` to handle process
lifecycle within your container.

If you need to run more than one service within a container, you can achieve
this in a few different ways.

## Use a wrapper script

Put all of your commands in a wrapper script, complete with testing and
debugging information. Run the wrapper script as your `CMD`. The following is a
naive example. First, the wrapper script:

```bash
#!/bin/bash

# Start the first process
./my_first_process &

# Start the second process
./my_second_process &

# Wait for any process to exit
wait -n

# Exit with status of process that exited first
exit $?
```

Next, the Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh
```

## Use Bash job controls

If you have one main process that needs to start first and stay running but you
temporarily need to run some other processes (perhaps to interact with the main
process) then you can use bash's job control. First, the wrapper script:

```bash
#!/bin/bash

# turn on bash's job control
set -m

# Start the primary process and put it in the background
./my_main_process &

# Start the helper process
./my_helper_process

# the my_helper_process might need to know how to wait on the
# primary process to start before it does its work and returns


# now we bring the primary process back into the foreground
# and leave it there
fg %1
```

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:latest
COPY my_main_process my_main_process
COPY my_helper_process my_helper_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh
```

## Use a process manager

Use a process manager like `supervisord`. This is more involved than the other
options, as it requires you to bundle `supervisord` and its configuration into
your image (or base your image on one that includes `supervisord`), along with
the different applications it manages. Then you start `supervisord`, which
manages your processes for you.

The following Dockerfile example shows this approach. The example assumes that
these files exist at the root of the build context:

- `supervisord.conf`
- `my_first_process`
- `my_second_process`

```dockerfile
# syntax=docker/dockerfile:1
FROM ubuntu:latest
RUN apt-get update && apt-get install -y supervisor
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY my_first_process my_first_process
COPY my_second_process my_second_process
CMD ["/usr/bin/supervisord"]
```

If you want to make sure both processes output their `stdout` and `stderr` to
the container logs, you can add the following to the `supervisord.conf` file:

```ini
[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0

[program:app]
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true
```


---

# Resource constraints

*Sección: Engine*

By default, a container has no resource constraints and can use as much of a
given resource as the host's kernel scheduler allows. Docker provides ways
to control how much memory, or CPU a container can use, setting runtime
configuration flags of the `docker run` command. This section provides details
on when you should set such limits and the possible implications of setting them.

Many of these features require your kernel to support Linux capabilities. To
check for support, you can use the
[`docker info`](/reference/cli/docker/system/info/) command. If a capability
is disabled in your kernel, you may see a warning at the end of the output like
the following:

```console
WARNING: No swap limit support
```

Consult your operating system's documentation for enabling them. See also the
[Docker Engine troubleshooting guide](../daemon/troubleshoot.md#kernel-cgroup-swap-limit-capabilities)
for more information.

## Memory

## Understand the risks of running out of memory

It's important not to allow a running container to consume too much of the
host machine's memory. On Linux hosts, if the kernel detects that there isn't
enough memory to perform important system functions, it throws an `OOME`, or
`Out Of Memory Exception`, and starts killing processes to free up
memory. Any process is subject to killing, including Docker and other important
applications. This can effectively bring the entire system down if the wrong
process is killed.

Docker attempts to mitigate these risks by adjusting the OOM priority on the
Docker daemon so that it's less likely to be killed than other processes
on the system. The OOM priority on containers isn't adjusted. This makes it more
likely for an individual container to be killed than for the Docker daemon
or other system processes to be killed. You shouldn't try to circumvent
these safeguards by manually setting `--oom-score-adj` to an extreme negative
number on the daemon or a container, or by setting `--oom-kill-disable` on a
container.

For more information about the Linux kernel's OOM management, see
[Out of Memory Management](https://www.kernel.org/doc/gorman/html/understand/understand016.html).

You can mitigate the risk of system instability due to OOME by:

- Perform tests to understand the memory requirements of your application
  before placing it into production.
- Ensure that your application runs only on hosts with adequate resources.
- Limit the amount of memory your container can use, as described below.
- Be mindful when configuring swap on your Docker hosts. Swap is slower than
  memory but can provide a buffer against running out of system memory.
- Consider converting your container to a
  [service](../swarm/services.md), and using service-level constraints
  and node labels to ensure that the application runs only on hosts with enough
  memory

### Limit a container's access to memory

Docker can enforce hard or soft memory limits.

- Hard limits let the container use no more than a fixed amount of memory.
- Soft limits let the container use as much memory as it needs unless certain
  conditions are met, such as when the kernel detects low memory or contention on
  the host machine.

Some of these options have different effects when used alone or when more than
one option is set.

Most of these options take a positive integer, followed by a suffix of `b`, `k`,
`m`, `g`, to indicate bytes, kilobytes, megabytes, or gigabytes.

| Option                 | Description                                                                                                                                                                                                                                                                                                                                                                                     |
| :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-m` or `--memory=`    | The maximum amount of memory the container can use. If you set this option, the minimum allowed value is `6m` (6 megabytes). That is, you must set the value to at least 6 megabytes.                                                                                                                                                                                                           |
| `--memory-swap`\*      | The amount of memory this container is allowed to swap to disk. See [`--memory-swap` details](#--memory-swap-details).                                                                                                                                                                                                                                                                          |
| `--memory-swappiness`  | By default, the host kernel can swap out a percentage of anonymous pages used by a container. You can set `--memory-swappiness` to a value between 0 and 100, to tune this percentage. See [`--memory-swappiness` details](#--memory-swappiness-details).                                                                                                                                       |
| `--memory-reservation` | Allows you to specify a soft limit smaller than `--memory` which is activated when Docker detects contention or low memory on the host machine. If you use `--memory-reservation`, it must be set lower than `--memory` for it to take precedence. Because it is a soft limit, it doesn't guarantee that the container doesn't exceed the limit.                                                |
| `--oom-kill-disable`   | By default, if an out-of-memory (OOM) error occurs, the kernel kills processes in a container. To change this behavior, use the `--oom-kill-disable` option. Only disable the OOM killer on containers where you have also set the `-m/--memory` option. If the `-m` flag isn't set, the host can run out of memory and the kernel may need to kill the host system's processes to free memory. |

For more information about cgroups and memory in general, see the documentation
for [Memory Resource Controller](https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt).

### `--memory-swap` details

`--memory-swap` is a modifier flag that only has meaning if `--memory` is also
set. Using swap allows the container to write excess memory requirements to disk
when the container has exhausted all the RAM that's available to it. There is a
performance penalty for applications that swap memory to disk often.

Its setting can have complicated effects:

- If `--memory-swap` is set to a positive integer, then both `--memory` and
  `--memory-swap` must be set. `--memory-swap` represents the total amount of
  memory and swap that can be used, and `--memory` controls the amount used by
  non-swap memory. So if `--memory="300m"` and `--memory-swap="1g"`, the
  container can use 300m of memory and 700m (`1g - 300m`) swap.

- If `--memory-swap` is set to `0`, the setting is ignored, and the value is
  treated as unset.

- If `--memory-swap` is set to the same value as `--memory`, and `--memory` is
  set to a positive integer, **the container doesn't have access to swap**.
  See
  [Prevent a container from using swap](#prevent-a-container-from-using-swap).

- If `--memory-swap` is unset, and `--memory` is set, the container can use
  as much swap as the `--memory` setting, if the host has swap
  memory configured. For instance, if `--memory="300m"` and `--memory-swap` is
  not set, the container can use 600m in total of memory and swap.

- If `--memory-swap` is explicitly set to `-1`, the container is allowed to use
  unlimited swap, up to the amount available on the host system.

- Inside the container, tools like `free` report the host's available swap, not what's available inside the container. Don't rely on the output of `free` or similar tools to determine whether swap is present.

#### Prevent a container from using swap

If `--memory` and `--memory-swap` are set to the same value, this prevents
containers from using any swap. This is because `--memory-swap` is the amount of
combined memory and swap that can be used, while `--memory` is only the amount
of physical memory that can be used.

### `--memory-swappiness` details

- A value of 0 turns off anonymous page swapping.
- A value of 100 sets all anonymous pages as swappable.
- By default, if you don't set `--memory-swappiness`, the value is
  inherited from the host machine.

## CPU

By default, each container's access to the host machine's CPU cycles is unlimited.
You can set various constraints to limit a given container's access to the host
machine's CPU cycles. Most users use and configure the
[default CFS scheduler](#configure-the-default-cfs-scheduler). You can also
configure the [real-time scheduler](#configure-the-real-time-scheduler).

### Configure the default CFS scheduler

The CFS is the Linux kernel CPU scheduler for normal Linux processes. Several
runtime flags let you configure the amount of access to CPU resources your
container has. When you use these settings, Docker modifies the settings for
the container's cgroup on the host machine.

| Option                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--cpus=<value>`       | Specify how much of the available CPU resources a container can use. For instance, if the host machine has two CPUs and you set `--cpus="1.5"`, the container is guaranteed at most one and a half of the CPUs. This is the equivalent of setting `--cpu-period="100000"` and `--cpu-quota="150000"`.                                                                                                                                                                                                                                                                                              |
| `--cpu-period=<value>` | Specify the CPU CFS scheduler period, which is used alongside `--cpu-quota`. Defaults to 100000 microseconds (100 milliseconds). Most users don't change this from the default. For most use-cases, `--cpus` is a more convenient alternative.                                                                                                                                                                                                                                                                                                                                                     |
| `--cpu-quota=<value>`  | Impose a CPU CFS quota on the container. The number of microseconds per `--cpu-period` that the container is limited to before being throttled. As such acting as the effective ceiling. For most use-cases, `--cpus` is a more convenient alternative.                                                                                                                                                                                                                                                                                                                                                  |
| `--cpuset-cpus`        | Limit the specific CPUs or cores a container can use. A comma-separated list or hyphen-separated range of CPUs a container can use, if you have more than one CPU. The first CPU is numbered 0. A valid value might be `0-3` (to use the first, second, third, and fourth CPU) or `1,3` (to use the second and fourth CPU).                                                                                                                                                                                                                                                                        |
| `--cpu-shares`         | Set this flag to a value greater or less than the default of 1024 to increase or reduce the container's weight, and give it access to a greater or lesser proportion of the host machine's CPU cycles. This is only enforced when CPU cycles are constrained. When plenty of CPU cycles are available, all containers use as much CPU as they need. In that way, this is a soft limit. `--cpu-shares` doesn't prevent containers from being scheduled in Swarm mode. It prioritizes container CPU resources for the available CPU cycles. It doesn't guarantee or reserve any specific CPU access. |

If you have 1 CPU, each of the following commands guarantees the container at
most 50% of the CPU every second.

```console
$ docker run -it --cpus=".5" ubuntu /bin/bash
```

Which is the equivalent to manually specifying `--cpu-period` and `--cpu-quota`;

```console
$ docker run -it --cpu-period=100000 --cpu-quota=50000 ubuntu /bin/bash
```

### Configure the real-time scheduler

You can configure your container to use the real-time scheduler, for tasks which
can't use the CFS scheduler. You need to
[make sure the host machine's kernel is configured correctly](#configure-the-host-machines-kernel)
before you can [configure the Docker daemon](#configure-the-docker-daemon) or
[configure individual containers](#configure-individual-containers).

> [!WARNING]
>
> CPU scheduling and prioritization are advanced kernel-level features. Most
> users don't need to change these values from their defaults. Setting these
> values incorrectly can cause your host system to become unstable or unusable.

#### Configure the host machine's kernel

Verify that `CONFIG_RT_GROUP_SCHED` is enabled in the Linux kernel by running
`zcat /proc/config.gz | grep CONFIG_RT_GROUP_SCHED` or by checking for the
existence of the file `/sys/fs/cgroup/cpu.rt_runtime_us`. For guidance on
configuring the kernel real-time scheduler, consult the documentation for your
operating system.

#### Configure the Docker daemon

To run containers using the real-time scheduler, run the Docker daemon with
the `--cpu-rt-runtime` flag set to the maximum number of microseconds reserved
for real-time tasks per runtime period. For instance, with the default period of
1000000 microseconds (1 second), setting `--cpu-rt-runtime=950000` ensures that
containers using the real-time scheduler can run for 950000 microseconds for every
1000000-microsecond period, leaving at least 50000 microseconds available for
non-real-time tasks. To make this configuration permanent on systems which use
`systemd`, create a systemd unit file for the `docker` service. For example,
see the instruction on how to configure the daemon to use a proxy with a
[systemd unit file](../daemon/proxy.md#systemd-unit-file).

#### Configure individual containers

You can pass several flags to control a container's CPU priority when you
start the container using `docker run`. Consult your operating system's
documentation or the `ulimit` command for information on appropriate values.

| Option                     | Description                                                                                                                                                                               |
| :------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--cap-add=sys_nice`       | Grants the container the `CAP_SYS_NICE` capability, which allows the container to raise process `nice` values, set real-time scheduling policies, set CPU affinity, and other operations. |
| `--cpu-rt-runtime=<value>` | The maximum number of microseconds the container can run at real-time priority within the Docker daemon's real-time scheduler period. You also need the `--cap-add=sys_nice` flag.        |
| `--ulimit rtprio=<value>`  | The maximum real-time priority allowed for the container. You also need the `--cap-add=sys_nice` flag.                                                                                    |

The following example command sets each of these three flags on a `debian:jessie`
container.

```console
$ docker run -it \
    --cpu-rt-runtime=950000 \
    --ulimit rtprio=99 \
    --cap-add=sys_nice \
    debian:jessie
```

If the kernel or Docker daemon isn't configured correctly, an error occurs.

## GPU

For information on how to access NVIDIA GPUs from a container, see
[GPU access](gpu.md).


---

# Runtime metrics

*Sección: Engine*

## Docker stats

You can use the `docker stats` command to live stream a container's
runtime metrics. The command supports CPU, memory usage, memory limit,
and network IO metrics.

The following is a sample output from the `docker stats` command

```console
$ docker stats redis1 redis2

CONTAINER           CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O
redis1              0.07%               796 KB / 64 MB        1.21%               788 B / 648 B       3.568 MB / 512 KB
redis2              0.07%               2.746 MB / 64 MB      4.29%               1.266 KB / 648 B    12.4 MB / 0 B
```

The [`docker stats`](/reference/cli/docker/container/stats/) reference
page has more details about the `docker stats` command.

## Control groups

Linux Containers rely on [control groups](https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt)
which not only track groups of processes, but also expose metrics about
CPU, memory, and block I/O usage. You can access those metrics and
obtain network usage metrics as well. This is relevant for "pure" LXC
containers, as well as for Docker containers.

Control groups are exposed through a pseudo-filesystem. In modern distributions, you
should find this filesystem under `/sys/fs/cgroup`. Under that directory, you
see multiple sub-directories, called `devices`, `freezer`, `blkio`, and so on.
Each sub-directory actually corresponds to a different cgroup hierarchy.

On older systems, the control groups might be mounted on `/cgroup`, without
distinct hierarchies. In that case, instead of seeing the sub-directories,
you see a bunch of files in that directory, and possibly some directories
corresponding to existing containers.

To figure out where your control groups are mounted, you can run:

```console
$ grep cgroup /proc/mounts
```

### Enumerate cgroups

The file layout of cgroups is significantly different between v1 and v2.

If `/sys/fs/cgroup/cgroup.controllers` is present on your system, you are using v2,
otherwise you are using v1.
Refer to the subsection that corresponds to your cgroup version.

cgroup v2 is used by default on the following distributions:

- Fedora (since 31)
- Debian GNU/Linux (since 11)
- Ubuntu (since 21.10)

> [!IMPORTANT]
>
> The detailed metrics examples later in this page describe the cgroup v1 file
> layout. On cgroup v2 hosts, use this page to find the container's cgroup
> directory and then inspect the controller files in that directory (for
> example, `memory.*`, `cpu.*`, and `io.*`). For controller semantics, refer to
> the [cgroup v2 kernel documentation](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html).

#### cgroup v1

You can look into `/proc/cgroups` to see the different control group subsystems
known to the system, the hierarchy they belong to, and how many groups they contain.

You can also look at `/proc/<pid>/cgroup` to see which control groups a process
belongs to. The control group is shown as a path relative to the root of
the hierarchy mountpoint. `/` means the process hasn't been assigned to a
group, while `/lxc/pumpkin` indicates that the process is a member of a
container named `pumpkin`.

#### cgroup v2

On cgroup v2 hosts, the content of `/proc/cgroups` isn't meaningful.
See `/sys/fs/cgroup/cgroup.controllers` to the available controllers.

### Changing cgroup version

Changing cgroup version requires rebooting the entire system.

On systemd-based systems, cgroup v2 can be enabled by adding `systemd.unified_cgroup_hierarchy=1`
to the kernel command line.
To revert the cgroup version to v1, you need to set `systemd.unified_cgroup_hierarchy=0` instead.

If `grubby` command is available on your system (e.g. on Fedora), the command line can be modified as follows:

```console
$ sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
```

If `grubby` command isn't available, edit the `GRUB_CMDLINE_LINUX` line in `/etc/default/grub`
and run `sudo update-grub`.

### Running Docker on cgroup v2

Docker supports cgroup v2 since Docker 20.10.
Running Docker on cgroup v2 also requires the following conditions to be satisfied:

- containerd: v1.4 or later
- runc: v1.0.0-rc91 or later
- Kernel: v4.15 or later (v5.2 or later is recommended)

Note that the cgroup v2 mode behaves slightly different from the cgroup v1 mode:

- The default cgroup driver (`dockerd --exec-opt native.cgroupdriver`) is `systemd` on v2, `cgroupfs` on v1.
- The default cgroup namespace mode (`docker run --cgroupns`) is `private` on v2, `host` on v1.
- The `docker run` flag `--oom-kill-disable` is discarded on v2.

### Find the cgroup for a given container

For each container, one cgroup is created in each hierarchy. On
older systems with older versions of the LXC userland tools, the name of
the cgroup is the name of the container. With more recent versions
of the LXC tools, the cgroup is `lxc/<container_name>.`

For Docker containers using cgroups, the cgroup name is the full
ID or long ID of the container. If a container shows up as ae836c95b4c3
in `docker ps`, its long ID might be something like
`ae836c95b4c3c9e9179e0e91015512da89fdec91612f63cebae57df9a5444c79`. You can
look it up with `docker inspect` or `docker ps --no-trunc`.

Putting everything together to look at the memory metrics for a Docker
container, take a look at the following paths:

- `/sys/fs/cgroup/memory/docker/<longid>/` on cgroup v1, `cgroupfs` driver
- `/sys/fs/cgroup/memory/system.slice/docker-<longid>.scope/` on cgroup v1, `systemd` driver
- `/sys/fs/cgroup/docker/<longid>/` on cgroup v2, `cgroupfs` driver
- `/sys/fs/cgroup/system.slice/docker-<longid>.scope/` on cgroup v2, `systemd` driver

### Metrics from cgroups: memory, CPU, block I/O (cgroup v1)

> [!NOTE]
>
> This section documents the cgroup v1 metric files and formats.
> For cgroup v2, inspect the relevant controller files in the container's
> cgroup directory and refer to
> [the kernel documentation](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html).

For each subsystem (memory, CPU, and block I/O), one or
more pseudo-files exist and contain statistics.

#### Memory metrics: `memory.stat`

Memory metrics are found in the `memory` cgroup. The memory
control group adds a little overhead, because it does very fine-grained
accounting of the memory usage on your host. Therefore, many distributions
chose to not enable it by default. Generally, to enable it, all you have
to do is to add some kernel command-line parameters:
`cgroup_enable=memory swapaccount=1`.

The metrics are in the pseudo-file `memory.stat`.
Here is what it looks like:

    cache 11492564992
    rss 1930993664
    mapped_file 306728960
    pgpgin 406632648
    pgpgout 403355412
    swap 0
    pgfault 728281223
    pgmajfault 1724
    inactive_anon 46608384
    active_anon 1884520448
    inactive_file 7003344896
    active_file 4489052160
    unevictable 32768
    hierarchical_memory_limit 9223372036854775807
    hierarchical_memsw_limit 9223372036854775807
    total_cache 11492564992
    total_rss 1930993664
    total_mapped_file 306728960
    total_pgpgin 406632648
    total_pgpgout 403355412
    total_swap 0
    total_pgfault 728281223
    total_pgmajfault 1724
    total_inactive_anon 46608384
    total_active_anon 1884520448
    total_inactive_file 7003344896
    total_active_file 4489052160
    total_unevictable 32768

The first half (without the `total_` prefix) contains statistics relevant
to the processes within the cgroup, excluding sub-cgroups. The second half
(with the `total_` prefix) includes sub-cgroups as well.

Some metrics are "gauges", or values that can increase or decrease. For instance,
`swap` is the amount of swap space used by the members of the cgroup.
Some others are "counters", or values that can only go up, because
they represent occurrences of a specific event. For instance, `pgfault`
indicates the number of page faults since the creation of the cgroup.

`cache`
: The amount of memory used by the processes of this control group that can be
associated precisely with a block on a block device. When you read from and
write to files on disk, this amount increases. This is the case if you use
"conventional" I/O (`open`, `read`, `write` syscalls) as well as mapped files
(with `mmap`). It also accounts for the memory used by `tmpfs` mounts, though
the reasons are unclear.

`rss`
: The amount of memory that doesn't correspond to anything on disk: stacks,
heaps, and anonymous memory maps.

`mapped_file`
: Indicates the amount of memory mapped by the processes in the control group.
It doesn't give you information about how much memory is used; it rather
tells you how it's used.

`pgfault`, `pgmajfault`
: Indicate the number of times that a process of the cgroup triggered a "page
fault" and a "major fault", respectively. A page fault happens when a process
accesses a virtual memory page that is not currently mapped to a physical
memory frame. This is a normal part of memory management. For example, a page
fault occurs when the process reads from a memory zone that has been swapped
out, or that corresponds to a memory-mapped file: in that case, the kernel
loads the page from disk and lets the CPU complete the memory access. It also
happens when the process writes to a copy-on-write memory zone: the kernel
duplicates the memory page and resumes the write operation on the process's
own copy of the page. "Major" faults happen when the kernel needs to read
data from disk. When it duplicates an existing page, or allocates an empty
page, it's a regular (or "minor") fault.

`swap`
: The amount of swap currently used by the processes in this cgroup.

`active_anon`, `inactive_anon`
: The amount of anonymous memory that has been identified has respectively
_active_ and _inactive_ by the kernel. "Anonymous" memory is the memory that is
_not_ linked to disk pages. In other words, that's the equivalent of the rss
counter described above. In fact, the very definition of the rss counter is
`active_anon` + `inactive_anon` - `tmpfs` (where tmpfs is the amount of
memory used up by `tmpfs` filesystems mounted by this control group). Now,
what's the difference between "active" and "inactive"? Pages are initially
"active"; and at regular intervals, the kernel sweeps over the memory, and tags
some pages as "inactive". Whenever they're accessed again, they're
immediately re-tagged "active". When the kernel is almost out of memory, and
time comes to swap out to disk, the kernel swaps "inactive" pages.

`active_file`, `inactive_file`
: Cache memory, with _active_ and _inactive_ similar to the _anon_ memory
above. The exact formula is `cache` = `active_file` + `inactive_file` +
`tmpfs`. The exact rules used by the kernel to move memory pages between
active and inactive sets are different from the ones used for anonymous memory,
but the general principle is the same. When the kernel needs to reclaim memory,
it's cheaper to reclaim a clean (=non modified) page from this pool, since it
can be reclaimed immediately (while anonymous pages and dirty/modified pages
need to be written to disk first).

`unevictable`
: The amount of memory that cannot be reclaimed; generally, it accounts for
memory that has been "locked" with `mlock`. It's often used by crypto
frameworks to make sure that secret keys and other sensitive material never
gets swapped out to disk.

`memory_limit`, `memsw_limit`
: These aren't really metrics, but a reminder of the limits applied to this
cgroup. The first one indicates the maximum amount of physical memory that can
be used by the processes of this control group; the second one indicates the
maximum amount of RAM+swap.

Accounting for memory in the page cache is very complex. If two
processes in different control groups both read the same file
(ultimately relying on the same blocks on disk), the corresponding
memory charge is split between the control groups. It's nice, but
it also means that when a cgroup is terminated, it could increase the
memory usage of another cgroup, because they're not splitting the cost
anymore for those memory pages.

### CPU metrics: `cpuacct.stat`

Now that we've covered memory metrics, everything else is
simple in comparison. CPU metrics are in the
`cpuacct` controller.

For each container, a pseudo-file `cpuacct.stat` contains the CPU usage
accumulated by the processes of the container, broken down into `user` and
`system` time. The distinction is:

- `user` time is the amount of time a process has direct control of the CPU,
  executing process code.
- `system` time is the time the kernel is executing system calls on behalf of
  the process.

Those times are expressed in ticks of 1/100th of a second, also called "user
jiffies". There are `USER_HZ` _"jiffies"_ per second, and on x86 systems,
`USER_HZ` is 100. Historically, this mapped exactly to the number of scheduler
"ticks" per second, but higher frequency scheduling and
[tickless kernels](https://lwn.net/Articles/549580/) have made the number of
ticks irrelevant.

#### Block I/O metrics

Block I/O is accounted in the `blkio` controller.
Different metrics are scattered across different files. While you can
find in-depth details in the [blkio-controller](https://www.kernel.org/doc/Documentation/cgroup-v1/blkio-controller.txt)
file in the kernel documentation, here is a short list of the most
relevant ones:

`blkio.sectors`
: Contains the number of 512-bytes sectors read and written by the processes
member of the cgroup, device by device. Reads and writes are merged in a single
counter.

`blkio.io_service_bytes`
: Indicates the number of bytes read and written by the cgroup. It has 4
counters per device, because for each device, it differentiates between
synchronous vs. asynchronous I/O, and reads vs. writes.

`blkio.io_serviced`
: The number of I/O operations performed, regardless of their size. It also has
4 counters per device.

`blkio.io_queued`
: Indicates the number of I/O operations currently queued for this cgroup. In
other words, if the cgroup isn't doing any I/O, this is zero. The opposite is
not true. In other words, if there is no I/O queued, it doesn't mean that the
cgroup is idle (I/O-wise). It could be doing purely synchronous reads on an
otherwise quiescent device, which can therefore handle them immediately,
without queuing. Also, while it's helpful to figure out which cgroup is
putting stress on the I/O subsystem, keep in mind that it's a relative
quantity. Even if a process group doesn't perform more I/O, its queue size can
increase just because the device load increases because of other devices.

### Network metrics

Network metrics aren't exposed directly by control groups. There is a
good explanation for that: network interfaces exist within the context
of _network namespaces_. The kernel could probably accumulate metrics
about packets and bytes sent and received by a group of processes, but
those metrics wouldn't be very useful. You want per-interface metrics
(because traffic happening on the local `lo`
interface doesn't really count). But since processes in a single cgroup
can belong to multiple network namespaces, those metrics would be harder
to interpret: multiple network namespaces means multiple `lo`
interfaces, potentially multiple `eth0`
interfaces, etc.; so this is why there is no easy way to gather network
metrics with control groups.

Instead you can gather network metrics from other sources.

#### iptables

iptables (or rather, the netfilter framework for which iptables is just
an interface) can do some serious accounting.

For instance, you can setup a rule to account for the outbound HTTP
traffic on a web server:

```console
$ iptables -I OUTPUT -p tcp --sport 80
```

There is no `-j` or `-g` flag,
so the rule just counts matched packets and goes to the following
rule.

Later, you can check the values of the counters, with:

```console
$ iptables -nxvL OUTPUT
```

Technically, `-n` isn't required, but it
prevents iptables from doing DNS reverse lookups, which are probably
useless in this scenario.

Counters include packets and bytes. If you want to setup metrics for
container traffic like this, you could execute a `for`
loop to add two `iptables` rules per
container IP address (one in each direction), in the `FORWARD`
chain. This only meters traffic going through the NAT
layer; you also need to add traffic going through the userland
proxy.

Then, you need to check those counters on a regular basis. If you
happen to use `collectd`, there is a [nice plugin](https://collectd.org/wiki/index.php/Table_of_Plugins)
to automate iptables counters collection.

#### Interface-level counters

Since each container has a virtual Ethernet interface, you might want to check
directly the TX and RX counters of this interface. Each container is associated
to a virtual Ethernet interface in your host, with a name like `vethKk8Zqi`.
Figuring out which interface corresponds to which container is, unfortunately,
difficult.

But for now, the best way is to check the metrics _from within the
containers_. To accomplish this, you can run an executable from the host
environment within the network namespace of a container using **ip-netns
magic**.

The `ip-netns exec` command allows you to execute any
program (present in the host system) within any network namespace
visible to the current process. This means that your host can
enter the network namespace of your containers, but your containers
can't access the host or other peer containers.
Containers can interact with their sub-containers, though.

The exact format of the command is:

```console
$ ip netns exec <nsname> <command...>
```

For example:

```console
$ ip netns exec mycontainer netstat -i
```

`ip netns` finds the `mycontainer` container by
using namespaces pseudo-files. Each process belongs to one network
namespace, one PID namespace, one `mnt` namespace,
etc., and those namespaces are materialized under
`/proc/<pid>/ns/`. For example, the network
namespace of PID 42 is materialized by the pseudo-file
`/proc/42/ns/net`.

When you run `ip netns exec mycontainer ...`, it
expects `/var/run/netns/mycontainer` to be one of
those pseudo-files. (Symlinks are accepted.)

In other words, to execute a command within the network namespace of a
container, we need to:

- Find out the PID of any process within the container that we want to investigate;
- Create a symlink from `/var/run/netns/<somename>` to `/proc/<thepid>/ns/net`
- Execute `ip netns exec <somename> ....`

Review [Enumerate Cgroups](#enumerate-cgroups) for how to find
the cgroup of an in-container process whose network usage you want to measure.
From there, you can examine the pseudo-file named
`tasks`, which contains all the PIDs in the
cgroup (and thus, in the container). Pick any one of the PIDs.

Putting everything together, if the "short ID" of a container is held in
the environment variable `$CID`, then you can do this:

```console
$ TASKS=/sys/fs/cgroup/devices/docker/$CID*/tasks
$ PID=$(head -n 1 $TASKS)
$ mkdir -p /var/run/netns
$ ln -sf /proc/$PID/ns/net /var/run/netns/$CID
$ ip netns exec $CID netstat -i
```

## Tips for high-performance metric collection

Running a new process each time you want to update metrics is
(relatively) expensive. If you want to collect metrics at high
resolutions, and/or over a large number of containers (think 1000
containers on a single host), you don't want to fork a new process each
time.

Here is how to collect metrics from a single process. You need to
write your metric collector in C (or any language that lets you do
low-level system calls). You need to use a special system call,
`setns()`, which lets the current process enter any
arbitrary namespace. It requires, however, an open file descriptor to
the namespace pseudo-file (remember: that's the pseudo-file in
`/proc/<pid>/ns/net`).

However, there is a catch: you must not keep this file descriptor open.
If you do, when the last process of the control group exits, the
namespace isn't destroyed, and its network resources (like the
virtual interface of the container) stays around forever (or until
you close that file descriptor).

The right approach would be to keep track of the first PID of each
container, and re-open the namespace pseudo-file each time.

## Collect metrics when a container exits

Sometimes, you don't care about real time metric collection, but when a
container exits, you want to know how much CPU, memory, etc. it has
used.

Docker makes this difficult because it relies on `lxc-start`, which carefully
cleans up after itself. It is usually easier to collect metrics at regular
intervals, and this is the way the `collectd` LXC plugin works.

But, if you'd still like to gather the stats when a container stops,
here is how:

For each container, start a collection process, and move it to the
control groups that you want to monitor by writing its PID to the tasks
file of the cgroup. The collection process should periodically re-read
the tasks file to check if it's the last process of the control group.
(If you also want to collect network statistics as explained in the
previous section, you should also move the process to the appropriate
network namespace.)

When the container exits, `lxc-start` attempts to
delete the control groups. It fails, since the control group is
still in use; but that's fine. Your process should now detect that it is
the only one remaining in the group. Now is the right time to collect
all the metrics you need!

Finally, your process should move itself back to the root control group,
and remove the container control group. To remove a control group, just
`rmdir` its directory. It's counter-intuitive to
`rmdir` a directory as it still contains files; but
remember that this is a pseudo-filesystem, so usual rules don't apply.
After the cleanup is done, the collection process can exit safely.


---

# Start containers automatically

*Sección: Engine*

Docker provides [restart policies](/reference/cli/docker/container/run/#restart)
to control whether your containers start automatically when they exit, or when
Docker restarts.
Docker recommends that you use restart policies, and avoid using process
managers to start containers.

Restart policies are different from the `--live-restore` flag of the `dockerd`
command. Using `--live-restore` lets you keep your containers running during
a Docker upgrade, though networking and user input are interrupted.

## Use a restart policy

To configure the restart policy for a container, use the [`--restart`](/reference/cli/docker/container/run/#restart) flag
when using the `docker run` command. The value of the `--restart` flag can be
any of the following:

| Flag                       | Description                                                                                                                                                                                                                                                                                                                                                           |
| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `no`                       | Don't automatically restart the container. (Default)                                                                                                                                                                                                                                                                                                                  |
| `on-failure[:max-retries]` | Restart the container if it exits due to an error, which manifests as a non-zero exit code. Optionally, limit the number of times the Docker daemon attempts to restart the container using the `:max-retries` option. The `on-failure` policy only prompts a restart if the container exits with a failure. It doesn't restart the container if the daemon restarts. |
| `always`                   | Always restart the container if it stops. If it's manually stopped, it's restarted only when Docker daemon restarts or the container itself is manually restarted. (See the second bullet listed in [restart policy details](#restart-policy-details))                                                                                                                |
| `unless-stopped`           | Similar to `always`, except that when the container is stopped (manually or otherwise), it isn't restarted even after Docker daemon restarts.                                                                                                                                                                                                                         |

The following command starts a Redis container with the `unless-stopped`
restart policy. Docker restarts the container if it exits or if the daemon
restarts, but not if you stopped the container yourself.

```console
$ docker run -d --name redis --restart unless-stopped redis
```

The following command changes the restart policy for an already running
container named `redis`.

```console
$ docker update --restart unless-stopped redis
```

The following command ensures all running containers restart.

```console
$ docker update --restart unless-stopped $(docker ps -q)
```

### Restart policy details

Keep the following in mind when using restart policies:

- A restart policy only takes effect after a container starts successfully. In
  this case, starting successfully means that the container is up for at least
  10 seconds and Docker has started monitoring it. This prevents a container
  which doesn't start at all from going into a restart loop.

- If you manually stop a container, the restart policy is ignored until the
  Docker daemon restarts or the container is manually restarted. This prevents
  a restart loop.

- Restart policies only apply to containers. To configure restart policies for
  Swarm services, see
  [flags related to service restart](/reference/cli/docker/service/create/).

### Restarting foreground containers

When you run a container in the foreground, stopping a container causes the
attached CLI to exit as well, regardless of the restart policy of the
container. This behavior is illustrated in the following example.

1. Create a Dockerfile that prints the numbers 1 to 5 and then exits.

   ```dockerfile
   FROM busybox:latest
   COPY --chmod=755 <<"EOF" /start.sh
   echo "Starting..."
   for i in $(seq 1 5); do
     echo "$i"
     sleep 1
   done
   echo "Exiting..."
   exit 1
   EOF
   ENTRYPOINT /start.sh
   ```

2. Build an image from the Dockerfile.

   ```console
   $ docker build -t startstop .
   ```

3. Run a container from the image, specifying `always` for its restart policy.

   The container prints the numbers 1..5 to stdout, and then exits. This causes
   the attached CLI to exit as well.

   ```console
   $ docker run --restart always startstop
   Starting...
   1
   2
   3
   4
   5
   Exiting...
   $
   ```

4. Running `docker ps` shows that is still running or restarting, thanks to the
   restart policy. The CLI session has already exited, however. It doesn't
   survive the initial container exit.

   ```console
   $ docker ps
   CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS         PORTS     NAMES
   081991b35afe   startstop   "/bin/sh -c /start.sh"   9 seconds ago   Up 4 seconds             gallant_easley
   ```

5. You can re-attach your terminal to the container between restarts, using the
   `docker container attach` command. It's detached again the next time the
   container exits.

   ```console
   $ docker container attach 081991b35afe
   4
   5
   Exiting...
   $
   ```

## Use a process manager

If restart policies don't suit your needs, such as when processes outside
Docker depend on Docker containers, you can use a process manager such as
[systemd](https://systemd.io/) or
[supervisor](http://supervisord.org/) instead.

> [!WARNING]
>
> Don't combine Docker restart policies with host-level process managers,
> as this creates conflicts.

To use a process manager, configure it to start your container or service using
the same `docker start` or `docker service` command you would normally use to
start the container manually. Consult the documentation for the specific
process manager for more details.

### Using a process manager inside containers

Process managers can also run within the container to check whether a process is
running and starts/restart it if not.

> [!WARNING]
>
> These aren't Docker-aware, and only monitor operating system processes within
> the container. Docker doesn't recommend this approach, because it's
> platform-dependent and may differ between versions of a given Linux
> distribution.


---

# Docker daemon configuration overview

*Sección: Engine*

This page shows you how to customize the Docker daemon, `dockerd`.

> [!NOTE]
>
> This page is for users who've installed Docker Engine manually. If you're
> using Docker Desktop, refer to the [settings page](../../desktop/settings-and-maintenance/settings.md#docker-engine).

## Configure the Docker daemon

There are two ways to configure the Docker daemon:

- Use a JSON configuration file. This is the preferred option, since it keeps
  all configurations in a single place.
- Use flags when starting `dockerd`.

You can use both of these options together as long as you don't specify the same
option both as a flag and in the JSON file. If that happens, the Docker daemon
won't start and prints an error message.

### Configuration file

The following table shows the location where the Docker daemon expects to find
the configuration file by default, depending on your system and how you're
running the daemon.

| OS and configuration | File location                              |
| -------------------- | ------------------------------------------ |
| Linux, regular setup | `/etc/docker/daemon.json`                  |
| Linux, rootless mode | `~/.config/docker/daemon.json`             |
| Windows              | `C:\ProgramData\docker\config\daemon.json` |

For rootless mode, the daemon respects the `XDG_CONFIG_HOME` variable. If set,
the expected file location is `$XDG_CONFIG_HOME/docker/daemon.json`.

You can also explicitly specify the location of the configuration file on
startup, using the `dockerd --config-file` flag.

Learn about the available configuration options in the
[dockerd reference docs](/reference/cli/dockerd.md#daemon-configuration-file)

### Configuration using flags

You can also start the Docker daemon manually and configure it using flags.
This can be useful for troubleshooting problems.

Here's an example of how to manually start the Docker daemon, using the same
configurations as shown in the previous JSON configuration:

```console
$ dockerd --debug \
  --tls=true \
  --tlscert=/var/docker/server.pem \
  --tlskey=/var/docker/serverkey.pem \
  --host tcp://192.168.59.3:2376
```

#### Listen on a Unix socket on Windows

Starting with Docker Engine 29.5, you can configure `dockerd` on Windows to
listen on a Unix socket. This setting is optional. The default Windows endpoint
remains the `npipe` named pipe.

Run `dockerd` from an elevated PowerShell session:

```powershell
PS C:\> dockerd -H unix://C:/Users/<USER>/docker.sock --group docker-users
```

Replace `<USER>` with the name of your Windows user profile directory.
Without `--group`, only members of the Administrators group and the `SYSTEM`
account can access the socket. Use a comma-separated list to grant access to
multiple users or groups.

Use a path in the user profile when granting access with `--group`. A socket
created directly under `C:\` can inherit a high integrity level that blocks
access for the configured users and groups.

Configure the Docker client to use the same socket:

```powershell
PS C:\> docker -H unix://C:/Users/<USER>/docker.sock info
```

Learn about the available configuration options in the
[dockerd reference docs](/reference/cli/dockerd.md), or by
running:

```console
$ dockerd --help
```

## Daemon data directory

The Docker daemon persists all data in a single directory. This tracks
everything related to Docker, including containers, images, volumes, service
definition, and secrets.

By default the daemon stores data in:

- `/var/lib/docker` on Linux
- `C:\ProgramData\docker` on Windows

When using the [containerd image store](../storage/containerd.md)
(the default for Docker Engine 29.0 and later on fresh installations), image
contents and container snapshots are stored in `/var/lib/containerd`. Other
daemon data (volumes, configs) remains in `/var/lib/docker`.

When using [classic storage drivers](../storage/drivers/index.md)
like `overlay2` (the default for upgraded installations), all data is stored in
`/var/lib/docker`.

### Configure the data directory location

You can configure the Docker daemon to use a different storage directory using
the `data-root` configuration option.

```json
{
  "data-root": "/mnt/docker-data"
}
```

The `data-root` option does not affect image and container data stored in
`/var/lib/containerd` when using the containerd image store. To change the
storage location of containerd snapshotters, use the system containerd
configuration file:

```toml {title="/etc/containerd/config.toml"}
version = 2
root = "/mnt/containerd-data"
```

Make sure you use a dedicated directory for each daemon. If two daemons share
the same directory, for example an NFS share, you will experience errors that
are difficult to troubleshoot.

## Next steps

Many specific configuration options are discussed throughout the Docker
documentation. Some places to go next include:

- [Automatically start containers](../containers/start-containers-automatically.md)
- [Run containerd in the Docker daemon](embedded-containerd.md)
- [Limit a container's resources](../containers/resource-constraints.md)
- [Configure storage drivers](../storage/drivers/select-storage-driver.md)
- [Container security](../security/index.md)
- [Configure the Docker daemon to use a proxy](proxy.md)


---

# Alternative container runtimes

*Sección: Engine*

Docker Engine uses containerd for managing the container lifecycle,
which includes creating, starting, and stopping containers.
By default, containerd uses runc as its container runtime.

## What runtimes can I use?

You can use any runtime that implements the containerd 
[shim API](https://github.com/containerd/containerd/blob/main/core/runtime/v2/README.md).
Such runtimes ship with a containerd shim, and you can use them without any
additional configuration. See [Use containerd shims](#use-containerd-shims).

Examples of runtimes that implement their own containerd shims include:

- [Wasmtime](https://wasmtime.dev/)
- [gVisor](https://github.com/google/gvisor)
- [Kata Containers](https://katacontainers.io/)

You can also use runtimes designed as drop-in replacements for runc. Such
runtimes depend on the runc containerd shim for invoking the runtime binary.
You must manually register such runtimes in the daemon configuration.

[youki](https://github.com/youki-dev/youki)
is one example of a runtime that can function as a runc drop-in replacement.
Refer to the [youki example](#youki) explaining the setup.

## Use containerd shims

containerd shims let you use alternative runtimes without having to change the
configuration of the Docker daemon. To use a containerd shim, install the shim
binary on `PATH` on the system where the Docker daemon is running.

To use a shim with `docker run`, specify the fully qualified name of the
runtime as the value to the `--runtime` flag:

```console
$ docker run --runtime io.containerd.kata.v2 hello-world
```

### Use a containerd shim without installing on PATH

You can use a shim without installing it on `PATH`, in which case you need to
register the shim in the daemon configuration as follows:

```json
{
  "runtimes": {
    "foo": {
      "runtimeType": "/path/to/containerd-shim-foobar-v1"
    }
  }
}
```

To use the shim, specify the name that you assigned to it:

```console
$ docker run --runtime foo hello-world
```

### Configure shims

If you need to pass additional configuration for a containerd shim, you can
use the `runtimes` option in the daemon configuration file.

1. Edit the daemon configuration file by adding a `runtimes` entry for the
   shim you want to configure.

   - Specify the fully qualified name for the runtime in `runtimeType` key
   - Add your runtime configuration under the `options` key

   ```json
   {
     "runtimes": {
       "gvisor": {
         "runtimeType": "io.containerd.runsc.v1",
         "options": {
           "TypeUrl": "io.containerd.runsc.v1.options",
           "ConfigPath": "/etc/containerd/runsc.toml"
         }
       }
     }
   }
   ```

2. Reload the daemon's configuration.

   ```console
   # systemctl reload docker
   ```

3. Use the customized runtime using the `--runtime` flag for `docker run`.

   ```console
   $ docker run --runtime gvisor hello-world
   ```

For more information about the configuration options for containerd shims, see
[Configure containerd shims](/reference/cli/dockerd.md#configure-containerd-shims).

## Examples

The following examples show you how to set up and use alternative container
runtimes with Docker Engine.

- [youki](#youki)
- [Wasmtime](#wasmtime)

### youki

youki is a container runtime written in Rust.
youki claims to be faster and use less memory than runc,
making it a good choice for resource-constrained environments.

youki functions as a drop-in replacement for runc, meaning it relies on the
runc shim to invoke the runtime binary. When you register runtimes acting as
runc replacements, you configure the path to the runtime executable, and
optionally a set of runtime arguments. For more information, see
[Configure runc drop-in replacements](/reference/cli/dockerd.md#configure-runc-drop-in-replacements).

To add youki as a container runtime:

1. Install youki and its dependencies.

   For instructions, refer to the
   [official setup guide](https://youki-dev.github.io/youki/user/basic_setup.html).

2. Register youki as a runtime for Docker by editing the Docker daemon
   configuration file, located at `/etc/docker/daemon.json` by default.

   The `path` key should specify the path to wherever you installed youki.

   ```console
   # cat > /etc/docker/daemon.json <<EOF
   {
     "runtimes": {
       "youki": {
         "path": "/usr/local/bin/youki"
       }
     }
   }
   EOF
   ```

3. Reload the daemon's configuration.

   ```console
   # systemctl reload docker
   ```

Now you can run containers that use youki as a runtime.

```console
$ docker run --rm --runtime youki hello-world
```

### Wasmtime

{{< summary-bar feature_name="Wasmtime" >}}

Wasmtime is a
[Bytecode Alliance](https://bytecodealliance.org/)
project, and a Wasm runtime that lets you run Wasm containers.
Running Wasm containers with Docker provides two layers of security.
You get all the benefits from container isolation,
plus the added sandboxing provided by the Wasm runtime environment.

To add Wasmtime as a container runtime, follow these steps:

1. Turn on the [containerd image store](../storage/containerd.md)
   feature in the daemon configuration file.

   ```json
   {
     "features": {
       "containerd-snapshotter": true
     }
   }
   ```

2. Restart the Docker daemon.

   ```console
   # systemctl restart docker
   ```

3. Install the Wasmtime containerd shim on `PATH`.

   The following command Dockerfile builds the Wasmtime binary from source
   and exports it to `./containerd-shim-wasmtime-v1`.

   ```console
   $ docker build --output . - <<EOF
   FROM rust:latest as build
   RUN cargo install \
       --git https://github.com/containerd/runwasi.git \
       --bin containerd-shim-wasmtime-v1 \
       --root /out \
       containerd-shim-wasmtime
   FROM scratch
   COPY --from=build /out/bin /
   EOF
   ```

   Put the binary in a directory on `PATH`.

   ```console
   $ mv ./containerd-shim-wasmtime-v1 /usr/local/bin
   ```

Now you can run containers that use Wasmtime as a runtime.

```console
$ docker run --rm \
 --runtime io.containerd.wasmtime.v1 \
 --platform wasi/wasm32 \
 michaelirwin244/wasm-example
```

## Related information

- To learn more about the configuration options for container runtimes,
  see [Configure container runtimes](/reference/cli/dockerd.md#configure-container-runtimes).
- You can configure which runtime that the daemon should use as its default.
  Refer to [Configure the default container runtime](/reference/cli/dockerd.md#configure-the-default-container-runtime).


---

# Run containerd in the Docker daemon

*Sección: Engine*

Starting with Docker Engine 29.7.0, the Docker daemon can run containerd in
the same process as `dockerd`. By default, the daemon starts and manages
containerd as a separate process.

> [!CAUTION]
>
> Embedded containerd is an experimental feature. Its behavior may change, or
> the feature may be removed from a future release.

Embedded mode changes how the daemon starts and communicates with containerd.
The embedded server still listens on a containerd socket, but the daemon and
BuildKit reach it over an in-memory connection instead. Task shims continue to
run as separate processes and connect over a socket.

The performance benefit is greatest when Docker uses the containerd image
store.
Any image interactions use containerd's content API for both metadata requests
and the bytes that make up image manifests, configurations, and layers.
A separate containerd process splits these reads and writes into gRPC messages
that cross a Unix socket or named pipe.
Embedded mode sends the same messages over an in-memory connection, avoiding
operating system socket calls and kernel transport for this data-heavy path.

The embedded server doesn't include the container runtime interface (CRI).
You can't enable `embedded-containerd` and `cri-containerd` at the same time.

## Enable embedded containerd

Add the `embedded-containerd` feature to the
[daemon configuration file](index.md#configuration-file):

```json
{
  "features": {
    "embedded-containerd": true
  }
}
```

Restart the Docker daemon:

```console
$ sudo systemctl restart docker
```

The `embedded-containerd` feature takes precedence over a containerd address
set with the `--containerd` daemon flag. This behavior means that packaged
service configurations that set a containerd address don't prevent embedded
containerd from starting.

> [!IMPORTANT]
>
> Embedded containerd keeps its state under the Docker data root, in
> `/var/lib/docker/containerd/daemon` by default. A containerd installed on the
> host keeps its own state elsewhere, such as `/var/lib/containerd`. If the
> daemon used such a containerd before, the containers and images stored there
> aren't available in embedded mode.

You can also enable the feature when starting `dockerd` manually:

```console
$ sudo dockerd --feature embedded-containerd
```

## Verify the configuration

Run `docker info` and check for the experimental mode warning:

```console
$ docker info
...
NOTE: Running with experimental embedded-containerd mode. In a future release,
this mode may be used by default when no system containerd is available, rather
than starting and supervising a separate containerd process. The option used to
enable this mode may also change.
```

## Connect directly to embedded containerd

The embedded server provides an endpoint for containerd clients such as
`ctr` and `nerdctl`. On Linux, the endpoint is
`<exec-root>/containerd/containerd.sock`. With the default daemon
configuration, this path is:

```text
/var/run/docker/containerd/containerd.sock
```

On Windows, the server uses a named pipe by default. Check the Docker daemon startup logs
for the endpoint address.

Docker Engine stores containers in the `moby` containerd namespace by
default. For example, use `ctr` on Linux to list them:

```console
$ sudo ctr --address /var/run/docker/containerd/containerd.sock \
  --namespace moby containers list
```

> [!WARNING]
>
> The endpoint is useful for debugging, but the daemon owns the state behind
> it. Don't treat it as a general-purpose containerd endpoint: its address and
> the layout of the namespaces can change, and changes that other clients make
> can conflict with the daemon.


---

# Use IPv6 networking

*Sección: Engine*

IPv6 is only supported on Docker daemons running on Linux hosts.

## Create an IPv6 network

- Using `docker network create`:

  ```console
  $ docker network create --ipv6 ip6net
  ```

- Using `docker network create`, specifying an IPv6 subnet:

  ```console
  $ docker network create --ipv6 --subnet 2001:db8::/64 ip6net
  ```

- Using a Docker Compose file:

  ```yaml
   networks:
     ip6net:
       enable_ipv6: true
       ipam:
         config:
           - subnet: 2001:db8::/64
  ```

> [!NOTE]
>
> The address `2001:db8::/64` in these examples is
> [reserved for use in documentation][wikipedia-ipv6-reserved].
> Replace it with a valid IPv6 network, for example a
> [Unique Local Address (ULA)][wikipedia-ipv6-ula] subnet from `fd00::/8`.

You can now run containers that attach to the `ip6net` network.

```console
$ docker run --rm --network ip6net -p 80:80 traefik/whoami
```

This publishes port 80 on both IPv6 and IPv4.
You can verify the IPv6 connection by running curl,
connecting to port 80 on the IPv6 loopback address:

```console
$ curl http://[::1]:80
Hostname: ea1cfde18196
IP: 127.0.0.1
IP: ::1
IP: 172.17.0.2
IP: 2001:db8::2
IP: fe80::42:acff:fe11:2
RemoteAddr: [2001:db8::1]:37574
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.1.2
Accept: */*
```

## Use IPv6 for the default bridge network

The following steps show you how to use IPv6 on the default bridge network.

1. Edit the Docker daemon configuration file,
   located at `/etc/docker/daemon.json`. Configure the following parameters:

   ```json
   {
     "ipv6": true,
     "fixed-cidr-v6": "2001:db8:1::/64"
   }
   ```

   > [!NOTE]
   >
   > The address `2001:db8:1::/64` in this example is
   > [reserved for use in documentation][wikipedia-ipv6-reserved].
   > Replace it with a valid IPv6 network, for example a
   > [Unique Local Address (ULA)][wikipedia-ipv6-ula] subnet from `fd00::/8`.

   - `ipv6` enables IPv6 networking on the default network.
   - `fixed-cidr-v6` assigns a subnet to the default bridge network,
     enabling dynamic IPv6 address allocation.
   - `ip6tables` enables additional IPv6 packet filter rules, providing network
     isolation and port mapping. It is enabled by-default, but can be disabled.

2. Save the configuration file.
3. Restart the Docker daemon for your changes to take effect.

   ```console
   $ sudo systemctl restart docker
   ```

You can now run containers on the default bridge network.

```console
$ docker run --rm -p 80:80 traefik/whoami
```

This publishes port 80 on both IPv6 and IPv4.
You can verify the IPv6 connection by making a request
to port 80 on the IPv6 loopback address:

```console
$ curl http://[::1]:80
Hostname: ea1cfde18196
IP: 127.0.0.1
IP: ::1
IP: 172.17.0.2
IP: 2001:db8:1::242:ac12:2
IP: fe80::42:acff:fe12:2
RemoteAddr: [2001:db8:1::1]:35558
GET / HTTP/1.1
Host: [::1]
User-Agent: curl/8.1.2
Accept: */*
```

## Dynamic IPv6 subnet allocation

If you don't explicitly configure subnets for user-defined networks,
using `docker network create --subnet=<your-subnet>`,
those networks use the default address pools of the daemon as a fallback.
This also applies to networks created from a Docker Compose file,
with `enable_ipv6` set to `true`.

If no IPv6 pools are included in Docker Engine's `default-address-pools`,
and no `--subnet` option is given, [Unique Local Addresses (ULAs)][wikipedia-ipv6-ula]
will be used when IPv6 is enabled. These `/64` subnets include a 40-bit
Global ID based on the Docker Engine's randomly generated ID, to give a
high probability of uniqueness.

The built-in default address pool configuration is shown in [Subnet allocation](../network/index.md#subnet-allocation).
It does not include any IPv6 pools.

To use different pools of IPv6 subnets for dynamic address allocation,
you must manually configure address pools of the daemon to include:

- The default IPv4 address pools
- One or more IPv6 pools of your own

The following example shows a valid configuration with IPv4 and IPv6 pools,
both pools provide 256 subnets. IPv4 subnets with prefix length `/24` will
be allocated from a `/16` pool. IPv6 subnets with prefix length `/64` will
be allocated from a `/56` pool.

```json
{
  "default-address-pools": [
    { "base": "172.17.0.0/16", "size": 24 },
    { "base": "2001:db8::/56", "size": 64 }
  ]
}
```

> [!NOTE]
>
> The address `2001:db8::` in this example is
> [reserved for use in documentation][wikipedia-ipv6-reserved].
> Replace it with a valid IPv6 network.
>
> The default IPv4 pools are from the private address range,
> similar to the default IPv6 [ULA][wikipedia-ipv6-ula] networks.

See [Subnet allocation](../network/index.md#subnet-allocation) for more information about
`default-address-pools`.

[wikipedia-ipv6-reserved]: https://en.wikipedia.org/wiki/Reserved_IP_addresses#IPv6
[wikipedia-ipv6-ula]: https://en.wikipedia.org/wiki/Unique_local_address

## Docker in Docker

On a host using `xtables` (legacy `iptables`) instead of `nftables`, kernel
module `ip6_tables` must be loaded before an IPv6 Docker network can be created,
It is normally loaded automatically when Docker starts.

However, if you running Docker in Docker that is not based on a recent
version of the [official `docker` image](https://hub.docker.com/_/docker), you
may need to run `modprobe ip6_tables` on your host. Alternatively, use daemon
option `--ip6tables=false` to disable `ip6tables` for the containerized Docker
Engine.

## Next steps

- [Networking overview](../network/index.md)


---

# Live restore

*Sección: Engine*

By default, when the Docker daemon terminates, it shuts down running containers.
You can configure the daemon so that containers remain running if the daemon
becomes unavailable. This functionality is called _live restore_. The live restore
option helps reduce container downtime due to daemon crashes, planned outages,
or upgrades.

> [!NOTE]
>
> Live restore isn't supported for Windows containers, but it does work for
> Linux containers running on Docker Desktop for Windows.

## Enable live restore

There are two ways to enable the live restore setting to keep containers alive
when the daemon becomes unavailable. **Only do one of the following**.

- Add the configuration to the daemon configuration file. On Linux, this
  defaults to `/etc/docker/daemon.json`. On Docker Desktop for Mac or Docker
  Desktop for Windows, select the Docker icon from the task bar, then click
  **Settings** -> **Docker Engine**.

  - Use the following JSON to enable `live-restore`.

    ```json
    {
      "live-restore": true
    }
    ```

  - Restart the Docker daemon. On Linux, you can avoid a restart (and avoid any
    downtime for your containers) by reloading the Docker daemon. If you use
    `systemd`, then use the command `systemctl reload docker`. Otherwise, send a
    `SIGHUP` signal to the `dockerd` process.

- If you prefer, you can start the `dockerd` process manually with the
  `--live-restore` flag. This approach isn't recommended because it doesn't
  set up the environment that `systemd` or another process manager would use
  when starting the Docker process. This can cause unexpected behavior.

## Live restore during upgrades

Live restore allows you to keep containers running across Docker daemon updates,
but is only supported when installing patch releases (`YY.MM.x`), not for
major (`YY.MM`) daemon upgrades.

If you skip releases during an upgrade, the daemon may not restore its
connection to the containers. If the daemon can't restore the connection, it
can't manage the running containers and you must stop them manually.

## Live restore upon restart

The live restore option only works to restore containers if the daemon options,
such as bridge IP addresses and graph driver, didn't change. If any of these
daemon-level configuration options have changed, the live restore may not work
and you may need to manually stop the containers.

## Impact of live restore on running containers

If the daemon is down for a long time, running containers may fill up the FIFO
log the daemon normally reads. A full log blocks containers from logging more
data. The default buffer size is 64K. If the buffers fill, you must restart
the Docker daemon to flush them.

On Linux, you can modify the kernel's buffer size by changing
`/proc/sys/fs/pipe-max-size`. You can't modify the buffer size on Docker Desktop for
Mac or Docker Desktop for Windows.

## Live restore and Swarm mode

The live restore option only pertains to standalone containers, and not to Swarm
services. Swarm services are managed by Swarm managers. If Swarm managers are
not available, Swarm services continue to run on worker nodes but can't be
managed until enough Swarm managers are available to maintain a quorum.


---

# Read the daemon logs

*Sección: Engine*

The daemon logs may help you diagnose problems. The logs may be saved in one of
a few locations, depending on the operating system configuration and the logging
subsystem used:

| Operating system             | Location                                                                                                                                 |
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
| Linux                        | Use the command `journalctl -xu docker.service` (or read `/var/log/syslog` or `/var/log/messages`, depending on your Linux Distribution) |
| macOS (Docker Desktop)       | `~/Library/Containers/com.docker.docker/Data/log/vm/init.log`                                                                            |
| Windows (WSL2)               | `%LOCALAPPDATA%\Docker\log\vm\init.log`                                                                                                  |
| Windows (Windows containers) | Logs are in the Windows Event Log                                                                                                        |

On macOS and Windows (WSL2), Docker Desktop writes daemon logs (`dockerd`,
`containerd`, and other VM services) to a single multiplexed `init.log` file
in JSON format. Each line contains a `"component"` field identifying the
service. To follow the logs, open a terminal and use the `tail` command with
the `-f` flag. Logs print until you terminate the command using `CTRL+c`:

```console
$ tail -f ~/Library/Containers/com.docker.docker/Data/log/vm/init.log
{"component":"dockerd","level":"debug","msg":"attach: stdout: begin","time":"2021-07-28T10:21:21.497642089Z"}
{"component":"dockerd","level":"debug","msg":"attach: stderr: begin","time":"2021-07-28T10:21:21.497714291Z"}
...
^C
```

To filter for `dockerd` output only:

```console
$ grep '"component":"dockerd"' ~/Library/Containers/com.docker.docker/Data/log/vm/init.log
```

## Enable debugging

There are two ways to enable debugging. The recommended approach is to set the
`debug` key to `true` in the `daemon.json` file. This method works for every
Docker platform.

1.  Edit the `daemon.json` file, which is usually located in `/etc/docker/`. You
    may need to create this file, if it doesn't yet exist. On macOS or Windows,
    don't edit the file directly. Instead, edit the file through the Docker Desktop settings.

2.  If the file is empty, add the following:

    ```json
    {
      "debug": true
    }
    ```

    If the file already contains JSON, just add the key `"debug": true`, being
    careful to add a comma to the end of the line if it's not the last line
    before the closing bracket. Also verify that if the `log-level` key is set,
    it's set to either `info` or `debug`. `info` is the default, and possible
    values are `debug`, `info`, `warn`, `error`, `fatal`.

3.  Send a `HUP` signal to the daemon to cause it to reload its configuration.
    On Linux hosts, use the following command.

    ```console
    $ sudo kill -SIGHUP $(pidof dockerd)
    ```

    On Windows hosts, restart Docker.

Instead of following this procedure, you can also stop the Docker daemon and
restart it manually with the debug flag `-D`. However, this may result in Docker
restarting with a different environment than the one the hosts' startup scripts
create, and this may make debugging more difficult.

## Force a stack trace to be logged

If the daemon is unresponsive, you can force a full stack trace to be logged by
sending a `SIGUSR1` signal to the daemon.

- **Linux**:

  ```console
  $ sudo kill -SIGUSR1 $(pidof dockerd)
  ```

- **Windows Server**:

  Download [docker-signal](https://github.com/moby/docker-signal).

  Get the process ID of dockerd `Get-Process dockerd`.

  Run the executable with the flag `--pid=<PID of daemon>`.

This forces a stack trace to be logged but doesn't stop the daemon. Daemon logs
show the stack trace or the path to a file containing the stack trace if it was
logged to a file.

The daemon continues operating after handling the `SIGUSR1` signal and dumping
the stack traces to the log. The stack traces can be used to determine the state
of all goroutines and threads within the daemon.

## View stack traces

The Docker daemon log can be viewed by using one of the following methods:

- By running `journalctl -u docker.service` on Linux systems using `systemctl`
- `/var/log/messages`, `/var/log/daemon.log`, or `/var/log/docker.log` on older
  Linux systems

> [!NOTE]
>
> It isn't possible to manually generate a stack trace on Docker Desktop for
> Mac or Docker Desktop for Windows. However, you can click the Docker taskbar
> icon and choose **Troubleshoot** to send information to Docker if you run into
> issues.

Look in the Docker logs for a message like the following:

```text
...goroutine stacks written to /var/run/docker/goroutine-stacks-2017-06-02T193336z.log
```

The locations where Docker saves these stack traces and dumps depends on your
operating system and configuration. You can sometimes get useful diagnostic
information straight from the stack traces and dumps. Otherwise, you can provide
this information to Docker for help diagnosing the problem.


---

# Collect Docker metrics with Prometheus

*Sección: Engine*

[Prometheus](https://prometheus.io/) is an open-source systems monitoring and
alerting toolkit. You can configure Docker as a Prometheus target.

> [!WARNING]
>
> The available metrics and the names of those metrics are in active
> development and may change at any time.

Currently, you can only monitor Docker itself. You can't currently monitor your
application using the Docker target.

## Example

The following example shows you how to configure your Docker daemon, set up
Prometheus to run as a container on your local machine, and monitor your Docker
instance using Prometheus.

### Configure the daemon

To configure the Docker daemon as a Prometheus target, you need to specify the
`metrics-address` in the `daemon.json` configuration file. This daemon expects
the file to be located at one of the following locations by default. If the
file doesn't exist, create it.

- **Linux**: `/etc/docker/daemon.json`
- **Windows Server**: `C:\ProgramData\docker\config\daemon.json`
- **Docker Desktop**: Open the Docker Desktop settings and select **Docker Engine** to edit the file.

Add the following configuration:

```json
{
  "metrics-addr": "127.0.0.1:9323"
}
```

Save the file, or in the case of Docker Desktop for Mac or Docker Desktop for
Windows, save the configuration. Restart Docker.

Docker now exposes Prometheus-compatible metrics on port 9323 via the loopback
interface. You can configure it to use the wildcard address `0.0.0.0` instead,
but this will expose the Prometheus port to the wider network. Consider your
threat model carefully when deciding which option best suits your environment.

### Create a Prometheus configuration

Copy the following configuration file and save it to a location of your choice,
for example `/tmp/prometheus.yml`. This is a stock Prometheus configuration file,
except for the addition of the Docker job definition at the bottom of the file.

```yml
# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: "codelab-monitor"

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first.rules"
  # - "second.rules"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: prometheus

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]

  - job_name: docker
      # metrics_path defaults to '/metrics'
      # scheme defaults to 'http'.

    static_configs:
      - targets: ["host.docker.internal:9323"]
```

### Run Prometheus in a container

Next, start a Prometheus container using this configuration.

```console
$ docker run --name my-prometheus \
    --mount type=bind,source=/tmp/prometheus.yml,destination=/etc/prometheus/prometheus.yml \
    -p 9090:9090 \
    --add-host host.docker.internal=host-gateway \
    prom/prometheus
```

If you're using Docker Desktop, the `--add-host` flag is optional. This flag
makes sure that the host's internal IP gets exposed to the Prometheus
container. Docker Desktop does this by default. The host IP is exposed as the
`host.docker.internal` hostname. This matches the configuration defined in
`prometheus.yml` in the previous step.

### Open the Prometheus Dashboard

Verify that the Docker target is listed at `http://localhost:9090/targets/`.

![Prometheus targets page](images/prometheus-targets.webp)

> [!NOTE]
>
> You can't access the endpoint URLs on this page directly if you use Docker
> Desktop.

### Use Prometheus

Create a graph. Select the **Graphs** link in the Prometheus UI. Choose a metric
from the combo box to the right of the **Execute** button, and click
**Execute**. The screenshot below shows the graph for
`engine_daemon_network_actions_seconds_count`.

![Idle Prometheus report](images/prometheus-graph_idle.webp)

The graph shows a pretty idle Docker instance, unless you're already running
active workloads on your system.

To make the graph more interesting, run a container that uses some network
actions by starting downloading some packages using a package manager:

```console
$ docker run --rm alpine apk add git make musl-dev go
```

Wait a few seconds (the default scrape interval is 15 seconds) and reload your
graph. You should see an uptick in the graph, showing the increased network
traffic caused by the container you just ran.

![Prometheus report showing traffic](images/prometheus-graph_load.webp)

## Next steps

The example provided here shows how to run Prometheus as a container on your
local system. In practice, you'll probably be running Prometheus on another
system or as a cloud service somewhere. You can set up the Docker daemon as a
Prometheus target in such contexts too. Configure the `metrics-addr` of the
daemon and add the address of the daemon as a scrape endpoint in your
Prometheus configuration.

```yaml
- job_name: docker
  static_configs:
    - targets: ["docker.daemon.example:<PORT>"]
```

For more information about Prometheus, refer to the
[Prometheus documentation](https://prometheus.io/docs/introduction/overview/)


---

# Daemon proxy configuration

*Sección: Engine*

<a name="httphttps-proxy"><!-- included for deep-links to old section --></a>

If your organization uses a proxy server to connect to the internet, you may
need to configure the Docker daemon to use the proxy server. The daemon uses
a proxy server to access images stored on Docker Hub and other registries,
and to reach other nodes in a Docker swarm.

This page describes how to configure a proxy for the Docker daemon. For
instructions on configuring proxy settings for the Docker CLI, see [Configure
Docker CLI to use a proxy server](../cli/proxy.md).

> [!IMPORTANT]
> Proxy configurations specified in the `daemon.json` are ignored by Docker
> Desktop. If you use Docker Desktop, you can configure proxies using the
> [Docker Desktop settings](../../desktop/settings-and-maintenance/settings.md#proxies).

There are two ways you can configure these settings:

- [Configuring the daemon](#daemon-configuration) through a configuration file or CLI flags
- Setting [environment variables](#environment-variables) on the system

Configuring the daemon directly takes precedence over environment variables.

## Daemon configuration

You may configure proxy behavior for the daemon in the `daemon.json` file,
or using CLI flags for the `--http-proxy` or `--https-proxy` flags for the
`dockerd` command. Configuration using `daemon.json` is recommended.

```json
{
  "proxies": {
    "http-proxy": "http://proxy.example.com:3128",
    "https-proxy": "http://proxy.example.com:3128",
    "no-proxy": "*.test.example.com,.example.org,127.0.0.0/8"
  }
}
```

After changing the configuration file, restart the daemon for the proxy configuration to take effect:

```console
$ sudo systemctl restart docker
```

## Environment variables

The Docker daemon checks the following environment variables in its start-up
environment to configure HTTP or HTTPS proxy behavior:

- `HTTP_PROXY`
- `http_proxy`
- `HTTPS_PROXY`
- `https_proxy`
- `NO_PROXY`
- `no_proxy`

### systemd unit file

If you're running the Docker daemon as a systemd service, you can create a
systemd drop-in file that sets the variables for the `docker` service.

> **Note for rootless mode**
>
> The location of systemd configuration files are different when running Docker
> in [rootless mode](/manuals/engine/security/rootless.md). When running in
> rootless mode, Docker is started as a user-mode systemd service, and uses
> files stored in each users' home directory in
> `~/.config/systemd/<user>/docker.service.d/`. In addition, `systemctl` must
> be executed without `sudo` and with the `--user` flag. Select the "Rootless
> mode" tab if you are running Docker in rootless mode.

{{< tabs >}}
{{< tab name="Regular install" >}}

1. Create a systemd drop-in directory for the `docker` service:

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

2. Create a file named `/etc/systemd/system/docker.service.d/http-proxy.conf`
   that adds the `HTTP_PROXY` environment variable:

   ```systemd
   [Service]
   Environment="HTTP_PROXY=http://proxy.example.com:3128"
   ```

   To proxy HTTPS requests, set the `HTTPS_PROXY` environment
   variable:

   ```systemd
   [Service]
   Environment="HTTPS_PROXY=http://proxy.example.com:3128"
   ```

   Multiple environment variables can be set; to set both an HTTP and an
   HTTPS proxy;

   ```systemd
   [Service]
   Environment="HTTP_PROXY=http://proxy.example.com:3128"
   Environment="HTTPS_PROXY=http://proxy.example.com:3128"
   ```

   > [!NOTE]
   >
   > Special characters in the proxy value, such as `#?!()[]{}`, must be double
   > escaped using `%%`. For example:
   >
   > ```systemd
   > [Service]
   > Environment="HTTP_PROXY=http://domain%%5Cuser:complex%%23pass@proxy.example.com:3128/"
   > ```

3. If you have internal Docker registries that you need to contact without
   proxying, you can specify them via the `NO_PROXY` environment variable.

   The `NO_PROXY` variable specifies a string that contains comma-separated
   values for hosts that should be excluded from proxying. These are the options
   you can specify to exclude hosts:
   - IP address prefix (`1.2.3.4`)
   - Domain name, or a special DNS label (`*`)
   - A domain name matches that name and all subdomains. A domain name with a
     leading "." matches subdomains only. For example, given the domains
     `foo.example.com` and `example.com`:
     - `example.com` matches `example.com` and `foo.example.com`, and
     - `.example.com` matches only `foo.example.com`
   - A single asterisk (`*`) indicates that no proxying should be done
   - Literal port numbers are accepted by IP address prefixes (`1.2.3.4:80`) and
     domain names (`foo.example.com:80`)

   Example:

   ```systemd
   [Service]
   Environment="HTTP_PROXY=http://proxy.example.com:3128"
   Environment="HTTPS_PROXY=http://proxy.example.com:3128"
   Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp"
   ```

4. Flush changes and restart Docker

   ```console
   $ sudo systemctl daemon-reload
   $ sudo systemctl restart docker
   ```

5. Verify that the configuration has been loaded and matches the changes you
   made, for example:

   ```console
   $ sudo systemctl show --property=Environment docker

   Environment=HTTP_PROXY=http://proxy.example.com:3128 HTTPS_PROXY=http://proxy.example.com:3128 NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp
   ```

{{< /tab >}}
{{< tab name="Rootless mode" >}}

1. Create a systemd drop-in directory for the `docker` service:

   ```console
   $ mkdir -p ~/.config/systemd/user/docker.service.d
   ```

2. Create a file named `~/.config/systemd/user/docker.service.d/http-proxy.conf`
   that adds the `HTTP_PROXY` environment variable:

   ```systemd
   [Service]
   Environment="HTTP_PROXY=http://proxy.example.com:3128"
   ```

   To proxy HTTPS requests, set the `HTTPS_PROXY` environment
   variable:

   ```systemd
   [Service]
   Environment="HTTPS_PROXY=http://proxy.example.com:3128"
   ```

   Multiple environment variables can be set; to set both an HTTP and an
   HTTPS proxy;

   ```systemd
   [Service]
   Environment="HTTP_PROXY=http://proxy.example.com:3128"
   Environment="HTTPS_PROXY=http://proxy.example.com:3128"
   ```

   > [!NOTE]
   >
   > Special characters in the proxy value, such as `#?!()[]{}`, must be double
   > escaped using `%%`. For example:
   >
   > ```systemd
   > [Service]
   > Environment="HTTP_PROXY=http://domain%%5Cuser:complex%%23pass@proxy.example.com:3128/"
   > ```

3. If you have internal Docker registries that you need to contact without
   proxying, you can specify them via the `NO_PROXY` environment variable.

   The `NO_PROXY` variable specifies a string that contains comma-separated
   values for hosts that should be excluded from proxying. These are the options
   you can specify to exclude hosts:
   - IP address prefix (`1.2.3.4`)
   - Domain name, or a special DNS label (`*`)
   - A domain name matches that name and all subdomains. A domain name with a
     leading "." matches subdomains only. For example, given the domains
     `foo.example.com` and `example.com`:
     - `example.com` matches `example.com` and `foo.example.com`, and
     - `.example.com` matches only `foo.example.com`
   - A single asterisk (`*`) indicates that no proxying should be done
   - Literal port numbers are accepted by IP address prefixes (`1.2.3.4:80`) and
     domain names (`foo.example.com:80`)

   Example:

   ```systemd
   [Service]
   Environment="HTTP_PROXY=http://proxy.example.com:3128"
   Environment="HTTPS_PROXY=http://proxy.example.com:3128"
   Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp"
   ```

4. Flush changes and restart Docker

   ```console
   $ systemctl --user daemon-reload
   $ systemctl --user restart docker
   ```

5. Verify that the configuration has been loaded and matches the changes you
   made, for example:

   ```console
   $ systemctl --user show --property=Environment docker

   Environment=HTTP_PROXY=http://proxy.example.com:3128 HTTPS_PROXY=http://proxy.example.com:3128 NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp
   ```

{{< /tab >}}
{{< /tabs >}}


---

# Configure remote access for Docker daemon

*Sección: Engine*

By default, the Docker daemon listens for connections on a Unix socket to accept
requests from local clients. You can configure Docker to accept requests
from remote clients by configuring it to listen on an IP address and port as well
as the Unix socket.

<!-- prettier-ignore -->
> [!WARNING]
>
> Configuring Docker to accept connections from remote clients can leave you
> vulnerable to unauthorized access to the host and other attacks.
>
> It's critically important that you understand the security implications of opening Docker to the network.
> If steps aren't taken to secure the connection, it's possible for remote non-root users to gain root access on the host.
>
> Remote access without TLS is **not recommended**, and will require explicit opt-in in a future release.
> For more information on how to use TLS certificates to secure this connection, see
> [Protect the Docker daemon socket](../security/protect-access.md).

## Enable remote access

You can enable remote access to the daemon either using a `docker.service` systemd unit file for Linux distributions using systemd.
Or you can use the `daemon.json` file, if your distribution doesn't use systemd.

Configuring Docker to listen for connections using both the systemd unit file
and the `daemon.json` file causes a conflict that prevents Docker from starting.

### Configuring remote access with systemd unit file

1. Use the command `sudo systemctl edit docker.service` to open an override file
   for `docker.service` in a text editor.

2. Add or modify the following lines, substituting your own values.

   ```systemd
   [Service]
   ExecStart=
   ExecStart=/usr/bin/dockerd -H fd:// -H tcp://127.0.0.1:2375
   ```

3. Save the file.

4. Reload the `systemctl` configuration.

   ```console
   $ sudo systemctl daemon-reload
   ```

5. Restart Docker.

   ```console
   $ sudo systemctl restart docker.service
   ```

6. Verify that the change has gone through.

   ```console
   $ sudo netstat -lntp | grep dockerd
   tcp        0      0 127.0.0.1:2375          0.0.0.0:*               LISTEN      3758/dockerd
   ```

### Configuring remote access with `daemon.json`

1. Set the `hosts` array in the `/etc/docker/daemon.json` to connect to the Unix
   socket and an IP address, as follows:

   ```json
   {
     "hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]
   }
   ```

2. Restart Docker.

3. Verify that the change has gone through.

   ```console
   $ sudo netstat -lntp | grep dockerd
   tcp        0      0 127.0.0.1:2375          0.0.0.0:*               LISTEN      3758/dockerd
   ```

### Allow access to the remote API through a firewall

If you run a firewall on the same host as you run Docker, and you want to access
the Docker Remote API from another remote host, you must configure your firewall
to allow incoming connections on the Docker port. The default port is `2376` if
you're using TLS encrypted transport, or `2375` otherwise.

Two common firewall daemons are:

- [Uncomplicated Firewall (ufw)](https://help.ubuntu.com/community/UFW), often
  used for Ubuntu systems.
- [firewalld](https://firewalld.org), often used for RPM-based systems.

Consult the documentation for your OS and firewall. The following information
might help you get started. The settings used in this instruction are
permissive, and you may want to use a different configuration that locks your
system down more.

- For ufw, set `DEFAULT_FORWARD_POLICY="ACCEPT"` in your configuration.

- For firewalld, add rules similar to the following to your policy. One for
  incoming requests, and one for outgoing requests.

  ```xml
  <direct>
    [ <rule ipv="ipv6" table="filter" chain="FORWARD_direct" priority="0"> -i zt0 -j ACCEPT </rule> ]
    [ <rule ipv="ipv6" table="filter" chain="FORWARD_direct" priority="0"> -o zt0 -j ACCEPT </rule> ]
  </direct>
  ```

  Make sure that the interface names and chain names are correct.

## Additional information

For more detailed information on configuration options for remote access to the daemon, refer to the
[dockerd CLI reference](/reference/cli/dockerd/#bind-docker-to-another-hostport-or-a-unix-socket).


---

# Start the daemon

*Sección: Engine*

This page shows how to start the daemon, either manually or using OS utilities.

## Start the daemon using operating system utilities

On a typical installation the Docker daemon is started by a system utility, not
manually by a user. This makes it easier to automatically start Docker when the
machine reboots.

The command to start Docker depends on your operating system. Check the correct
page under [Install Docker](../install/index.md).

### Start with systemd

On some operating systems, like Ubuntu and Debian, the Docker daemon service
starts automatically. Use the following command to start it manually:

```console
$ sudo systemctl start docker
```

If you want Docker to start at boot, see
[Configure Docker to start on boot](../install/linux-postinstall.md#configure-docker-to-start-on-boot-with-systemd).

## Start the daemon manually

If you don't want to use a system utility to manage the Docker daemon, or just
want to test things out, you can manually run it using the `dockerd` command.
You may need to use `sudo`, depending on your operating system configuration.

When you start Docker this way, it runs in the foreground and sends its logs
directly to your terminal.

```console
$ dockerd

INFO[0000] +job init_networkdriver()
INFO[0000] +job serveapi(unix:///var/run/docker.sock)
INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
```

To stop Docker when you have started it manually, issue a `Ctrl+C` in your
terminal.


---

# Troubleshooting the Docker daemon

*Sección: Engine*

This page describes how to troubleshoot and debug the daemon if you run into
issues.

You can turn on debugging on the daemon to learn about the runtime activity of
the daemon and to aid in troubleshooting. If the daemon is unresponsive, you can
also [force a full stack trace](logs.md#force-a-stack-trace-to-be-logged) of all
threads to be added to the daemon log by sending the `SIGUSR` signal to the
Docker daemon.

## Daemon

### Unable to connect to the Docker daemon

```text
Cannot connect to the Docker daemon. Is 'docker daemon' running on this host?
```

This error may indicate:

- The Docker daemon isn't running on your system. Start the daemon and try
  running the command again.
- Your Docker client is attempting to connect to a Docker daemon on a different
  host, and that host is unreachable.

### Check whether Docker is running

The operating-system independent way to check whether Docker is running is to
ask Docker, using the `docker info` command.

You can also use operating system utilities, such as
`sudo systemctl is-active docker` or `sudo status docker` or
`sudo service docker status`, or checking the service status using Windows
utilities.

Finally, you can check in the process list for the `dockerd` process, using
commands like `ps` or `top`.

#### Check which host your client is connecting to

To see which host your client is connecting to, check the value of the
`DOCKER_HOST` variable in your environment.

```console
$ env | grep DOCKER_HOST
```

If this command returns a value, the Docker client is set to connect to a Docker
daemon running on that host. If it's unset, the Docker client is set to connect
to the Docker daemon running on the local host. If it's set in error, use the
following command to unset it:

```console
$ unset DOCKER_HOST
```

You may need to edit your environment in files such as `~/.bashrc` or
`~/.profile` to prevent the `DOCKER_HOST` variable from being set erroneously.

If `DOCKER_HOST` is set as intended, verify that the Docker daemon is running on
the remote host and that a firewall or network outage isn't preventing you from
connecting.

### Troubleshoot conflicts between the `daemon.json` and startup scripts

If you use a `daemon.json` file and also pass options to the `dockerd` command
manually or using start-up scripts, and these options conflict, Docker fails to
start with an error such as:

```text
unable to configure the Docker daemon with file /etc/docker/daemon.json:
the following directives are specified both as a flag and in the configuration
file: hosts: (from flag: [unix:///var/run/docker.sock], from file: [tcp://127.0.0.1:2376])
```

If you see an error similar to this one and you are starting the daemon manually
with flags, you may need to adjust your flags or the `daemon.json` to remove the
conflict.

> [!NOTE]
>
> If you see this specific error message about `hosts`, continue to the
> [next section](#configure-the-daemon-host-with-systemd)
> for a workaround.

If you are starting Docker using your operating system's init scripts, you may
need to override the defaults in these scripts in ways that are specific to the
operating system.

#### Configure the daemon host with systemd

One notable example of a configuration conflict that's difficult to
troubleshoot is when you want to specify a different daemon address from the
default. Docker listens on a socket by default. On Debian and Ubuntu systems
using `systemd`, this means that a host flag `-H` is always used when starting
`dockerd`. If you specify a `hosts` entry in the `daemon.json`, this causes a
configuration conflict and results in the Docker daemon failing to start.

To work around this problem, create a new file
`/etc/systemd/system/docker.service.d/docker.conf` with the following contents,
to remove the `-H` argument that's used when starting the daemon by default.

```systemd
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
```

There are other times when you might need to configure `systemd` with Docker,
such as [configuring a HTTP or HTTPS proxy](proxy.md).

> [!NOTE]
>
> If you override this option without specifying a `hosts` entry in the
> `daemon.json` or a `-H` flag when starting Docker manually, Docker fails to
> start.

Run `sudo systemctl daemon-reload` before attempting to start Docker. If Docker
starts successfully, it's now listening on the IP address specified in the
`hosts` key of the `daemon.json` instead of a socket.

> [!IMPORTANT]
>
> Setting `hosts` in the `daemon.json` isn't supported on Docker
> Desktop for Windows or Docker Desktop for Mac.

### Out of memory issues

If your containers attempt to use more memory than the system has available, you
may experience an Out of Memory (OOM) exception, and a container, or the Docker
daemon, might be stopped by the kernel OOM killer. To prevent this from
happening, ensure that your application runs on hosts with adequate memory and
see
[Understand the risks of running out of memory](../containers/resource-constraints.md#understand-the-risks-of-running-out-of-memory).

### Kernel compatibility

Docker can't run correctly if your kernel is older than version 3.10, or if it's
missing kernel modules. To check kernel compatibility, you can download and run
the
[`check-config.sh`](https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh)
script.

```console
$ curl https://raw.githubusercontent.com/docker/docker/master/contrib/check-config.sh > check-config.sh

$ bash ./check-config.sh
```

The script only works on Linux.

### Kernel cgroup swap limit capabilities

On Ubuntu or Debian hosts, you may see messages similar to the following when
working with an image.

```text
WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.
```

If you don't need these capabilities, you can ignore the warning.

You can turn on these capabilities on Ubuntu or Debian by following these
instructions. Memory and swap accounting incur an overhead of about 1% of the
total available memory and a 10% overall performance degradation, even when
Docker isn't running.

1. Log into the Ubuntu or Debian host as a user with `sudo` privileges.

2. Edit the `/etc/default/grub` file. Add or edit the `GRUB_CMDLINE_LINUX` line
   to add the following two key-value pairs:

   ```text
   GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"
   ```

   Save and close the file.

3. Update the GRUB boot loader.

   ```console
   $ sudo update-grub
   ```

   An error occurs if your GRUB configuration file has incorrect syntax. In this
   case, repeat steps 2 and 3.

   The changes take effect when you reboot the system.

## Networking

### IP forwarding problems

If you manually configure your network using `systemd-network` with systemd
version 219 or later, Docker containers may not be able to access your network.
Beginning with systemd version 220, the forwarding setting for a given network
(`net.ipv4.conf.<interface>.forwarding`) defaults to off. This setting prevents
IP forwarding. It also conflicts with Docker's behavior of enabling the
`net.ipv4.conf.all.forwarding` setting within containers.

To work around this on RHEL, CentOS, or Fedora, edit the `<interface>.network`
file in `/usr/lib/systemd/network/` on your Docker host, for example,
`/usr/lib/systemd/network/80-container-host0.network`.

Add the following block within the `[Network]` section.

```systemd
[Network]
...
IPForward=kernel
# OR
IPForward=true
```

This configuration allows IP forwarding from the container as expected.

### DNS resolver issues

```console
DNS resolver found in resolv.conf and containers can't use it
```

Linux desktop environments often have a network manager program running, that
uses `dnsmasq` to cache DNS requests by adding them to `/etc/resolv.conf`. The
`dnsmasq` instance runs on a loopback address such as `127.0.0.1` or
`127.0.1.1`. It speeds up DNS look-ups and provides DHCP services. Such a
configuration doesn't work within a Docker container. The Docker container uses
its own network namespace, and resolves loopback addresses such as `127.0.0.1`
to itself, and it's unlikely to be running a DNS server on its own loopback
address.

If Docker detects that no DNS server referenced in `/etc/resolv.conf` is a fully
functional DNS server, the following warning occurs:

```text
WARNING: Local (127.0.0.1) DNS resolver found in resolv.conf and containers
can't use it. Using default external servers : [8.8.8.8 8.8.4.4]
```

If you see this warning, first check to see if you use `dnsmasq`:

```console
$ ps aux | grep dnsmasq
```

If your container needs to resolve hosts which are internal to your network, the
public nameservers aren't adequate. You have two choices:

- Specify DNS servers for Docker to use.
- Turn off `dnsmasq`.

  Turning off `dnsmasq` adds the IP addresses of actual DNS nameservers to
  `/etc/resolv.conf`, and you lose the benefits of `dnsmasq`.

You only need to use one of these methods.

### Specify DNS servers for Docker

The default location of the configuration file is `/etc/docker/daemon.json`. You
can change the location of the configuration file using the `--config-file`
daemon flag. The following instruction assumes that the location of the
configuration file is `/etc/docker/daemon.json`.

1. Create or edit the Docker daemon configuration file, which defaults to
   `/etc/docker/daemon.json` file, which controls the Docker daemon
   configuration.

   ```console
   $ sudo nano /etc/docker/daemon.json
   ```

2. Add a `dns` key with one or more DNS server IP addresses as values.

   ```json
   {
     "dns": ["8.8.8.8", "8.8.4.4"]
   }
   ```

   If the file has existing contents, you only need to add or edit the `dns`
   line. If your internal DNS server can't resolve public IP addresses, include
   at least one DNS server that can. Doing so allows you to connect to Docker
   Hub, and your containers to resolve internet domain names.

   Save and close the file.

3. Restart the Docker daemon.

   ```console
   $ sudo service docker restart
   ```

4. Verify that Docker can resolve external IP addresses by trying to pull an
   image:

   ```console
   $ docker pull hello-world
   ```

5. If necessary, verify that Docker containers can resolve an internal hostname
   by pinging it.

   ```console
   $ docker run --rm -it alpine ping -c4 <my_internal_host>

   PING google.com (192.168.1.2): 56 data bytes
   64 bytes from 192.168.1.2: seq=0 ttl=41 time=7.597 ms
   64 bytes from 192.168.1.2: seq=1 ttl=41 time=7.635 ms
   64 bytes from 192.168.1.2: seq=2 ttl=41 time=7.660 ms
   64 bytes from 192.168.1.2: seq=3 ttl=41 time=7.677 ms
   ```

### Turn off `dnsmasq`

{{< tabs >}}
{{< tab name="Ubuntu" >}}

If you prefer not to change the Docker daemon's configuration to use a specific
IP address, follow these instructions to turn off `dnsmasq` in NetworkManager.

1. Edit the `/etc/NetworkManager/NetworkManager.conf` file.

2. Comment out the `dns=dnsmasq` line by adding a `#` character to the beginning
   of the line.

   ```text
   # dns=dnsmasq
   ```

   Save and close the file.

3. Restart both NetworkManager and Docker. As an alternative, you can reboot
   your system.

   ```console
   $ sudo systemctl restart network-manager
   $ sudo systemctl restart docker
   ```

{{< /tab >}}
{{< tab name="RHEL, CentOS, or Fedora" >}}

To turn off `dnsmasq` on RHEL, CentOS, or Fedora:

1. Turn off the `dnsmasq` service:

   ```console
   $ sudo systemctl stop dnsmasq
   $ sudo systemctl disable dnsmasq
   ```

2. Configure the DNS servers manually using the
   [Red Hat documentation](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/configuring_and_managing_networking/configuring-the-order-of-dns-servers_configuring-and-managing-networking).

{{< /tab >}}
{{< /tabs >}}

### Docker networks disappearing

If a Docker network, such as the `docker0` bridge or a custom network, randomly
disappears or otherwise appears to be working incorrectly, it could be because
another service is interfering with or modifying Docker interfaces. Tools that
manage networking interfaces on the host are known to sometimes also
inappropriately modify Docker interfaces.

Refer to the following sections for instructions on how to configure your
network manager to set Docker interfaces as un-managed, depending on the
network management tools that exist on the host:

- If `netscript` is installed, consider [uninstalling it](#uninstall-netscript)
- Configure the network manager to [treat Docker interfaces as un-managed](#un-manage-docker-interfaces)
- If you're using Netplan, you may need to [apply a custom Netplan configuration](#prevent-netplan-from-overriding-network-configuration)

#### Uninstall `netscript`

If `netscript` is installed on your system, you can likely fix this issue by
uninstalling it. For example, on a Debian-based system:

```console
$ sudo apt-get remove netscript-2.4
```

#### Un-manage Docker interfaces

In some cases, the network manager will attempt to manage Docker interfaces by
default. You can try to explicitly flag Docker networks as un-managed by
editing your system's network configuration settings.

{{< tabs >}}
{{< tab name="NetworkManager" >}}

If you're using `NetworkManager`, edit your system network configuration under
`/etc/network/interfaces`

1. Create a file at `/etc/network/interfaces.d/20-docker0` with the following
   contents:

   ```text
   iface docker0 inet manual
   ```

   Note that this example configuration only "un-manages" the default `docker0`
   bridge, not custom networks.

2. Restart `NetworkManager` for the configuration change to take effect.

   ```console
   $ systemctl restart NetworkManager
   ```

3. Verify that the `docker0` interface has the `unmanaged` state.

   ```console
   $ nmcli device
   ```

{{< /tab >}}
{{< tab name="systemd-networkd" >}}

If you're running Docker on a system using `systemd-networkd` as a networking
daemon, configure the Docker interfaces as un-managed by creating configuration
files under `/etc/systemd/network`:

1. Create `/etc/systemd/network/docker.network` with the following contents:

   ```ini
   # Ensure that the Docker interfaces are un-managed

   [Match]
   Name=docker0 br-* veth*

   [Link]
   Unmanaged=yes

   ```

2. Reload the configuration.

   ```console
   $ sudo systemctl restart systemd-networkd
   ```

3. Restart the Docker daemon.

   ```console
   $ sudo systemctl restart docker
   ```

4. Verify that the Docker interfaces have the `unmanaged` state.

   ```console
   $ networkctl
   ```

{{< /tab >}}
{{< /tabs >}}

### Prevent Netplan from overriding network configuration

On systems that use [Netplan](https://netplan.io/) through
[`cloud-init`](https://cloudinit.readthedocs.io/en/latest/index.html), you may
need to apply a custom configuration to prevent `netplan` from overriding the
network manager configuration:

1. Follow the steps in [Un-manage Docker interfaces](#un-manage-docker-interfaces)
   for creating the network manager configuration.
2. Create a `netplan` configuration file under `/etc/netplan/50-cloud-init.yml`.

   The following example configuration file is a starting point.
   Adjust it to match the interfaces you want to un-manage.
   Incorrect configuration can lead to network connectivity issues.

   ```yaml {title="/etc/netplan/50-cloud-init.yml"}
   network:
     ethernets:
       all:
         dhcp4: true
         dhcp6: true
         match:
           # edit this filter to match whatever makes sense for your system
           name: en*
     renderer: networkd
     version: 2
   ```

3. Apply the new Netplan configuration.

   ```console
   $ sudo netplan apply
   ```

4. Restart the Docker daemon:

   ```console
   $ sudo systemctl restart docker
   ```

5. Verify that the Docker interfaces have the `unmanaged` state.

   ```console
   $ networkctl
   ```

## Volumes

### Unable to remove filesystem

```text
Error: Unable to remove filesystem
```

Some container-based utilities, such
as [Google cAdvisor](https://github.com/google/cadvisor), mount Docker system
directories, such as `/var/lib/docker/`, into a container. For instance, the
documentation for `cadvisor` instructs you to run the `cadvisor` container as
follows:

```console
$ sudo docker run \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:rw \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --publish=8080:8080 \
  --detach=true \
  --name=cadvisor \
  google/cadvisor:latest
```

When you bind-mount `/var/lib/docker/`, this effectively mounts all resources of
all other running containers as filesystems within the container which mounts
`/var/lib/docker/`. When you attempt to remove any of these containers, the
removal attempt may fail with an error like the following:

```text
Error: Unable to remove filesystem for
74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515:
remove /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm:
Device or resource busy
```

The problem occurs if the container which bind-mounts `/var/lib/docker/`
uses `statfs` or `fstatfs` on filesystem handles within `/var/lib/docker/`
and does not close them.

Typically, we would advise against bind-mounting `/var/lib/docker` in this way.
However, `cAdvisor` requires this bind-mount for core functionality.

If you are unsure which process is causing the path mentioned in the error to
be busy and preventing it from being removed, you can use the `lsof` command
to find its process. For instance, for the error above:

```console
$ sudo lsof /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm
```

To work around this problem, stop the container which bind-mounts
`/var/lib/docker` and try again to remove the other container.


---

# Install Docker Engine

*Sección: Engine*

This section describes how to install Docker Engine on Linux. Docker Engine is
also available for Windows, macOS, and Linux,
through Docker Desktop. For instructions on how to install Docker Desktop,
see: [Overview of Docker Desktop](../../desktop/index.md).

## Installation procedures for supported platforms

Click on a platform's link to view the relevant installation procedure.

| Platform                                       | x86_64 / amd64 | arm64 / aarch64 | arm (32-bit) | ppc64le | s390x |
| :--------------------------------------------- | :------------: | :-------------: | :----------: | :-----: | :---: |
| [CentOS](centos.md)                            |       ✅       |       ✅        |              |   ✅    |       |
| [Debian](debian.md)                            |       ✅       |       ✅        |      ✅      |   ✅    |       |
| [Fedora](fedora.md)                            |       ✅       |       ✅        |              |   ✅    |       |
| [Raspberry Pi OS (32-bit)](raspberry-pi-os.md) |                |                 |      ⚠️      |         |       |
| [RHEL](rhel.md)                                |       ✅       |       ✅        |              |         |  ✅   |
| [Ubuntu](ubuntu.md)                            |       ✅       |       ✅        |      ✅      |   ✅    |  ✅   |
| [Binaries](binaries.md)                        |       ✅       |       ✅        |      ✅      |         |       |

### Other Linux distributions

> [!NOTE]
>
> While the following instructions may work, Docker doesn't test or verify
> installation on distribution derivatives.

- If you use Debian derivatives such as "BunsenLabs Linux", "Kali Linux" or
  "LMDE" (Debian-based Mint) should follow the installation instructions for
  [Debian](debian.md), substitute the version of your distribution for the
  corresponding Debian release. Refer to the documentation of your distribution to find
  which Debian release corresponds with your derivative version.
- Likewise, if you use Ubuntu derivatives such as "Kubuntu", "Lubuntu" or "Xubuntu"
  you should follow the installation instructions for [Ubuntu](ubuntu.md),
  substituting the version of your distribution for the corresponding Ubuntu release.
  Refer to the documentation of your distribution to find which Ubuntu release
  corresponds with your derivative version.
- Some Linux distributions provide a package of Docker Engine through their
  package repositories. These packages are built and maintained by the Linux
  distribution's package maintainers and may have differences in configuration
  or are built from modified source code. Docker isn't involved in releasing these
  packages and you should report any bugs or issues involving these packages to
  your Linux distribution's issue tracker.

Docker provides [binaries](binaries.md) for manual installation of Docker Engine.
These binaries are statically linked and you can use them on any Linux distribution.

## Release channels

Docker Engine has two types of update channels, **stable** and **test**:

* The **stable** channel gives you the latest versions released for general availability.
* The **test** channel gives you pre-release versions that are ready for testing before
  general availability.

Use the test channel with caution. Pre-release versions include experimental and
early-access features that are subject to breaking changes.

## Support

Docker Engine is an open source project, supported by the Moby project maintainers
and community members. Docker doesn't provide support for Docker Engine.
Docker provides support for Docker products, including Docker Desktop, which uses
Docker Engine as one of its components.

For information about the open source project, refer to the
[Moby project website](https://mobyproject.org/).

### Upgrade path

Patch releases are always backward compatible with its major and minor version.

### Licensing

Commercial use of Docker Engine obtained via Docker Desktop
within larger enterprises (exceeding 250 employees OR with annual revenue surpassing
$10 million USD), requires a [paid subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsEngineInstall).
Apache License, Version 2.0. See [LICENSE](https://github.com/moby/moby/blob/master/LICENSE) for the full license.

## Reporting security issues

If you discover a security issue, we request that you bring it to our attention immediately.

DO NOT file a public issue. Instead, submit your report privately to security@docker.com.

Security reports are greatly appreciated, and Docker will publicly thank you for it.

## Get started

After setting up Docker, you can learn the basics with
[Build and share a containerized application](/get-started/tutorials/run-an-app.md).


---

# Install Docker Engine from binaries

*Sección: Engine*

> [!IMPORTANT]
>
> This page contains information on how to install Docker using binaries. These
> instructions are mostly suitable for testing purposes. We do not recommend
> installing Docker using binaries in production environments as they don't have automatic security updates. The Linux binaries described on this
> page are statically linked, which means that vulnerabilities in build-time
> dependencies are not automatically patched by security updates of your Linux
> distribution.
>
> Updating binaries is also slightly more involved when compared to Docker packages
> installed using a package manager or through Docker Desktop, as it requires
> (manually) updating the installed version whenever there is a new release of
> Docker.
>
> Also, static binaries may not include all functionalities provided by the dynamic
> packages.
>
> On Windows and Mac, we recommend that you install [Docker Desktop](../../desktop/index.md)
> instead. For Linux, we recommend that you follow the instructions specific for
> your distribution.

If you want to try Docker or use it in a testing environment, but you're not on
a supported platform, you can try installing from static binaries. If possible,
you should use packages built for your operating system, and use your operating
system's package management system to manage Docker installation and upgrades.

Static binaries for the Docker daemon binary are only available for Linux (as
`dockerd`) and Windows (as `dockerd.exe`).
Static binaries for the Docker client are available for Linux, Windows, and macOS (as `docker`).

This topic discusses binary installation for Linux, Windows, and macOS:

- [Install daemon and client binaries on Linux](#install-daemon-and-client-binaries-on-linux)
- [Install client binaries on macOS](#install-client-binaries-on-macos)
- [Install server and client binaries on Windows](#install-server-and-client-binaries-on-windows)

## Install daemon and client binaries on Linux

### Prerequisites

Before attempting to install Docker from binaries, be sure your host machine
meets the prerequisites:

- A 64-bit installation
- Version 3.10 or higher of the Linux kernel. The latest version of the kernel
  available for your platform is recommended.
- `iptables` version 1.4 or higher
- `git` version 1.7 or higher
- A `ps` executable, usually provided by `procps` or a similar package.
- [XZ Utils](https://tukaani.org/xz/) 4.9 or higher
- A [properly mounted](
  https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount)
  `cgroupfs` hierarchy; a single, all-encompassing `cgroup` mount
  point is not sufficient. See Github issues
  [#2683](https://github.com/moby/moby/issues/2683),
  [#3485](https://github.com/moby/moby/issues/3485),
  [#4568](https://github.com/moby/moby/issues/4568)).

#### Secure your environment as much as possible

##### OS considerations

Enable SELinux or AppArmor if possible.

It is recommended to use AppArmor or SELinux if your Linux distribution supports
either of the two. This helps improve security and blocks certain
types of exploits. Review the documentation for your Linux distribution for
instructions for enabling and configuring AppArmor or SELinux.

> **Security warning**
>
> If either of the security mechanisms is enabled, do not disable it as a
> work-around to make Docker or its containers run. Instead, configure it
> correctly to fix any problems.

##### Docker daemon considerations

- Enable `seccomp` security profiles if possible. See
  [Enabling `seccomp` for Docker](../security/seccomp.md).

- Enable user namespaces if possible. See the
  [Daemon user namespace options](/reference/cli/dockerd/#daemon-user-namespace-options).

### Install static binaries

1.  Download the static binary archive. Go to
    [https://download.docker.com/linux/static/stable/](https://download.docker.com/linux/static/stable/),
    choose your hardware platform, and download the `.tgz` file relating to the
    version of Docker Engine you want to install.

2.  Extract the archive using the `tar` utility. The `dockerd` and `docker`
    binaries are extracted.

    ```console
    $ tar xzvf /path/to/<FILE>.tar.gz
    ```

3.  **Optional**: Move the binaries to a directory on your executable path, such
    as `/usr/bin/`. If you skip this step, you must provide the path to the
    executable when you invoke `docker` or `dockerd` commands.

    ```console
    $ sudo cp docker/* /usr/bin/
    ```

4.  Start the Docker daemon:

    ```console
    $ sudo dockerd &
    ```

    If you need to start the daemon with additional options, modify the above
    command accordingly or create and edit the file `/etc/docker/daemon.json`
    to add the custom configuration options.

5.  Verify that Docker is installed correctly by running the `hello-world`
    image.

    ```console
    $ sudo docker run hello-world
    ```

    This command downloads a test image and runs it in a container. When the
    container runs, it prints a message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

## Install client binaries on macOS

> [!NOTE]
>
> The following instructions are mostly suitable for testing purposes. The macOS
> binary includes the Docker client only. It does not include the `dockerd` daemon
> which is required to run containers. Therefore, we recommend that you install
> [Docker Desktop](../../desktop/index.md) instead.

The binaries for Mac also do not contain:

- A runtime environment. You must set up a functional engine either in a Virtual Machine, or on a remote Linux machine.
- Docker components such as `buildx` and `docker compose`.

To install client binaries, perform the following steps:

1.  Download the static binary archive. Go to
    [https://download.docker.com/mac/static/stable/](https://download.docker.com/mac/static/stable/) and select `x86_64` (for Mac on Intel chip) or `aarch64` (for Mac on Apple silicon),
    and then download the `.tgz` file relating to the version of Docker Engine you want
    to install.

2.  Extract the archive using the `tar` utility. The `docker` binary is
    extracted.

    ```console
    $ tar xzvf /path/to/<FILE>.tar.gz
    ```

3.  Clear the extended attributes to allow it run.

    ```console
    $ sudo xattr -rc docker
    ```

    Now, when you run the following command, you can see the Docker CLI usage instructions:

    ```console
    $ docker/docker
    ```

4.  **Optional**: Move the binary to a directory on your executable path, such
    as `/usr/local/bin/`. If you skip this step, you must provide the path to the
    executable when you invoke `docker` or `dockerd` commands.

    ```console
    $ sudo cp docker/docker /usr/local/bin/
    ```

5.  Verify that Docker is installed correctly by running the `hello-world`
    image. The value of `<hostname>` is a hostname or IP address running the
    Docker daemon and accessible to the client.

    ```console
    $ sudo docker -H <hostname> run hello-world
    ```

    This command downloads a test image and runs it in a container. When the
    container runs, it prints a message and exits.

## Install server and client binaries on Windows

> [!NOTE]
>
> The following section describes how to install the Docker daemon on Windows
> Server which allows you to run Windows containers only. When you install the
> Docker daemon on Windows Server, the daemon doesn't contain Docker components
> such as `buildx` and `compose`. If you're running Windows 10 or 11,
> we recommend that you install [Docker Desktop](../../desktop/index.md) instead.

Binary packages on Windows include both `dockerd.exe` and `docker.exe`. On Windows,
these binaries only provide the ability to run native Windows containers (not
Linux containers).

To install server and client binaries, perform the following steps:

1. Download the static binary archive. Go to
    [https://download.docker.com/win/static/stable/x86_64](https://download.docker.com/win/static/stable/x86_64) and select the latest version from the list.

2. Run the following PowerShell commands to install and extract the archive to your program files:

    ```powershell
    PS C:\> Expand-Archive /path/to/<FILE>.zip -DestinationPath $Env:ProgramFiles
    ```

3. Register the service and start the Docker Engine:

    ```powershell
    PS C:\> &$Env:ProgramFiles\Docker\dockerd --register-service
    PS C:\> Start-Service docker
    ```

4.  Verify that Docker is installed correctly by running the `hello-world`
    image.

    ```powershell
    PS C:\> &$Env:ProgramFiles\Docker\docker run hello-world:nanoserver
    ```

    This command downloads a test image and runs it in a container. When the
    container runs, it prints a message and exits.

## Upgrade static binaries

To upgrade your manual installation of Docker Engine, first stop any
`dockerd` or `dockerd.exe`  processes running locally, then follow the
regular installation steps to install the new version on top of the existing
version.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# Install Docker Engine on CentOS

*Sección: Engine*

To get started with Docker Engine on CentOS, make sure you
[meet the prerequisites](#prerequisites), and then follow the
[installation steps](#installation-methods).

## Prerequisites

### OS requirements

To install Docker Engine, you need a maintained version of one of the following
CentOS versions:

- CentOS Stream 10
- CentOS Stream 9

The `centos-extras` repository must be enabled. This repository is enabled by
default. If you have disabled it, you need to re-enable it.

### Uninstall old versions

Before you can install Docker Engine, you need to uninstall any conflicting packages.

Your Linux distribution may provide unofficial Docker packages, which may conflict
with the official packages provided by Docker. You must uninstall these packages
before you install the official version of Docker Engine.

```console
$ sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
```

`dnf` might report that you have none of these packages installed.

Images, containers, volumes, and networks stored in `/var/lib/docker/` aren't
automatically removed when you uninstall Docker.

## Installation methods

You can install Docker Engine in different ways, depending on your needs:

- You can
  [set up Docker's repositories](#install-using-the-repository) and install
  from them, for ease of installation and upgrade tasks. This is the
  recommended approach.

- You can download the RPM package,
  [install it manually](#install-from-a-package), and manage
  upgrades completely manually. This is useful in situations such as installing
  Docker on air-gapped systems with no access to the internet.

- In testing and development environments, you can use automated
  [convenience scripts](#install-using-the-convenience-script) to install Docker.

{{% include "engine-license.md" %}}

### Install using the rpm repository {#install-using-the-repository}

Before you install Docker Engine for the first time on a new host machine, you
need to set up the Docker repository. Afterward, you can install and update
Docker from the repository.

#### Set up the repository

Install the `dnf-plugins-core` package (which provides the commands to manage
your DNF repositories) and set up the repository.

```console
$ sudo dnf -y install dnf-plugins-core
$ sudo dnf config-manager --add-repo {{% param "download-url-base" %}}/docker-ce.repo
```

#### Install Docker Engine

1. Install the Docker packages.

   {{< tabs >}}
   {{< tab name="Latest" >}}

   To install the latest version, run:

   ```console
   $ sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   If prompted to accept the GPG key, verify that the fingerprint matches
   `060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35`, and if so, accept it.

   This command installs Docker, but it doesn't start Docker. It also creates a
   `docker` group, however, it doesn't add any users to the group by default.

   {{< /tab >}}
   {{< tab name="Specific version" >}}

   To install a specific version, start by listing the available versions in
   the repository:

   ```console
   $ dnf list docker-ce --showduplicates | sort -r

   docker-ce.x86_64    3:{{% param "docker_ce_version" %}}-1.el9    docker-ce-stable
   docker-ce.x86_64    3:{{% param "docker_ce_version_prev" %}}-1.el9    docker-ce-stable
   <...>
   ```

   The list returned depends on which repositories are enabled, and is specific
   to your version of CentOS (indicated by the `.el9` suffix in this example).

   Install a specific version by its fully qualified package name, which is
   the package name (`docker-ce`) plus the version string (2nd column),
   separated by a hyphen (`-`). For example, `docker-ce-3:{{% param "docker_ce_version" %}}-1.el9`.

   Replace `<VERSION_STRING>` with the desired version and then run the following
   command to install:

   ```console
   $ sudo dnf install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   This command installs Docker, but it doesn't start Docker. It also creates a
   `docker` group, however, it doesn't add any users to the group by default.

   {{< /tab >}}
   {{< /tabs >}}

2. Start Docker Engine.

   ```console
   $ sudo systemctl enable --now docker
   ```

   This configures the Docker systemd service to start automatically when you
   boot your system. If you don't want Docker to start automatically, use `sudo
   systemctl start docker` instead.

3. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, follow the [installation instructions](#install-using-the-repository),
choosing the new version you want to install.

### Install from a package

If you can't use Docker's `rpm` repository to install Docker Engine, you can
download the `.rpm` file for your release and install it manually. You need to
download a new file each time you want to upgrade Docker Engine.

<!-- markdownlint-disable-next-line -->
1. Go to [{{% param "download-url-base" %}}/]({{% param "download-url-base" %}}/)
   and choose your version of CentOS. Then browse to `x86_64/stable/Packages/`
   and download the `.rpm` file for the Docker version you want to install.

2. Install Docker Engine, changing the following path to the path where you downloaded
   the Docker package.

   ```console
   $ sudo dnf install /path/to/package.rpm
   ```

   Docker is installed but not started. The `docker` group is created, but no
   users are added to the group.

3. Start Docker Engine.

   ```console
   $ sudo systemctl enable --now docker
   ```

   This configures the Docker systemd service to start automatically when you
   boot your system. If you don't want Docker to start automatically, use `sudo
   systemctl start docker` instead.

4. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, download the newer package files and repeat the
[installation procedure](#install-from-a-package), using `dnf upgrade`
instead of `dnf install`, and point to the new files.

{{% include "install-script.md" %}}

## Uninstall Docker Engine

1. Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

   ```console
   $ sudo dnf remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
   ```

2. Images, containers, volumes, or custom configuration files on your host
   aren't automatically removed. To delete all images, containers, and volumes:

   ```console
   $ sudo rm -rf /var/lib/docker
   $ sudo rm -rf /var/lib/containerd
   ```

You have to delete any edited configuration files manually.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# Install Docker Engine on Debian

*Sección: Engine*

To get started with Docker Engine on Debian, make sure you
[meet the prerequisites](#prerequisites), and then follow the
[installation steps](#installation-methods).

## Prerequisites

### Firewall limitations

> [!WARNING]
>
> Before you install Docker, make sure you consider the following
> security implications and firewall incompatibilities.

- If you use ufw or firewalld to manage firewall settings, be aware that
  when you expose container ports using Docker, these ports bypass your
  firewall rules. For more information, refer to
  [Docker and ufw](../network/packet-filtering-firewalls.md#docker-and-ufw).
- Docker is only compatible with `iptables-nft` and `iptables-legacy`.
  Firewall rules created with `nft` are not supported on a system with Docker installed.
  Make sure that any firewall rulesets you use are created with `iptables` or `ip6tables`,
  and that you add them to the `DOCKER-USER` chain,
  see [Packet filtering and firewalls](../network/packet-filtering-firewalls.md).

### OS requirements

To install Docker Engine, you need one of these Debian versions:

- Debian Trixie 13 (stable)
- Debian Bookworm 12 (oldstable)

Docker Engine for Debian is compatible with x86_64 (or amd64), armhf (arm/v7),
arm64, and ppc64le (ppc64el) architectures.

### Uninstall old versions

Before you can install Docker Engine, you need to uninstall any conflicting packages.

Your Linux distribution may provide unofficial Docker packages, which may conflict
with the official packages provided by Docker. You must uninstall these packages
before you install the official version of Docker Engine.

The unofficial packages to uninstall are:

- `docker.io`
- `docker-compose`
- `docker-doc`
- `docker-buildx`
- `podman-docker`

Moreover, Docker Engine depends on `containerd` and `runc`. Docker Engine
bundles these dependencies as one bundle: `containerd.io`. If you have
installed the `containerd` or `runc` previously, uninstall them to avoid
conflicts with the versions bundled with Docker Engine.

Run the following command to uninstall all conflicting packages:

```console
$ sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-doc docker-buildx podman-docker containerd runc | cut -f1)
```

`apt` might report that you have none of these packages installed.

Images, containers, volumes, and networks stored in `/var/lib/docker/` aren't
automatically removed when you uninstall Docker. If you want to start with a
clean installation, and prefer to clean up any existing data, read the
[uninstall Docker Engine](#uninstall-docker-engine) section.

## Installation methods

You can install Docker Engine in different ways, depending on your needs:

- Docker Engine comes bundled with
  [Docker Desktop for Linux](../../desktop/setup/install/linux/index.md). This is
  the easiest and quickest way to get started.

- Set up and install Docker Engine from
  [Docker's `apt` repository](#install-using-the-repository).

- [Install it manually](#install-from-a-package) and manage upgrades manually.

- Use a [convenience script](#install-using-the-convenience-script). Only
  recommended for testing and development environments.

{{% include "engine-license.md" %}}

### Install using the `apt` repository {#install-using-the-repository}

Before you install Docker Engine for the first time on a new host machine, you
need to set up the Docker `apt` repository. Afterward, you can install and update
Docker from the repository.

1. Set up Docker's `apt` repository.

   ```bash
   # Add Docker's official GPG key:
   sudo apt update
   sudo apt install ca-certificates curl
   sudo install -m 0755 -d /etc/apt/keyrings
   sudo curl -fsSL {{% param "download-url-base" %}}/gpg -o /etc/apt/keyrings/docker.asc
   sudo chmod a+r /etc/apt/keyrings/docker.asc

   # Add the repository to Apt sources:
   sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
   Types: deb
   URIs: {{% param "download-url-base" %}}
   Suites: $(. /etc/os-release && echo "$VERSION_CODENAME")
   Components: stable
   Architectures: $(dpkg --print-architecture)
   Signed-By: /etc/apt/keyrings/docker.asc
   EOF

   sudo apt update
   ```

   > [!NOTE]
   >
   > If you use Debian testing or a derivative distribution such as Kali Linux,
   > you may need to substitute the part of this command that's expected to
   > print the version codename:
   >
   > ```console
   > $(. /etc/os-release && echo "$VERSION_CODENAME")
   > ```
   >
   > Replace this part with the codename of the corresponding Debian release,
   > such as `trixie`.

2. Install the Docker packages.

   {{< tabs >}}
   {{< tab name="Latest" >}}

   To install the latest version, run:

   ```console
   $ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   {{< /tab >}}
   {{< tab name="Specific version" >}}

   To install a specific version of Docker Engine, start by listing the
   available versions in the repository:

   ```console
   $ apt list --all-versions docker-ce

   docker-ce/bookworm 5:{{% param "docker_ce_version" %}}-1~debian.12~bookworm <arch>
   docker-ce/bookworm 5:{{% param "docker_ce_version_prev" %}}-1~debian.12~bookworm <arch>
   ...
   ```

   Select the desired version and install:

   ```console
   $ VERSION_STRING=5:{{% param "docker_ce_version" %}}-1~debian.12~bookworm
   $ sudo apt install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   {{< /tab >}}
   {{< /tabs >}}

    > [!NOTE]
    >
    > After installation, verify that Docker is running:
    >
    > ```console
    > $ sudo systemctl status docker
    > ```
    >
    > If Docker is not running, start it manually:
    >
    > ```console
    > $ sudo systemctl start docker
    > ```

3. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, follow step 2 of the
[installation instructions](#install-using-the-repository),
choosing the new version you want to install.

### Install from a package

If you can't use Docker's `apt` repository to install Docker Engine, you can
download the `deb` file for your release and install it manually. You need to
download a new file each time you want to upgrade Docker Engine.

<!-- markdownlint-disable-next-line -->
1. Go to [`{{% param "download-url-base" %}}/dists/`]({{% param "download-url-base" %}}/dists/).

2. Select your Debian version in the list.

3. Go to `pool/stable/` and select the applicable architecture (`amd64`,
   `armhf`, `arm64`, or `s390x`).

4. Download the following `deb` files for the Docker Engine, CLI, containerd,
   and Docker Compose packages:

   - `containerd.io_<version>_<arch>.deb`
   - `docker-ce_<version>_<arch>.deb`
   - `docker-ce-cli_<version>_<arch>.deb`
   - `docker-buildx-plugin_<version>_<arch>.deb`
   - `docker-compose-plugin_<version>_<arch>.deb`

5. Install the `.deb` packages. Update the paths in the following example to
   where you downloaded the Docker packages.

   ```console
   $ sudo dpkg -i ./containerd.io_<version>_<arch>.deb \
     ./docker-ce_<version>_<arch>.deb \
     ./docker-ce-cli_<version>_<arch>.deb \
     ./docker-buildx-plugin_<version>_<arch>.deb \
     ./docker-compose-plugin_<version>_<arch>.deb
   ```

    > [!NOTE]
    >
    > After installation, verify that Docker is running:
    >
    > ```console
    > $ sudo systemctl status docker
    > ```
    >
    > If Docker is not running, start it manually:
    >
    > ```console
    > $ sudo systemctl start docker
    > ```

6. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, download the newer package files and repeat the
[installation procedure](#install-from-a-package), pointing to the new files.

{{% include "install-script.md" %}}

## Uninstall Docker Engine

1. Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

   ```console
   $ sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
   ```

2. Images, containers, volumes, or custom configuration files on your host
   aren't automatically removed. To delete all images, containers, and volumes:

   ```console
   $ sudo rm -rf /var/lib/docker
   $ sudo rm -rf /var/lib/containerd
   ```

3. Remove source list and keyrings

   ```console
   $ sudo rm /etc/apt/sources.list.d/docker.sources
   $ sudo rm /etc/apt/keyrings/docker.asc
   ```

You have to delete any edited configuration files manually.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# Install Docker Engine on Fedora

*Sección: Engine*

To get started with Docker Engine on Fedora, make sure you
[meet the prerequisites](#prerequisites), and then follow the
[installation steps](#installation-methods).

## Prerequisites

### OS requirements

To install Docker Engine, you need a maintained version of one of the following
Fedora versions:

- Fedora 44
- Fedora 43

### Uninstall old versions

Before you can install Docker Engine, you need to uninstall any conflicting packages.

Your Linux distribution may provide unofficial Docker packages, which may conflict
with the official packages provided by Docker. You must uninstall these packages
before you install the official version of Docker Engine.

```console
$ sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine
```

`dnf` might report that you have none of these packages installed.

Images, containers, volumes, and networks stored in `/var/lib/docker/` aren't
automatically removed when you uninstall Docker.

## Installation methods

You can install Docker Engine in different ways, depending on your needs:

- You can
  [set up Docker's repositories](#install-using-the-repository) and install
  from them, for ease of installation and upgrade tasks. This is the
  recommended approach.

- You can download the RPM package,
  [install it manually](#install-from-a-package), and manage
  upgrades completely manually. This is useful in situations such as installing
  Docker on air-gapped systems with no access to the internet.

- In testing and development environments, you can use automated
  [convenience scripts](#install-using-the-convenience-script) to install Docker.

{{% include "engine-license.md" %}}

### Install using the rpm repository {#install-using-the-repository}

Before you install Docker Engine for the first time on a new host machine, you
need to set up the Docker repository. Afterward, you can install and update
Docker from the repository.

#### Set up the repository

```console
$ sudo dnf config-manager addrepo --from-repofile {{% param "download-url-base" %}}/docker-ce.repo
```

#### Install Docker Engine

1. Install the Docker packages.

   {{< tabs >}}
   {{< tab name="Latest" >}}

   To install the latest version, run:

   ```console
   $ sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   If prompted to accept the GPG key, verify that the fingerprint matches
   `060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35`, and if so, accept it.

   This command installs Docker, but it doesn't start Docker. It also creates a
   `docker` group, however, it doesn't add any users to the group by default.

   {{< /tab >}}
   {{< tab name="Specific version" >}}

   To install a specific version, start by listing the available versions in
   the repository:

   ```console
   $ dnf list docker-ce --showduplicates | sort -r

   docker-ce.x86_64    3:{{% param "docker_ce_version" %}}-1.fc41    docker-ce-stable
   docker-ce.x86_64    3:{{% param "docker_ce_version_prev" %}}-1.fc41    docker-ce-stable
   <...>
   ```

   The list returned depends on which repositories are enabled, and is specific
   to your version of Fedora (indicated by the `.fc40` suffix in this example).

   Install a specific version by its fully qualified package name, which is
   the package name (`docker-ce`) plus the version string (2nd column),
   separated by a hyphen (`-`). For example, `docker-ce-3:{{% param "docker_ce_version" %}}-1.fc41`.

   Replace `<VERSION_STRING>` with the desired version and then run the following
   command to install:

   ```console
   $ sudo dnf install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   This command installs Docker, but it doesn't start Docker. It also creates a
   `docker` group, however, it doesn't add any users to the group by default.

   {{< /tab >}}
   {{< /tabs >}}

2. Start Docker Engine.

   ```console
   $ sudo systemctl enable --now docker
   ```

   This configures the Docker systemd service to start automatically when you
   boot your system. If you don't want Docker to start automatically, use `sudo
   systemctl start docker` instead.

   > [!NOTE]
   >
   > If the Docker service fails to start and `journalctl -u docker`
   > shows `failed to find iptables`, point the `iptables` command to
   > `iptables-nft` using `alternatives` and restart the service:
   >
   > ```console
   > $ sudo alternatives --set iptables /usr/bin/iptables-nft
   > $ sudo systemctl restart docker
   > ```

3. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, follow the [installation instructions](#install-using-the-repository),
choosing the new version you want to install.

### Install from a package

If you can't use Docker's `rpm` repository to install Docker Engine, you can
download the `.rpm` file for your release and install it manually. You need to
download a new file each time you want to upgrade Docker Engine.

<!-- markdownlint-disable-next-line -->
1. Go to [{{% param "download-url-base" %}}/]({{% param "download-url-base" %}}/)
   and choose your version of Fedora. Then browse to `x86_64/stable/Packages/`
   and download the `.rpm` file for the Docker version you want to install.

2. Install Docker Engine, changing the following path to the path where you downloaded
   the Docker package.

   ```console
   $ sudo dnf install /path/to/package.rpm
   ```

   Docker is installed but not started. The `docker` group is created, but no
   users are added to the group.

3. Start Docker Engine.

   ```console
   $ sudo systemctl enable --now docker
   ```

   This configures the Docker systemd service to start automatically when you
   boot your system. If you don't want Docker to start automatically, use `sudo
   systemctl start docker` instead.

   > [!NOTE]
   >
   > If the Docker service fails to start and `journalctl -u docker`
   > shows `failed to find iptables`, point the `iptables` command to
   > `iptables-nft` using `alternatives` and restart the service:
   >
   > ```console
   > $ sudo alternatives --set iptables /usr/bin/iptables-nft
   > $ sudo systemctl restart docker
   > ```

4. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, download the newer package files and repeat the
[installation procedure](#install-from-a-package), using `dnf upgrade`
instead of `dnf install`, and point to the new files.

{{% include "install-script.md" %}}

## Uninstall Docker Engine

1. Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

   ```console
   $ sudo dnf remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
   ```

2. Images, containers, volumes, or custom configuration files on your host
   aren't automatically removed. To delete all images, containers, and volumes:

   ```console
   $ sudo rm -rf /var/lib/docker
   $ sudo rm -rf /var/lib/containerd
   ```

You have to delete any edited configuration files manually.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# Linux post-installation steps for Docker Engine

*Sección: Engine*

These optional post-installation procedures describe how to configure your
Linux host machine to work better with Docker.

## Manage Docker as a non-root user

The Docker daemon binds to a Unix socket, not a TCP port. By default it's the
`root` user that owns the Unix socket, and other users can only access it using
`sudo`. The Docker daemon always runs as the `root` user.

When the Docker daemon starts, it creates a Unix socket accessible by members of the `docker` group.
On some Linux distributions, the system automatically creates this group when installing Docker Engine using a package manager.
In that case, you don't need to create the group manually.

There are two ways to run `docker` commands without `sudo` while the Docker daemon runs as `root`:

- [Add your user to the `docker` group](#add-your-user-to-the-docker-group) for access throughout your login session.
- [Access the `docker` group on demand](#access-the-docker-group-on-demand) by entering a password-protected, Docker-enabled shell.

<!-- prettier-ignore -->
> [!WARNING]
>
> The `docker` group grants root-level privileges to the user. For
> details on how this impacts security in your system, see
> [Docker Daemon Attack Surface](../security/index.md#docker-daemon-attack-surface).

> [!NOTE]
>
> To run Docker without root privileges, see
> [Run the Docker daemon as a non-root user (Rootless mode)](../security/rootless.md).

### Add your user to the `docker` group

To create the `docker` group and add your user:

1. Create the `docker` group.

   ```console
   $ sudo groupadd docker
   ```

2. Add your user to the `docker` group.

   ```console
   $ sudo usermod -aG docker $USER
   ```

3. Log out and log back in so that your group membership is re-evaluated.

   > If you're running Linux in a virtual machine, it may be necessary to
   > restart the virtual machine for changes to take effect.

   You can also run the following command to activate the changes to groups:

   ```console
   $ newgrp docker
   ```

4. Verify that you can run `docker` commands without `sudo`.

   ```console
   $ docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a message and exits.

   If you initially ran Docker CLI commands using `sudo` before adding your user
   to the `docker` group, you may see the following error:

   ```text
   WARNING: Error loading config file: /home/user/.docker/config.json -
   stat /home/user/.docker/config.json: permission denied
   ```

   This error indicates that the permission settings for the `~/.docker/`
   directory are incorrect, due to having used the `sudo` command earlier.

   To fix this problem, either remove the `~/.docker/` directory (it's recreated
   automatically, but any custom settings are lost), or change its ownership and
   permissions using the following commands:

   ```console
   $ sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
   $ sudo chmod g+rwx "$HOME/.docker" -R
   ```

### Access the `docker` group on demand

Group passwords are a legacy Unix access-control mechanism, but they can be useful for gating Docker access on a single-user workstation.
Like `sudo`, this method adds an explicit password step before privileged access.
Unlike running `sudo docker`, `newgrp` keeps the Docker CLI running under your user ID and grants access through the shell's primary group, so the CLI doesn't access its configuration as `root`.

Permanent membership in the `docker` group gives every process in your login session access to the Docker socket.
The Docker-enabled shell and its descendants inherit access to the Docker socket.
This reduces ambient access from applications running elsewhere in your login session.
To configure this access, keep your user out of the group, set a group password, and use `newgrp` to start a Docker-enabled shell.

> [!WARNING]
>
> A group password reduces ambient access to the Docker socket, but it doesn't reduce the root-level privileges granted after access is authorized.
> Group passwords are also shared secrets and don't provide per-user accountability.
> This method isn't a security boundary against malicious code running as your user.
> Such code can modify user-writable shell configuration, commands, or scripts that you later use from the Docker-enabled shell and gain Docker access after you authenticate.
> Don't rely on a group password to contain untrusted code or protect a compromised login session.
> This configuration is most suitable for a single-user workstation.
> For stronger isolation, use [Rootless mode](../security/rootless.md) or run Docker in a virtual machine.

This procedure requires `gpasswd` and `newgrp`.
The package names for these commands vary by Linux distribution.
Verify that both commands are available:

```console
$ command -v gpasswd newgrp
/usr/bin/gpasswd
/usr/bin/newgrp
```

To require a password for Docker access:

1. Create the `docker` group if it doesn't exist:

   ```console
   $ sudo groupadd --force docker
   ```

   The `--force` option makes the command succeed when the group already exists.

2. If your user is a member of the `docker` group, remove the membership:

   ```console
   $ sudo gpasswd --delete "$USER" docker
   ```

   Sign out of the desktop or SSH session completely, then sign back in.
   Group membership remains in the credentials of existing processes, so opening a new terminal isn't sufficient.

   Verify that `docker` is absent from the group list before continuing:

   ```console
   $ id -nG
   user wheel
   ```

   Your group list varies by system, but it must not include `docker`.

3. Set a dedicated password for the `docker` group:

   ```console
   $ sudo gpasswd docker
   Changing the password for group docker
   New Password:
   Re-enter new password:
   ```

   Don't add your user back to the group.
   Users configured as group members can use `newgrp` without entering the group password.

4. Start a child shell with `docker` as its primary group:

   ```console
   $ newgrp docker
   Password:
   ```

   Verify that the shell still uses your user ID and has `docker` as its primary group, then test Docker access:

   ```console
   $ id -un
   user
   $ id -gn
   docker
   $ docker run --rm hello-world
   ```

   Commands and applications started from this shell inherit access to the Docker socket.
   Applications that were already running outside the shell don't gain access.

   > [!CAUTION]
   >
   > Files and directories created from this shell normally have `docker` as their group owner.
   > Use this shell only for Docker-related commands, or verify the group ownership of files you create.

5. Exit the Docker-enabled shell when you finish:

   ```console
   $ exit
   ```

   Verify that `docker` is no longer in the original shell's group list:

   ```console
   $ id -nG
   user wheel
   ```

> [!CAUTION]
>
> Exiting the shell doesn't revoke access from background, detached, or daemonized processes started inside it.
> Those processes retain the `docker` group until they exit.

To change the group password, run `sudo gpasswd docker` again.

#### Disable password-based entry

To stop using the shared password and require configured group membership, run:

```console
$ sudo gpasswd --restrict docker
```

This reverses the password-gated setup.
Afterward, only users configured as members of the `docker` group can enter it.
The change affects new authorization attempts; it doesn't terminate existing Docker-enabled shells or their descendant processes.

`gpasswd` manages local `/etc/group` and `/etc/gshadow` files.
Systems using LDAP, NIS, or another identity service require that service's group-management mechanism.

## Configure Docker to start on boot with systemd

Many modern Linux distributions use [systemd](https://systemd.io/) to
manage which services start when the system boots. On Debian and Ubuntu, the
Docker service starts on boot by default. To automatically start Docker and
containerd on boot for other Linux distributions using systemd, run the
following commands:

```console
$ sudo systemctl enable docker.service
$ sudo systemctl enable containerd.service
```

To stop this behavior, use `disable` instead.

```console
$ sudo systemctl disable docker.service
$ sudo systemctl disable containerd.service
```

You can use systemd unit files to configure the Docker service on startup,
for example to add an HTTP proxy, set a different directory or partition for the
Docker runtime files, or other customizations. For an example, see
[Configure the daemon to use a proxy](../daemon/proxy.md#systemd-unit-file).

## Configure default logging driver

Docker provides [logging drivers](../logging/index.md) for
collecting and viewing log data from all containers running on a host. The
default logging driver, `json-file`, writes log data to JSON-formatted files on
the host filesystem. Over time, these log files expand in size, leading to
potential exhaustion of disk resources.

To avoid issues with overusing disk for log data, consider one of the following
options:

- Configure the `json-file` logging driver to turn on
  [log rotation](../logging/drivers/json-file.md).
- Use an
  [alternative logging driver](../logging/configure.md#configure-the-default-logging-driver)
  such as the ["local" logging driver](../logging/drivers/local.md)
  that performs log rotation by default.
- Use a logging driver that sends logs to a remote logging aggregator.

## Next steps

- Take a look at [Get started with Docker](/get-started/tutorials/run-an-app.md) to learn how to build an image and run it as a containerized application.


---

# Install Docker Engine on Raspberry Pi OS (32-bit / armhf)

*Sección: Engine*

> [!WARNING]
>
> **Raspberry Pi OS 32-bit (armhf) Deprecation**
>
> Docker Engine v28 will be the last major version to support Raspberry Pi OS 32-bit (armhf).
> Starting with Docker Engine v29, new major versions will no longer provide packages for Raspberry Pi OS 32-bit (armhf).
>
> **Migration options**
> - **64-bit ARM:** Install the Debian `arm64` packages (fully supported). See the
>   [Debian installation instructions](debian.md).
> - **32-bit ARM (v7):** Install the Debian `armhf` packages (targets ARMv7 CPUs).
>
> **Note:** Older devices based on the ARMv6 architecture are no longer supported by official packages, including:
> - Raspberry Pi 1 (Model A/B/A+/B+)
> - Raspberry Pi Zero and Zero W

To get started with Docker Engine on Raspberry Pi OS, make sure you
[meet the prerequisites](#prerequisites), and then follow the
[installation steps](#installation-methods).

> [!IMPORTANT]
>
> This installation instruction refers to the 32-bit (armhf) version of
> Raspberry Pi OS. If you're using the 64-bit (arm64) version, follow the
> instructions for [Debian](debian.md).

## Prerequisites

### Firewall limitations

> [!WARNING]
>
> Before you install Docker, make sure you consider the following
> security implications and firewall incompatibilities.

- If you use ufw or firewalld to manage firewall settings, be aware that
  when you expose container ports using Docker, these ports bypass your
  firewall rules. For more information, refer to
  [Docker and ufw](../network/packet-filtering-firewalls.md#docker-and-ufw).
- Docker is only compatible with `iptables-nft` and `iptables-legacy`.
  Firewall rules created with `nft` are not supported on a system with Docker installed.
  Make sure that any firewall rulesets you use are created with `iptables` or `ip6tables`,
  and that you add them to the `DOCKER-USER` chain,
  see [Packet filtering and firewalls](../network/packet-filtering-firewalls.md).

### OS requirements

To install Docker Engine, you need one of the following OS versions:

- 32-bit Raspberry Pi OS Bookworm 12 (stable)
- 32-bit Raspberry Pi OS Bullseye 11 (oldstable)

> [!WARNING]
>
> Docker Engine v28 is the last major version to support Raspberry Pi OS 32-bit (armhf). Starting with v29,
> no new packages will be provided for 32-bit Raspberry Pi OS.
>
> Migration options:
> - 64-bit ARM: use Debian `arm64` packages; see the [Debian installation instructions](debian.md).
> - 32-bit ARM (v7): use Debian `armhf` packages (targets ARMv7 CPUs).
>
> Note: ARMv6-based devices (Raspberry Pi 1 models and Raspberry Pi Zero/Zero W) are not supported by
> official packages.

### Uninstall old versions

Before you can install Docker Engine, you need to uninstall any conflicting packages.

Your Linux distribution may provide unofficial Docker packages, which may conflict
with the official packages provided by Docker. You must uninstall these packages
before you install the official version of Docker Engine.

The unofficial packages to uninstall are:

- `docker.io`
- `docker-compose`
- `docker-doc`
- `podman-docker`

Moreover, Docker Engine depends on `containerd` and `runc`. Docker Engine
bundles these dependencies as one bundle: `containerd.io`. If you have
installed the `containerd` or `runc` previously, uninstall them to avoid
conflicts with the versions bundled with Docker Engine.

Run the following command to uninstall all conflicting packages:

```console
$ for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done
```

`apt-get` might report that you have none of these packages installed.

Images, containers, volumes, and networks stored in `/var/lib/docker/` aren't
automatically removed when you uninstall Docker. If you want to start with a
clean installation, and prefer to clean up any existing data, read the
[uninstall Docker Engine](#uninstall-docker-engine) section.

## Installation methods

You can install Docker Engine in different ways, depending on your needs:

- Docker Engine comes bundled with
  [Docker Desktop for Linux](../../desktop/setup/install/linux/index.md). This is
  the easiest and quickest way to get started.

- Set up and install Docker Engine from
  [Docker's `apt` repository](#install-using-the-repository).

- [Install it manually](#install-from-a-package) and manage upgrades manually.

- Use a [convenience script](#install-using-the-convenience-script). Only
  recommended for testing and development environments.

{{% include "engine-license.md" %}}

### Install using the `apt` repository {#install-using-the-repository}

Before you install Docker Engine for the first time on a new host machine, you
need to set up the Docker `apt` repository. Afterward, you can install and update
Docker from the repository.

1. Set up Docker's `apt` repository.

   ```bash
   # Add Docker's official GPG key:
   sudo apt-get update
   sudo apt-get install ca-certificates curl
   sudo install -m 0755 -d /etc/apt/keyrings
   sudo curl -fsSL {{% param "download-url-base" %}}/gpg -o /etc/apt/keyrings/docker.asc
   sudo chmod a+r /etc/apt/keyrings/docker.asc

   # Add the repository to Apt sources:
   echo \
     "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] {{% param "download-url-base" %}} \
     $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
     sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
   sudo apt-get update
   ```

2. Install the Docker packages.

   {{< tabs >}}
   {{< tab name="Latest" >}}

   To install the latest version, run:

   ```console
   $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   {{< /tab >}}
   {{< tab name="Specific version" >}}

   To install a specific version of Docker Engine, start by listing the
   available versions in the repository:

   ```console
   # List the available versions:
   $ apt-cache madison docker-ce | awk '{ print $3 }'

   5:{{% param "docker_ce_version" %}}-1~raspbian.12~bookworm
   5:{{% param "docker_ce_version_prev" %}}-1~raspbian.12~bookworm
   ...
   ```

   Select the desired version and install:

   ```console
   $ VERSION_STRING=5:{{% param "docker_ce_version" %}}-1~raspbian.12~bookworm
   $ sudo apt-get install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   {{< /tab >}}
   {{< /tabs >}}

    > [!NOTE]
    >
    > After installation, verify that Docker is running:
    >
    > ```console
    > $ sudo systemctl status docker
    > ```
    >
    > If Docker is not running, start it manually:
    >
    > ```console
    > $ sudo systemctl start docker
    > ```

3. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, follow step 2 of the
[installation instructions](#install-using-the-repository),
choosing the new version you want to install.

### Install from a package

If you can't use Docker's `apt` repository to install Docker Engine, you can
download the `deb` file for your release and install it manually. You need to
download a new file each time you want to upgrade Docker Engine.

<!-- markdownlint-disable-next-line -->
1. Go to [`{{% param "download-url-base" %}}/dists/`]({{% param "download-url-base" %}}/dists/).

2. Select your Raspberry Pi OS version in the list.

3. Go to `pool/stable/` and select the applicable architecture (`amd64`,
   `armhf`, `arm64`, or `s390x`).

4. Download the following `deb` files for the Docker Engine, CLI, containerd,
   and Docker Compose packages:

   - `containerd.io_<version>_<arch>.deb`
   - `docker-ce_<version>_<arch>.deb`
   - `docker-ce-cli_<version>_<arch>.deb`
   - `docker-buildx-plugin_<version>_<arch>.deb`
   - `docker-compose-plugin_<version>_<arch>.deb`

5. Install the `.deb` packages. Update the paths in the following example to
   where you downloaded the Docker packages.

   ```console
   $ sudo dpkg -i ./containerd.io_<version>_<arch>.deb \
     ./docker-ce_<version>_<arch>.deb \
     ./docker-ce-cli_<version>_<arch>.deb \
     ./docker-buildx-plugin_<version>_<arch>.deb \
     ./docker-compose-plugin_<version>_<arch>.deb
   ```

    > [!NOTE]
    >
    > After installation, verify that Docker is running:
    >
    > ```console
    > $ sudo systemctl status docker
    > ```
    >
    > If Docker is not running, start it manually:
    >
    > ```console
    > $ sudo systemctl start docker
    > ```

6. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, download the newer package files and repeat the
[installation procedure](#install-from-a-package), pointing to the new files.

{{% include "install-script.md" %}}

## Uninstall Docker Engine

1. Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

   ```console
   $ sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
   ```

2. Images, containers, volumes, or custom configuration files on your host
   aren't automatically removed. To delete all images, containers, and volumes:

   ```console
   $ sudo rm -rf /var/lib/docker
   $ sudo rm -rf /var/lib/containerd
   ```

3. Remove source list and keyrings

   ```console
   $ sudo rm /etc/apt/sources.list.d/docker.list
   $ sudo rm /etc/apt/keyrings/docker.asc
   ```

You have to delete any edited configuration files manually.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# Install Docker Engine on RHEL

*Sección: Engine*

To get started with Docker Engine on RHEL, make sure you
[meet the prerequisites](#prerequisites), and then follow the
[installation steps](#installation-methods).

## Prerequisites

### OS requirements

To install Docker Engine, you need a maintained version of one of the following
RHEL versions:

- RHEL 8
- RHEL 9
- RHEL 10

### Uninstall old versions

Before you can install Docker Engine, you need to uninstall any conflicting packages.

Your Linux distribution may provide unofficial Docker packages, which may conflict
with the official packages provided by Docker. You must uninstall these packages
before you install the official version of Docker Engine.

```console
$ sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine \
                  podman \
                  runc
```

`dnf` might report that you have none of these packages installed.

Images, containers, volumes, and networks stored in `/var/lib/docker/` aren't
automatically removed when you uninstall Docker.

## Installation methods

You can install Docker Engine in different ways, depending on your needs:

- You can
  [set up Docker's repositories](#install-using-the-repository) and install
  from them, for ease of installation and upgrade tasks. This is the
  recommended approach.

- You can download the RPM package,
  [install it manually](#install-from-a-package), and manage
  upgrades completely manually. This is useful in situations such as installing
  Docker on air-gapped systems with no access to the internet.

- In testing and development environments, you can use automated
  [convenience scripts](#install-using-the-convenience-script) to install Docker.

{{% include "engine-license.md" %}}

### Install using the rpm repository {#install-using-the-repository}

Before you install Docker Engine for the first time on a new host machine, you
need to set up the Docker repository. Afterward, you can install and update
Docker from the repository.

#### Set up the repository

Install the `dnf-plugins-core` package (which provides the commands to manage
your DNF repositories) and set up the repository.

```console
$ sudo dnf -y install dnf-plugins-core
$ sudo dnf config-manager --add-repo {{% param "download-url-base" %}}/docker-ce.repo
```

#### Install Docker Engine

1. Install the Docker packages.

   {{< tabs >}}
   {{< tab name="Latest" >}}

   To install the latest version, run:

   ```console
   $ sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   If prompted to accept the GPG key, verify that the fingerprint matches
   `060A 61C5 1B55 8A7F 742B 77AA C52F EB6B 621E 9F35`, and if so, accept it.

   This command installs Docker, but it doesn't start Docker. It also creates a
   `docker` group, however, it doesn't add any users to the group by default.

   {{< /tab >}}
   {{< tab name="Specific version" >}}

   To install a specific version, start by listing the available versions in
   the repository:

   ```console
   $ dnf list docker-ce --showduplicates | sort -r

   docker-ce.x86_64    3:{{% param "docker_ce_version" %}}-1.el9    docker-ce-stable
   docker-ce.x86_64    3:{{% param "docker_ce_version_prev" %}}-1.el9    docker-ce-stable
   <...>
   ```

   The list returned depends on which repositories are enabled, and is specific
   to your version of RHEL (indicated by the `.el9` suffix in this example).

   Install a specific version by its fully qualified package name, which is
   the package name (`docker-ce`) plus the version string (2nd column),
   separated by a hyphen (`-`). For example, `docker-ce-3:{{% param "docker_ce_version" %}}-1.el9`.

   Replace `<VERSION_STRING>` with the desired version and then run the following
   command to install:

   ```console
   $ sudo dnf install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   This command installs Docker, but it doesn't start Docker. It also creates a
   `docker` group, however, it doesn't add any users to the group by default.

   {{< /tab >}}
   {{< /tabs >}}

2. Start Docker Engine.

   ```console
   $ sudo systemctl enable --now docker
   ```

   This configures the Docker systemd service to start automatically when you
   boot your system. If you don't want Docker to start automatically, use `sudo
   systemctl start docker` instead.

3. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, follow the [installation instructions](#install-using-the-repository),
choosing the new version you want to install.

### Install from a package

If you can't use Docker's `rpm` repository to install Docker Engine, you can
download the `.rpm` file for your release and install it manually. You need to
download a new file each time you want to upgrade Docker Engine.

<!-- markdownlint-disable-next-line -->
1. Go to [{{% param "download-url-base" %}}/]({{% param "download-url-base" %}}/).

2. Select your RHEL version in the list.

3. Select the applicable architecture (`x86_64`, `aarch64`, or `s390x`), and
   then go to `stable/Packages/`.

4. Download the following `rpm` files for the Docker Engine, CLI, containerd,
   and Docker Compose packages:

   - `containerd.io-<version>.<arch>.rpm`
   - `docker-ce-<version>.<arch>.rpm`
   - `docker-ce-cli-<version>.<arch>.rpm`
   - `docker-buildx-plugin-<version>.<arch>.rpm`
   - `docker-compose-plugin-<version>.<arch>.rpm`

5. Install Docker Engine, changing the following path to the path where you downloaded
   the packages.

   ```console
   $ sudo dnf install ./containerd.io-<version>.<arch>.rpm \
     ./docker-ce-<version>.<arch>.rpm \
     ./docker-ce-cli-<version>.<arch>.rpm \
     ./docker-buildx-plugin-<version>.<arch>.rpm \
     ./docker-compose-plugin-<version>.<arch>.rpm
   ```

   Docker is installed but not started. The `docker` group is created, but no
   users are added to the group.

6. Start Docker Engine.

   ```console
   $ sudo systemctl enable --now docker
   ```

   This configures the Docker systemd service to start automatically when you
   boot your system. If you don't want Docker to start automatically, use `sudo
   systemctl start docker` instead.

7. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, download the newer package files and repeat the
[installation procedure](#install-from-a-package), using `dnf upgrade`
instead of `dnf install`, and point to the new files.

{{% include "install-script.md" %}}

## Uninstall Docker Engine

1. Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

   ```console
   $ sudo dnf remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
   ```

2. Images, containers, volumes, or custom configuration files on your host
   aren't automatically removed. To delete all images, containers, and volumes:

   ```console
   $ sudo rm -rf /var/lib/docker
   $ sudo rm -rf /var/lib/containerd
   ```

You have to delete any edited configuration files manually.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# Install Docker Engine on Ubuntu

*Sección: Engine*

To get started with Docker Engine on Ubuntu, make sure you
[meet the prerequisites](#prerequisites), and then follow the
[installation steps](#installation-methods).

## Prerequisites

### Firewall limitations

> [!WARNING]
>
> Before you install Docker, make sure you consider the following
> security implications and firewall incompatibilities.

- If you use ufw or firewalld to manage firewall settings, be aware that
  when you expose container ports using Docker, these ports bypass your
  firewall rules. For more information, refer to
  [Docker and ufw](../network/packet-filtering-firewalls.md#docker-and-ufw).
- Docker is only compatible with `iptables-nft` and `iptables-legacy`.
  Firewall rules created with `nft` are not supported on a system with Docker installed.
  Make sure that any firewall rulesets you use are created with `iptables` or `ip6tables`,
  and that you add them to the `DOCKER-USER` chain,
  see [Packet filtering and firewalls](../network/packet-filtering-firewalls.md).

### OS requirements

To install Docker Engine, you need the 64-bit version of one of these Ubuntu
versions:

- Ubuntu Resolute 26.04 (LTS)
- Ubuntu Noble 24.04 (LTS)
- Ubuntu Jammy 22.04 (LTS)

Docker Engine for Ubuntu is compatible with x86_64 (or amd64), armhf, arm64,
s390x, and ppc64le (ppc64el) architectures.

> [!NOTE]
>
> Installation on Ubuntu derivative distributions, such as Linux Mint, is not officially
> supported (though it may work).

### Uninstall old versions

Before you can install Docker Engine, you need to uninstall any conflicting packages.

Your Linux distribution may provide unofficial Docker packages, which may conflict
with the official packages provided by Docker. You must uninstall these packages
before you install the official version of Docker Engine.

The unofficial packages to uninstall are:

- `docker.io`
- `docker-compose`
- `docker-compose-v2`
- `docker-doc`
- `docker-buildx`
- `podman-docker`

Moreover, Docker Engine depends on `containerd` and `runc`. Docker Engine
bundles these dependencies as one bundle: `containerd.io`. If you have
installed the `containerd` or `runc` previously, uninstall them to avoid
conflicts with the versions bundled with Docker Engine.

Run the following command to uninstall all conflicting packages:

```console
$ sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc | cut -f1)
```

`apt` might report that you have none of these packages installed.

Images, containers, volumes, and networks stored in `/var/lib/docker/` aren't
automatically removed when you uninstall Docker. If you want to start with a
clean installation, and prefer to clean up any existing data, read the
[uninstall Docker Engine](#uninstall-docker-engine) section.

## Installation methods

You can install Docker Engine in different ways, depending on your needs:

- Docker Engine comes bundled with
  [Docker Desktop for Linux](../../desktop/setup/install/linux/index.md). This is
  the easiest and quickest way to get started.

- Set up and install Docker Engine from
  [Docker's `apt` repository](#install-using-the-repository).

- [Install it manually](#install-from-a-package) and manage upgrades manually.

- Use a [convenience script](#install-using-the-convenience-script). Only
  recommended for testing and development environments.

{{% include "engine-license.md" %}}

### Install using the `apt` repository {#install-using-the-repository}

Before you install Docker Engine for the first time on a new host machine, you
need to set up the Docker `apt` repository. Afterward, you can install and update
Docker from the repository.

1. Set up Docker's `apt` repository.

   ```bash
   # Add Docker's official GPG key:
   sudo apt update
   sudo apt install ca-certificates curl
   sudo install -m 0755 -d /etc/apt/keyrings
   sudo curl -fsSL {{% param "download-url-base" %}}/gpg -o /etc/apt/keyrings/docker.asc
   sudo chmod a+r /etc/apt/keyrings/docker.asc

   # Add the repository to Apt sources:
   sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
   Types: deb
   URIs: {{% param "download-url-base" %}}
   Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
   Components: stable
   Architectures: $(dpkg --print-architecture)
   Signed-By: /etc/apt/keyrings/docker.asc
   EOF

   sudo apt update
   ```

2. Install the Docker packages.

   {{< tabs >}}
   {{< tab name="Latest" >}}

   To install the latest version, run:

   ```console
   $ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   {{< /tab >}}
   {{< tab name="Specific version" >}}

   To install a specific version of Docker Engine, start by listing the
   available versions in the repository:

   ```console
   $ apt list --all-versions docker-ce

   docker-ce/noble 5:{{% param "docker_ce_version" %}}-1~ubuntu.24.04~noble <arch>
   docker-ce/noble 5:{{% param "docker_ce_version_prev" %}}-1~ubuntu.24.04~noble <arch>
   ...
   ```

   Select the desired version and install:

   ```console
   $ VERSION_STRING=5:{{% param "docker_ce_version" %}}-1~ubuntu.24.04~noble
   $ sudo apt install docker-ce=$VERSION_STRING docker-ce-cli=$VERSION_STRING containerd.io docker-buildx-plugin docker-compose-plugin
   ```

   {{< /tab >}}
   {{< /tabs >}}

    > [!NOTE]
    >
    > After installation, verify that Docker is running:
    >
    > ```console
    > $ sudo systemctl status docker
    > ```
    >
    > If Docker is not running, start it manually:
    >
    > ```console
    > $ sudo systemctl start docker
    > ```

3. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, follow step 2 of the
[installation instructions](#install-using-the-repository),
choosing the new version you want to install.

### Install from a package

If you can't use Docker's `apt` repository to install Docker Engine, you can
download the `deb` file for your release and install it manually. You need to
download a new file each time you want to upgrade Docker Engine.

<!-- markdownlint-disable-next-line -->
1. Go to [`{{% param "download-url-base" %}}/dists/`]({{% param "download-url-base" %}}/dists/).

2. Select your Ubuntu version in the list.

3. Go to `pool/stable/` and select the applicable architecture (`amd64`,
   `armhf`, `arm64`, or `s390x`).

4. Download the following `deb` files for the Docker Engine, CLI, containerd,
   and Docker Compose packages:

   - `containerd.io_<version>_<arch>.deb`
   - `docker-ce_<version>_<arch>.deb`
   - `docker-ce-cli_<version>_<arch>.deb`
   - `docker-buildx-plugin_<version>_<arch>.deb`
   - `docker-compose-plugin_<version>_<arch>.deb`

5. Install the `.deb` packages. Update the paths in the following example to
   where you downloaded the Docker packages.

   ```console
   $ sudo dpkg -i ./containerd.io_<version>_<arch>.deb \
     ./docker-ce_<version>_<arch>.deb \
     ./docker-ce-cli_<version>_<arch>.deb \
     ./docker-buildx-plugin_<version>_<arch>.deb \
     ./docker-compose-plugin_<version>_<arch>.deb
   ```

    > [!NOTE]
    >
    > After installation, verify that Docker is running:
    >
    > ```console
    > $ sudo systemctl status docker
    > ```
    >
    > If Docker is not running, start it manually:
    >
    > ```console
    > $ sudo systemctl start docker
    > ```

6. Verify that the installation is successful by running the `hello-world` image:

   ```console
   $ sudo docker run hello-world
   ```

   This command downloads a test image and runs it in a container. When the
   container runs, it prints a confirmation message and exits.

You have now successfully installed and started Docker Engine.

{{% include "root-errors.md" %}}

#### Upgrade Docker Engine

To upgrade Docker Engine, download the newer package files and repeat the
[installation procedure](#install-from-a-package), pointing to the new files.

{{% include "install-script.md" %}}

## Uninstall Docker Engine

1. Uninstall the Docker Engine, CLI, containerd, and Docker Compose packages:

   ```console
   $ sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
   ```

2. Images, containers, volumes, or custom configuration files on your host
   aren't automatically removed. To delete all images, containers, and volumes:

   ```console
   $ sudo rm -rf /var/lib/docker
   $ sudo rm -rf /var/lib/containerd
   ```

3. Remove source list and keyrings

   ```console
   $ sudo rm /etc/apt/sources.list.d/docker.sources
   $ sudo rm /etc/apt/keyrings/docker.asc
   ```

You have to delete any edited configuration files manually.

## Next steps

- Continue to [Post-installation steps for Linux](linux-postinstall.md).


---

# View container logs

*Sección: Engine*

The `docker logs` command shows information logged by a running container. The
`docker service logs` command shows information logged by all containers
participating in a service. The information that's logged and the format of the
log depends almost entirely on the container's endpoint command.

By default, `docker logs` or `docker service logs` shows the command's output
just as it would appear if you ran the command interactively in a terminal. Unix
and Linux commands typically open three I/O streams when they run, called
`STDIN`, `STDOUT`, and `STDERR`. `STDIN` is the command's input stream, which
may include input from the keyboard or input from another command. `STDOUT` is
usually a command's normal output, and `STDERR` is typically used to output
error messages. By default, `docker logs` shows the command's `STDOUT` and
`STDERR`. To read more about I/O and Linux, see the
[Linux Documentation Project article on I/O redirection](https://tldp.org/LDP/abs/html/io-redirection.html).

In some cases, `docker logs` may not show useful information unless you take
additional steps.

- If you use a [logging driver](configure.md) which sends logs to a file, an
  external host, a database, or another logging back-end, and have ["dual logging"](dual-logging.md)
  disabled, `docker logs` may not show useful information.
- If your image runs a non-interactive process such as a web server or a
  database, that application may send its output to log files instead of `STDOUT`
  and `STDERR`.

In the first case, your logs are processed in other ways and you may choose not
to use `docker logs`. In the second case, the official `nginx` image shows one
workaround, and the official Apache `httpd` image shows another.

The official `nginx` image creates a symbolic link from `/var/log/nginx/access.log`
to `/dev/stdout`, and creates another symbolic link
from `/var/log/nginx/error.log` to `/dev/stderr`, overwriting the log files and
causing logs to be sent to the relevant special device instead. See the
[Dockerfile](https://github.com/nginxinc/docker-nginx/blob/8921999083def7ba43a06fabd5f80e4406651353/mainline/jessie/Dockerfile#L21-L23).

The official `httpd` driver changes the `httpd` application's configuration to
write its normal output directly to `/proc/self/fd/1` (which is `STDOUT`) and
its errors to `/proc/self/fd/2` (which is `STDERR`). See the
[Dockerfile](https://github.com/docker-library/httpd/blob/b13054c7de5c74bbaa6d595dbe38969e6d4f860c/2.2/Dockerfile#L72-L75).

## Next steps

- Configure [logging drivers](configure.md).
- Write a [Dockerfile](../../build/concepts/dockerfile.md).


---

# Configure logging drivers

*Sección: Engine*

Docker includes multiple logging mechanisms to help you get information from
running containers and services. These mechanisms are called logging drivers.
Each Docker daemon has a default logging driver, which each container uses
unless you configure it to use a different logging driver, or log driver for
short.

As a default, Docker uses the [`json-file` logging driver](drivers/json-file.md), which
caches container logs as JSON internally. In addition to using the logging drivers
included with Docker, you can also implement and use [logging driver plugins](plugins.md).

> [!TIP]
>
> Use the `local` logging driver to prevent disk-exhaustion. By default, no log-rotation is performed. As a result, log-files stored by the
> default [`json-file` logging driver](drivers/json-file.md) can cause
> a significant amount of disk space to be used for containers that generate much
> output, which can lead to disk space exhaustion.
>
> Docker keeps the json-file logging driver (without log-rotation) as a default
> to remain backwards compatible with older versions of Docker, and for situations
> where Docker is used as runtime for Kubernetes.
>
> For other situations, the `local` logging driver is recommended as it performs
> log-rotation by default, and uses a more efficient file format. Refer to the
> [Configure the default logging driver](#configure-the-default-logging-driver)
> section below to learn how to configure the `local` logging driver as a default,
> and the [local file logging driver](drivers/local.md) page for more details about the
> `local` logging driver.

## Configure the default logging driver

To configure the Docker daemon to default to a specific logging driver, set the
value of `log-driver` to the name of the logging driver in the `daemon.json`
configuration file. Refer to the "daemon configuration file" section in the
[`dockerd` reference manual](/reference/cli/dockerd/#daemon-configuration-file)
for details.

The default logging driver is `json-file`. The following example sets the default
logging driver to the [`local` log driver](drivers/local.md):

```json
{
  "log-driver": "local"
}
```

If the logging driver has configurable options, you can set them in the
`daemon.json` file as a JSON object with the key `log-opts`. The following
example sets four configurable options on the `json-file` logging driver:

```json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3",
    "labels": "production_status",
    "env": "os,customer"
  }
}
```

Restart Docker for the changes to take effect for newly created containers.
Existing containers don't use the new logging configuration automatically.

> [!NOTE]
>
> `log-opts` configuration options in the `daemon.json` configuration file must
> be provided as strings. Boolean and numeric values (such as the value for
> `max-file` in the example above) must therefore be enclosed in quotes (`"`).

If you don't specify a logging driver, the default is `json-file`.
To find the current default logging driver for the Docker daemon, run
`docker info` and search for `Logging Driver`. You can use the following
command on Linux, macOS, or PowerShell on Windows:

```console
$ docker info --format '{{.LoggingDriver}}'

json-file
```

> [!NOTE]
>
> Changing the default logging driver or logging driver options in the daemon
> configuration only affects containers that are created after the configuration
> is changed. Existing containers retain the logging driver options that were
> used when they were created. To update the logging driver for a container, the
> container has to be re-created with the desired options.
> Refer to the [configure the logging driver for a container](#configure-the-logging-driver-for-a-container)
> section below to learn how to find the logging-driver configuration of a
> container.

## Configure the logging driver for a container

When you start a container, you can configure it to use a different logging
driver than the Docker daemon's default, using the `--log-driver` flag. If the
logging driver has configurable options, you can set them using one or more
instances of the `--log-opt <NAME>=<VALUE>` flag. Even if the container uses the
default logging driver, it can use different configurable options.

The following example starts an Alpine container with the `none` logging driver.

```console
$ docker run -it --log-driver none alpine ash
```

To find the current logging driver for a running container, if the daemon
is using the `json-file` logging driver, run the following `docker inspect`
command, substituting the container name or ID for `<CONTAINER>`:

```console
$ docker inspect -f '{{.HostConfig.LogConfig.Type}}' <CONTAINER>

json-file
```

## Configure the delivery mode of log messages from container to log driver

Docker provides two modes for delivering messages from the container to the log
driver:

- (default) direct, blocking delivery from container to driver
- non-blocking delivery that stores log messages in an intermediate per-container buffer for consumption by driver

The `non-blocking` message delivery mode prevents applications from blocking due
to logging back pressure. Applications are likely to fail in unexpected ways when
STDERR or STDOUT streams block.

> [!WARNING]
>
> When the buffer is full, new messages will not be enqueued. Dropping messages is often preferred to blocking the
> log-writing process of an application.

The `mode` log option controls whether to use the `blocking` (default) or
`non-blocking` message delivery.

The `max-buffer-size` controls the size of the buffer used for
intermediate message storage when `mode` is set to `non-blocking`.
The default is `1m` meaning 1 MB (1 million bytes).
See [function `FromHumanSize()` in the `go-units` package](https://pkg.go.dev/github.com/docker/go-units#FromHumanSize) for the allowed format strings,
some examples are `1KiB` for 1024 bytes, `2g` for 2 billion bytes.

The following example starts an Alpine container with log output in non-blocking
mode and a 4 megabyte buffer:

```console
$ docker run -it --log-opt mode=non-blocking --log-opt max-buffer-size=4m alpine ping 127.0.0.1
```

### Use environment variables or labels with logging drivers

Some logging drivers add the value of a container's `--env|-e` or `--label`
flags to the container's logs. This example starts a container using the Docker
daemon's default logging driver (in the following example, `json-file`) but
sets the environment variable `os=ubuntu`.

```console
$ docker run -dit --label production_status=testing -e os=ubuntu alpine sh
```

If the logging driver supports it, this adds additional fields to the logging
output. The following output is generated by the `json-file` logging driver:

```json
"attrs":{"production_status":"testing","os":"ubuntu"}
```

## Supported logging drivers

The following logging drivers are supported. See the link to each driver's
documentation for its configurable options, if applicable. If you are using
[logging driver plugins](plugins.md), you may
see more options.

| Driver                                | Description                                                                                                 |
| :------------------------------------ | :---------------------------------------------------------------------------------------------------------- |
| `none`                                | No logs are available for the container and `docker logs` does not return any output.                       |
| [`local`](drivers/local.md)           | Logs are stored in a custom format designed for minimal overhead.                                           |
| [`json-file`](drivers/json-file.md)   | The logs are formatted as JSON. The default logging driver for Docker.                                      |
| [`syslog`](drivers/syslog.md)         | Writes logging messages to the `syslog` facility. The `syslog` daemon must be running on the host machine.  |
| [`journald`](drivers/journald.md)     | Writes log messages to `journald`. The `journald` daemon must be running on the host machine.               |
| [`gelf`](drivers/gelf.md)             | Writes log messages to a Graylog Extended Log Format (GELF) endpoint such as Graylog or Logstash.           |
| [`fluentd`](drivers/fluentd.md)       | Writes log messages to `fluentd` (forward input). The `fluentd` daemon must be running on the host machine. |
| [`awslogs`](drivers/awslogs.md)       | Writes log messages to Amazon CloudWatch Logs.                                                              |
| [`splunk`](drivers/splunk.md)         | Writes log messages to `splunk` using the HTTP Event Collector.                                             |
| [`etwlogs`](drivers/etwlogs.md)       | Writes log messages as Event Tracing for Windows (ETW) events. Only available on Windows platforms.         |
| [`gcplogs`](drivers/gcplogs.md)       | Writes log messages to Google Cloud Platform (GCP) Logging.                                                 |

## Limitations of logging drivers

- Reading log information requires decompressing rotated log files, which causes
  a temporary increase in disk usage (until the log entries from the rotated
  files are read) and an increased CPU usage while decompressing.
- The capacity of the host storage where the Docker data directory resides
  determines the maximum size of the log file information.


---

# Logging drivers

*Sección: Engine*




---

# Amazon CloudWatch Logs logging driver

*Sección: Engine*

The `awslogs` logging driver sends container logs to
[Amazon CloudWatch Logs](https://aws.amazon.com/cloudwatch/details/#log-monitoring).
Log entries can be retrieved through the [AWS Management
Console](https://console.aws.amazon.com/cloudwatch/home#logs:) or the [AWS SDKs
and Command Line Tools](https://docs.aws.amazon.com/cli/latest/reference/logs/index.html).

## Usage

To use the `awslogs` driver as the default logging driver, set the `log-driver`
and `log-opt` keys to appropriate values in the `daemon.json` file. For more
about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `awslogs` and sets the
`awslogs-region` option.

```json
{
  "log-driver": "awslogs",
  "log-opts": {
    "awslogs-region": "us-east-1"
  }
}
```

Restart Docker for the changes to take effect.

You can set the logging driver for a specific container by using the
`--log-driver` option to `docker run`:

```console
$ docker run --log-driver=awslogs ...
```

If you are using Docker Compose, set `awslogs` using the following declaration example:

```yaml
myservice:
  logging:
    driver: awslogs
    options:
      awslogs-region: us-east-1
```

## Amazon CloudWatch Logs options

You can add logging options to the `daemon.json` to set Docker-wide defaults,
or use the `--log-opt NAME=VALUE` flag to specify Amazon CloudWatch Logs
logging driver options when starting a container.

### awslogs-region

The `awslogs` logging driver sends your Docker logs to a specific region. Use
the `awslogs-region` log option or the `AWS_REGION` environment variable to set
the region. By default, if your Docker daemon is running on an EC2 instance
and no region is set, the driver uses the instance's region.

```console
$ docker run --log-driver=awslogs --log-opt awslogs-region=us-east-1 ...
```

### awslogs-endpoint

By default, Docker uses either the `awslogs-region` log option or the
detected region to construct the remote CloudWatch Logs API endpoint.
Use the `awslogs-endpoint` log option to override the default endpoint
with the provided endpoint.

> [!NOTE]
>
> The `awslogs-region` log option or detected region controls the
> region used for signing. You may experience signature errors if the
> endpoint you've specified with `awslogs-endpoint` uses a different region.

### awslogs-group

You must specify a
[log group](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)
for the `awslogs` logging driver. You can specify the log group with the
`awslogs-group` log option:

```console
$ docker run --log-driver=awslogs --log-opt awslogs-region=us-east-1 --log-opt awslogs-group=myLogGroup ...
```

### awslogs-stream

To configure which
[log stream](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html)
should be used, you can specify the `awslogs-stream` log option. If not
specified, the container ID is used as the log stream.

> [!NOTE]
>
> Log streams within a given log group should only be used by one container
> at a time. Using the same log stream for multiple containers concurrently
> can cause reduced logging performance.

### awslogs-create-group

Log driver returns an error by default if the log group doesn't exist. However, you can set the
`awslogs-create-group` to `true` to automatically create the log group as needed.
The `awslogs-create-group` option defaults to `false`.

```console
$ docker run \
    --log-driver=awslogs \
    --log-opt awslogs-region=us-east-1 \
    --log-opt awslogs-group=myLogGroup \
    --log-opt awslogs-create-group=true \
    ...
```

> [!NOTE]
>
> Your AWS IAM policy must include the `logs:CreateLogGroup` permission before
> you attempt to use `awslogs-create-group`.

### awslogs-create-stream

By default, the log driver creates the AWS CloudWatch Logs stream used for container log persistence.

Set `awslogs-create-stream` to `false` to disable log stream creation. When disabled, the Docker daemon assumes
the log stream already exists. A use case where this is beneficial is when log stream creation is handled by 
another process avoiding redundant AWS CloudWatch Logs API calls.

If `awslogs-create-stream` is set to `false` and the log stream does not exist, log persistence to CloudWatch
fails during container runtime, resulting in `Failed to put log events` error messages in daemon logs.

```console
$ docker run \
    --log-driver=awslogs \
    --log-opt awslogs-region=us-east-1 \
    --log-opt awslogs-group=myLogGroup \
    --log-opt awslogs-stream=myLogStream \
    --log-opt awslogs-create-stream=false \
    ...
```

### awslogs-datetime-format

The `awslogs-datetime-format` option defines a multi-line start pattern in [Python
`strftime` format](https://strftime.org). A log message consists of a line that
matches the pattern and any following lines that don't match the pattern. Thus
the matched line is the delimiter between log messages.

One example of a use case for using
this format is for parsing output such as a stack dump, which might otherwise
be logged in multiple entries. The correct pattern allows it to be captured in a
single entry.

This option always takes precedence if both `awslogs-datetime-format` and
`awslogs-multiline-pattern` are configured.

> [!NOTE]
>
> Multi-line logging performs regular expression parsing and matching of all log
> messages, which may have a negative impact on logging performance.

Consider the following log stream, where new log messages start with a
timestamp:

```console
[May 01, 2017 19:00:01] A message was logged
[May 01, 2017 19:00:04] Another multi-line message was logged
Some random message
with some random words
[May 01, 2017 19:01:32] Another message was logged
```

The format can be expressed as a `strftime` expression of
`[%b %d, %Y %H:%M:%S]`, and the `awslogs-datetime-format` value can be set to
that expression:

```console
$ docker run \
    --log-driver=awslogs \
    --log-opt awslogs-region=us-east-1 \
    --log-opt awslogs-group=myLogGroup \
    --log-opt awslogs-datetime-format='\[%b %d, %Y %H:%M:%S\]' \
    ...
```

This parses the logs into the following CloudWatch log events:

```console
# First event
[May 01, 2017 19:00:01] A message was logged

# Second event
[May 01, 2017 19:00:04] Another multi-line message was logged
Some random message
with some random words

# Third event
[May 01, 2017 19:01:32] Another message was logged
```

The following `strftime` codes are supported:

| Code | Meaning                                                          | Example  |
| :--- | :--------------------------------------------------------------- | :------- |
| `%a` | Weekday abbreviated name.                                        | Mon      |
| `%A` | Weekday full name.                                               | Monday   |
| `%w` | Weekday as a decimal number where 0 is Sunday and 6 is Saturday. | 0        |
| `%d` | Day of the month as a zero-padded decimal number.                | 08       |
| `%b` | Month abbreviated name.                                          | Feb      |
| `%B` | Month full name.                                                 | February |
| `%m` | Month as a zero-padded decimal number.                           | 02       |
| `%Y` | Year with century as a decimal number.                           | 2008     |
| `%y` | Year without century as a zero-padded decimal number.            | 08       |
| `%H` | Hour (24-hour clock) as a zero-padded decimal number.            | 19       |
| `%I` | Hour (12-hour clock) as a zero-padded decimal number.            | 07       |
| `%p` | AM or PM.                                                        | AM       |
| `%M` | Minute as a zero-padded decimal number.                          | 57       |
| `%S` | Second as a zero-padded decimal number.                          | 04       |
| `%f` | Microseconds as a zero-padded decimal number.                    | 000345   |
| `%z` | UTC offset in the form +HHMM or -HHMM.                           | +1300    |
| `%Z` | Time zone name.                                                  | PST      |
| `%j` | Day of the year as a zero-padded decimal number.                 | 363      |

In addition, the following non-`strftime` codes are supported:

| Code | Meaning                                                              | Example  |
| :--- | :------------------------------------------------------------------- | :------- |
| `%L` | Milliseconds as a zero-padded decimal number preceded with a period. | .123     |

### awslogs-multiline-pattern

The `awslogs-multiline-pattern` option defines a multi-line start pattern using a
regular expression. A log message consists of a line that matches the pattern
and any following lines that don't match the pattern. Thus the matched line is
the delimiter between log messages.

This option is ignored if `awslogs-datetime-format` is also configured.

> [!NOTE]
>
> Multi-line logging performs regular expression parsing and matching of all log
> messages. This may have a negative impact on logging performance.

Consider the following log stream, where each log message should start with the
pattern `INFO`:

```console
INFO A message was logged
INFO Another multi-line message was logged
     Some random message
INFO Another message was logged
```

You can use the regular expression of `^INFO`:

```console
$ docker run \
    --log-driver=awslogs \
    --log-opt awslogs-region=us-east-1 \
    --log-opt awslogs-group=myLogGroup \
    --log-opt awslogs-multiline-pattern='^INFO' \
    ...
```

This parses the logs into the following CloudWatch log events:

```console
# First event
INFO A message was logged

# Second event
INFO Another multi-line message was logged
     Some random message

# Third event
INFO Another message was logged
```

### tag

Specify `tag` as an alternative to the `awslogs-stream` option. `tag` interprets
Go template markup, such as `{{.ID}}`, `{{.FullID}}`
or `{{.Name}}` `docker.{{.ID}}`. See
the [tag option documentation](../log-tags.md) for details on supported template
substitutions.

When both `awslogs-stream` and `tag` are specified, the value supplied for
`awslogs-stream` overrides the template specified with `tag`.

If not specified, the container ID is used as the log stream.

> [!NOTE]
>
> The CloudWatch log API doesn't support `:` in the log name. This can cause
> some issues when using the `{{ .ImageName }}` as a tag,
> since a Docker image has a format of `IMAGE:TAG`, such as `alpine:latest`.
> Template markup can be used to get the proper format. To get the image name
> and the first 12 characters of the container ID, you can use:
>
> ```bash
> --log-opt tag='{{ with split .ImageName ":" }}{{join . "_"}}{{end}}-{{.ID}}'
> ```
>
> the output is something like: `alpine_latest-bf0072049c76`

### awslogs-force-flush-interval-seconds

The `awslogs` driver periodically flushes logs to CloudWatch.

The `awslogs-force-flush-interval-seconds` option changes log flush interval seconds.

Default is 5 seconds.

### awslogs-max-buffered-events

The `awslogs` driver buffers logs.

The `awslogs-max-buffered-events` option changes log buffer size.

Default is 4K.

## Credentials

You must provide AWS credentials to the Docker daemon to use the `awslogs`
logging driver. You can provide these credentials with the `AWS_ACCESS_KEY_ID`,
`AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` environment variables, the
default AWS shared credentials file (`~/.aws/credentials` of the root user), or
if you are running the Docker daemon on an Amazon EC2 instance, the Amazon EC2
instance profile.

> [!NOTE]
> Docker reads AWS credentials when the container starts.
> If you use a shared AWS credentials file with temporary credentials,
> updating the file later does not automatically update the credentials
> used by the running container. When the temporary credentials expire,
> log delivery to Amazon CloudWatch Logs can fail. Restart the container
> after refreshing the credentials so Docker can load the updated values.

Credentials must have a policy applied that allows the `logs:CreateLogStream`
and `logs:PutLogEvents` actions, as shown in the following example.

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["logs:CreateLogStream", "logs:PutLogEvents"],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}
```


---

# ETW logging driver

*Sección: Engine*

The Event Tracing for Windows (ETW) logging driver forwards container logs as ETW events.
ETW stands for Event Tracing in Windows, and is the common framework
for tracing applications in Windows. Each ETW event contains a message
with both the log and its context information. A client can then create
an ETW listener to listen to these events.

The ETW provider that this logging driver registers with Windows, has the
GUID identifier of: `{a3693192-9ed6-46d2-a981-f8226c8363bd}`. A client creates an
ETW listener and registers to listen to events from the logging driver's provider.
It doesn't matter the order in which the provider and listener are created.
A client can create their ETW listener and start listening for events from the provider,
before the provider has been registered with the system.

## Usage

Here is an example of how to listen to these events using the logman utility program
included in most installations of Windows:

1. `logman start -ets DockerContainerLogs -p "{a3693192-9ed6-46d2-a981-f8226c8363bd}" 0x0 -o trace.etl`
2. Run your container(s) with the etwlogs driver, by adding
   `--log-driver=etwlogs` to the Docker run command, and generate log messages.
3. `logman stop -ets DockerContainerLogs`
4. This generates an etl file that contains the events. One way to convert this
   file into human-readable form is to run: `tracerpt -y trace.etl`.

Each ETW event contains a structured message string in this format:

```text
container_name: %s, image_name: %s, container_id: %s, image_id: %s, source: [stdout | stderr], log: %s
```

Details on each item in the message can be found below:

| Field            | Description                                    |
| ---------------- | ---------------------------------------------- |
| `container_name` | The container name at the time it was started. |
| `image_name`     | The name of the container's image.             |
| `container_id`   | The full 64-character container ID.            |
| `image_id`       | The full ID of the container's image.          |
| `source`         | `stdout` or `stderr`.                          |
| `log`            | The container log message.                     |

Here is an example event message (output formatted for readability):

```yaml
container_name: backstabbing_spence,
image_name: windowsservercore,
container_id: f14bb55aa862d7596b03a33251c1be7dbbec8056bbdead1da8ec5ecebbe29731,
image_id: sha256:2f9e19bd998d3565b4f345ac9aaf6e3fc555406239a4fb1b1ba879673713824b,
source: stdout,
log: Hello world!
```

A client can parse this message string to get both the log message, as well as its
context information. The timestamp is also available within the ETW event.

> [!NOTE]
>
> This ETW provider only emits a message string, and not a specially structured
> ETW event. Therefore, you don't have to register a manifest file with the
> system to read and interpret its ETW events.


---

# Fluentd logging driver

*Sección: Engine*

The `fluentd` logging driver sends container logs to the
[Fluentd](https://www.fluentd.org) collector as structured log data. Then, users
can use any of the [various output plugins of
Fluentd](https://www.fluentd.org/plugins) to write these logs to various
destinations.

In addition to the log message itself, the `fluentd` log
driver sends the following metadata in the structured log message:

| Field            | Description                                                                                                                                           |
| :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `container_id`   | The full 64-character container ID.                                                                                                                   |
| `container_name` | The container name at the time it was started. If you use `docker rename` to rename a container, the new name isn't reflected in the journal entries. |
| `source`         | `stdout` or `stderr`                                                                                                                                  |
| `log`            | The container log                                                                                                                                     |

## Usage

Some options are supported by specifying `--log-opt` as many times as needed:

- `fluentd-address`: specify a socket address to connect to the Fluentd daemon, ex `fluentdhost:24224` or `unix:///path/to/fluentd.sock`.
- `tag`: specify a tag for Fluentd messages. Supports some Go template markup, ex `{{.ID}}`, `{{.FullID}}` or `{{.Name}}` `docker.{{.ID}}`.

To use the `fluentd` driver as the default logging driver, set the `log-driver`
and `log-opt` keys to appropriate values in the `daemon.json` file. For more
about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `fluentd` and sets the
`fluentd-address` option.

```json
{
  "log-driver": "fluentd",
  "log-opts": {
    "fluentd-address": "fluentdhost:24224"
  }
}
```

Restart Docker for the changes to take effect.

> [!NOTE]
>
> `log-opts` configuration options in the `daemon.json` configuration file must
> be provided as strings. Boolean and numeric values (such as the value for
> `fluentd-async` or `fluentd-max-retries`) must therefore be enclosed
> in quotes (`"`).

To set the logging driver for a specific container, pass the
`--log-driver` option to `docker run`:

```console
$ docker run --log-driver=fluentd ...
```

Before using this logging driver, launch a Fluentd daemon. The logging driver
connects to this daemon through `localhost:24224` by default. Use the
`fluentd-address` option to connect to a different address.

```console
$ docker run --log-driver=fluentd --log-opt fluentd-address=fluentdhost:24224
```

If container cannot connect to the Fluentd daemon, the container stops
immediately unless the `fluentd-async` option is used.

## Options

Users can use the `--log-opt NAME=VALUE` flag to specify additional Fluentd logging driver options.

### fluentd-address

By default, the logging driver connects to `localhost:24224`. Supply the
`fluentd-address` option to connect to a different address. `tcp`(default) and `unix` sockets are supported.

```console
$ docker run --log-driver=fluentd --log-opt fluentd-address=fluentdhost:24224
$ docker run --log-driver=fluentd --log-opt fluentd-address=tcp://fluentdhost:24224
$ docker run --log-driver=fluentd --log-opt fluentd-address=unix:///path/to/fluentd.sock
```

Two of the above specify the same address, because `tcp` is default.

### tag

By default, Docker uses the first 12 characters of the container ID to tag log messages.
Refer to the [log tag option documentation](../log-tags.md) for customizing
the log tag format.

### labels, labels-regex, env, and env-regex

The `labels` and `env` options each take a comma-separated list of keys. If
there is collision between `label` and `env` keys, the value of the `env` takes
precedence. Both options add additional fields to the extra attributes of a
logging message.

The `env-regex` and `labels-regex` options are similar to and compatible with
respectively `env` and `labels`. Their values are regular expressions to match
logging-related environment variables and labels. It is used for advanced
[log tag options](../log-tags.md).

### fluentd-async

Docker connects to Fluentd in the background. Messages are buffered until the
connection is established. Defaults to `false`.

### fluentd-async-reconnect-interval

When `fluentd-async` is enabled, the `fluentd-async-reconnect-interval` option
defines the interval, in milliseconds, at which the connection to
`fluentd-address` is re-established. This option is useful if the address
resolves to one or more IP addresses, for example a Consul service address.

### fluentd-buffer-limit

Sets the number of events buffered on the memory. Records will be stored in memory
up to this number. If the buffer is full, the call to record logs will fail.
The default is 1048576.
(https://github.com/fluent/fluent-logger-golang/tree/master#bufferlimit)

### fluentd-retry-wait

How long to wait between retries. Defaults to 1 second.

### fluentd-max-retries

The maximum number of retries. Defaults to `4294967295` (2\*\*32 - 1).

### fluentd-sub-second-precision

Generates event logs in nanosecond resolution. Defaults to `false`.

### fluentd-write-timeout

Sets the timeout for the write call to the `fluentd` daemon. By default,
writes have no timeout and will block indefinitely.

## Fluentd daemon management with Docker

About `Fluentd` itself, see [the project webpage](https://www.fluentd.org)
and [its documents](https://docs.fluentd.org).

To use this logging driver, start the `fluentd` daemon on a host. We recommend
that you use [the Fluentd docker
image](https://hub.docker.com/r/fluent/fluentd/). This image is
especially useful if you want to aggregate multiple container logs on each
host then, later, transfer the logs to another Fluentd node to create an
aggregate store.

### Test container loggers

1.  Write a configuration file (`test.conf`) to dump input logs:

    ```text
    <source>
      @type forward
    </source>

    <match *>
      @type stdout
    </match>
    ```

2.  Launch Fluentd container with this configuration file:

    ```console
    $ docker run -it -p 24224:24224 -v /path/to/conf/test.conf:/fluentd/etc/test.conf -e FLUENTD_CONF=test.conf fluent/fluentd:latest
    ```

3.  Start one or more containers with the `fluentd` logging driver:

    ```console
    $ docker run --log-driver=fluentd your/application
    ```


---

# Google Cloud Logging driver

*Sección: Engine*

The Google Cloud Logging driver sends container logs to
[Google Cloud Logging](https://cloud.google.com/logging/docs/)
Logging.

## Usage

To use the `gcplogs` driver as the default logging driver, set the `log-driver`
and `log-opt` keys to appropriate values in the `daemon.json` file. For more
about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `gcplogs` and sets the
`gcp-meta-name` option.

```json
{
  "log-driver": "gcplogs",
  "log-opts": {
    "gcp-meta-name": "example-instance-12345"
  }
}
```

Restart Docker for the changes to take effect.

You can set the logging driver for a specific container by using the
`--log-driver` option to `docker run`:

```console
$ docker run --log-driver=gcplogs ...
```

If Docker detects that it's running in a Google Cloud Project, it discovers
configuration from the
[instance metadata service](https://cloud.google.com/compute/docs/metadata).
Otherwise, the user must specify
which project to log to using the `--gcp-project` log option and Docker
attempts to obtain credentials from the
[Google Application Default Credential](https://developers.google.com/identity/protocols/application-default-credentials).
The `--gcp-project` flag takes precedence over information discovered from the
metadata server, so a Docker daemon running in a Google Cloud project can be
overridden to log to a different project using `--gcp-project`.

Docker fetches the values for zone, instance name and instance ID from Google
Cloud metadata server. Those values can be provided via options if metadata
server isn't available. They don't override the values from metadata server.

## gcplogs options

You can use the `--log-opt NAME=VALUE` flag to specify these additional Google
Cloud Logging driver options:

| Option          | Required | Description                                                                                                                                                  |
| :-------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `gcp-project`   | optional | Which Google Cloud project to log to. Defaults to discovering this value from the Google Cloud metadata server.                                                               |
| `gcp-log-cmd`   | optional | Whether to log the command that the container was started with. Defaults to false.                                                                           |
| `labels`        | optional | Comma-separated list of keys of labels, which should be included in message, if these labels are specified for the container.                                |
| `labels-regex`  | optional | Similar to and compatible with `labels`. A regular expression to match logging-related labels. Used for advanced [log tag options](../log-tags.md).             |
| `env`           | optional | Comma-separated list of keys of environment variables, which should be included in message, if these variables are specified for the container.              |
| `env-regex`     | optional | Similar to and compatible with `env`. A regular expression to match logging-related environment variables. Used for advanced [log tag options](../log-tags.md). |
| `gcp-meta-zone` | optional | Zone name for the instance.                                                                                                                                  |
| `gcp-meta-name` | optional | Instance name.                                                                                                                                               |
| `gcp-meta-id`   | optional | Instance ID.                                                                                                                                                 |

If there is collision between `label` and `env` keys, the value of the `env`
takes precedence. Both options add additional fields to the attributes of a
logging message.

The following is an example of the logging options required to log to the default
logging destination which is discovered by querying the Google Cloud metadata server.

```console
$ docker run \
    --log-driver=gcplogs \
    --log-opt labels=location \
    --log-opt env=TEST \
    --log-opt gcp-log-cmd=true \
    --env "TEST=false" \
    --label location=west \
    your/application
```

This configuration also directs the driver to include in the payload the label
`location`, the environment variable `ENV`, and the command used to start the
container.

The following example shows logging options for running outside of Google
Cloud. The `GOOGLE_APPLICATION_CREDENTIALS` environment variable must be set
for the daemon, for example via systemd:

```ini
[Service]
Environment="GOOGLE_APPLICATION_CREDENTIALS=uQWVCPkMTI34bpssr1HI"
```

```console
$ docker run \
    --log-driver=gcplogs \
    --log-opt gcp-project=test-project \
    --log-opt gcp-meta-zone=west1 \
    --log-opt gcp-meta-name=`hostname` \
    your/application
```


---

# Graylog Extended Format logging driver

*Sección: Engine*

The `gelf` logging driver is a convenient format that's understood by a number of tools such as
[Graylog](https://www.graylog.org/), [Logstash](https://www.elastic.co/products/logstash), and
[Fluentd](https://www.fluentd.org). Many tools use this format.

In GELF, every log message is a dict with the following fields:

- Version
- Host (who sent the message in the first place)
- Timestamp
- Short and long version of the message
- Any custom fields you configure yourself

## Usage

To use the `gelf` driver as the default logging driver, set the `log-driver` and
`log-opt` keys to appropriate values in the `daemon.json` file. For more about
configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `gelf` and sets the `gelf-address`
option.

```json
{
  "log-driver": "gelf",
  "log-opts": {
    "gelf-address": "udp://1.2.3.4:12201"
  }
}
```

Restart Docker for the changes to take effect.

> [!NOTE]
>
> `log-opts` configuration options in the `daemon.json` configuration file must
> be provided as strings. Boolean and numeric values (such as the value for
> `gelf-tcp-max-reconnect`) must therefore be enclosed in quotes (`"`).

You can set the logging driver for a specific container by setting the
`--log-driver` flag when using `docker container create` or `docker run`:

```console
$ docker run \
      --log-driver gelf --log-opt gelf-address=udp://1.2.3.4:12201 \
      alpine echo hello world
```

### GELF options

The `gelf` logging driver supports the following options:

| Option                     | Required | Description                                                                                                                                                                                                                                                                         | Example value                                      |
| :------------------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------- |
| `gelf-address`             | required | The address of the GELF server. `tcp` and `udp` are the only supported URI specifier and you must specify the port.                                                                                                                                                                 | `--log-opt gelf-address=udp://192.168.0.42:12201`  |
| `gelf-compression-type`    | optional | `UDP Only` The type of compression the GELF driver uses to compress each log message. Allowed values are `gzip`, `zlib` and `none`. The default is `gzip`. Note that enabled compression leads to excessive CPU usage, so it's highly recommended to set this to `none`.            | `--log-opt gelf-compression-type=gzip`             |
| `gelf-compression-level`   | optional | `UDP Only` The level of compression when `gzip` or `zlib` is the `gelf-compression-type`. An integer in the range of `-1` to `9` (BestCompression). Default value is 1 (BestSpeed). Higher levels provide more compression at lower speed. Either `-1` or `0` disables compression. | `--log-opt gelf-compression-level=2`               |
| `gelf-tcp-max-reconnect`   | optional | `TCP Only` The maximum number of reconnection attempts when the connection drop. A positive integer. Default value is 3.                                                                                                                                                            | `--log-opt gelf-tcp-max-reconnect=3`               |
| `gelf-tcp-reconnect-delay` | optional | `TCP Only` The number of seconds to wait between reconnection attempts. A positive integer. Default value is 1.                                                                                                                                                                     | `--log-opt gelf-tcp-reconnect-delay=1`             |
| `tag`                      | optional | A string that's appended to the `APP-NAME` in the `gelf` message. By default, Docker uses the first 12 characters of the container ID to tag log messages. Refer to the [log tag option documentation](../log-tags.md) for customizing the log tag format.                             | `--log-opt tag=mailer`                             |
| `labels`                   | optional | Applies when starting the Docker daemon. A comma-separated list of logging-related labels this daemon accepts. Adds additional key on the `extra` fields, prefixed by an underscore (`_`). Used for advanced [log tag options](../log-tags.md).                                        | `--log-opt labels=production_status,geo`           |
| `labels-regex`             | optional | Similar to and compatible with `labels`. A regular expression to match logging-related labels. Used for advanced [log tag options](../log-tags.md).                                                                                                                                    | `--log-opt labels-regex=^(production_status\|geo)` |
| `env`                      | optional | Applies when starting the Docker daemon. A comma-separated list of logging-related environment variables this daemon accepts. Adds additional key on the `extra` fields, prefixed by an underscore (`_`). Used for advanced [log tag options](../log-tags.md).                         | `--log-opt env=os,customer`                        |
| `env-regex`                | optional | Similar to and compatible with `env`. A regular expression to match logging-related environment variables. Used for advanced [log tag options](../log-tags.md).                                                                                                                        | `--log-opt env-regex=^(os\|customer)`              |

> [!NOTE]
>
> The `gelf` driver doesn't support TLS for TCP connections. Messages sent to TLS-protected inputs can silently fail.

### Examples

This example configures the container to use the GELF server running at
`192.168.0.42` on port `12201`.

```console
$ docker run -dit \
    --log-driver=gelf \
    --log-opt gelf-address=udp://192.168.0.42:12201 \
    alpine sh
```


---

# Journald logging driver

*Sección: Engine*

The `journald` logging driver sends container logs to the
[`systemd` journal](https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html).
Log entries can be retrieved using the `journalctl` command, through use of the
`journal` API, or using the `docker logs` command.

In addition to the text of the log message itself, the `journald` log driver
stores the following metadata in the journal with each message:

| Field                                | Description                                                                                                                                           |
| :----------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `CONTAINER_ID`                       | The container ID truncated to 12 characters.                                                                                                          |
| `CONTAINER_ID_FULL`                  | The full 64-character container ID.                                                                                                                   |
| `CONTAINER_NAME`                     | The container name at the time it was started. If you use `docker rename` to rename a container, the new name isn't reflected in the journal entries. |
| `CONTAINER_TAG`, `SYSLOG_IDENTIFIER` | The container tag ([log tag option documentation](../log-tags.md)).                                                                                      |
| `CONTAINER_PARTIAL_MESSAGE`          | A field that flags log integrity. Improve logging of long log lines.                                                                                  |
| `IMAGE_NAME`                         | The name of the container image.                                                                                                                      |

## Usage

To use the `journald` driver as the default logging driver, set the `log-driver`
and `log-opts` keys to appropriate values in the `daemon.json` file. For more
about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `journald`:

```json
{
  "log-driver": "journald"
}
```

Restart Docker for the changes to take effect.

To configure the logging driver for a specific container, use the `--log-driver`
flag on the `docker run` command.

```console
$ docker run --log-driver=journald ...
```

## Options

Use the `--log-opt NAME=VALUE` flag to specify additional `journald` logging
driver options.

| Option         | Required | Description                                                                                                                                                                   |
| :------------- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tag`          | optional | Specify template to set `CONTAINER_TAG` and `SYSLOG_IDENTIFIER` value in journald logs. Refer to [log tag option documentation](../log-tags.md) to customize the log tag format. |
| `labels`       | optional | Comma-separated list of keys of labels, which should be included in message, if these labels are specified for the container.                                                 |
| `labels-regex` | optional | Similar to and compatible with labels. A regular expression to match logging-related labels. Used for advanced [log tag options](../log-tags.md).                                |
| `env`          | optional | Comma-separated list of keys of environment variables, which should be included in message, if these variables are specified for the container.                               |
| `env-regex`    | optional | Similar to and compatible with `env`. A regular expression to match logging-related environment variables. Used for advanced [log tag options](../log-tags.md).                    |

If a collision occurs between `label` and `env` options, the value of the `env`
takes precedence. Each option adds additional fields to the attributes of a
logging message.

The following is an example of the logging options required to log to journald.

```console
$ docker run \
    --log-driver=journald \
    --log-opt labels=location \
    --log-opt env=TEST \
    --env "TEST=false" \
    --label location=west \
    your/application
```

This configuration also directs the driver to include in the payload the label
location, and the environment variable `TEST`. If the `--env "TEST=false"`
or `--label location=west` arguments were omitted, the corresponding key would
not be set in the journald log.

## Note regarding container names

The value logged in the `CONTAINER_NAME` field is the name of the container that
was set at startup. If you use `docker rename` to rename a container, the new
name isn't reflected in the journal entries. Journal entries continue
to use the original name.

## Retrieve log messages with `journalctl`

Use the `journalctl` command to retrieve log messages. You can apply filter
expressions to limit the retrieved messages to those associated with a specific
container:

```console
$ sudo journalctl CONTAINER_NAME=webserver
```

You can use additional filters to further limit the messages retrieved. The `-b`
flag only retrieves messages generated since the last system boot:

```console
$ sudo journalctl -b CONTAINER_NAME=webserver
```

The `-o` flag specifies the format for the retrieved log messages. Use `-o json`
to return the log messages in JSON format.

```console
$ sudo journalctl -o json CONTAINER_NAME=webserver
```

### View logs for a container with a TTY enabled

If TTY is enabled on a container you may see `[10B blob data]` in the output
when retrieving log messages.
The reason for that is that `\r` is appended to the end of the line and
`journalctl` doesn't strip it automatically unless `--all` is set:

```console
$ sudo journalctl -b CONTAINER_NAME=webserver --all
```

## Retrieve log messages with the `journal` API

This example uses the `systemd` Python module to retrieve container
logs:

```python
import systemd.journal

reader = systemd.journal.Reader()
reader.add_match('CONTAINER_NAME=web')

for msg in reader:
    print('{CONTAINER_ID_FULL}: {MESSAGE}'.format(**msg))
```


---

# JSON File logging driver

*Sección: Engine*

By default, Docker captures the standard output (and standard error) of all your containers,
and writes them in files using the JSON format. The JSON format annotates each line with its
origin (`stdout` or `stderr`) and its timestamp. Each log file contains information about
only one container.

```json
{
  "log": "Log line is here\n",
  "stream": "stdout",
  "time": "2019-01-01T11:11:11.111111111Z"
}
```

> [!WARNING]
>
> The `json-file` logging driver uses file-based storage. These files are designed
> to be exclusively accessed by the Docker daemon. Interacting with these files
> with external tools may interfere with Docker's logging system and result in
> unexpected behavior, and should be avoided.

## Usage

To use the `json-file` driver as the default logging driver, set the `log-driver`
and `log-opts` keys to appropriate values in the `daemon.json` file. For more
information about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `json-file` and sets the `max-size`
and `max-file` options to enable automatic log-rotation.

```json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
```

> [!NOTE]
>
> `log-opts` configuration options in the `daemon.json` configuration file must
> be provided as strings. Boolean and numeric values (such as the value for
> `max-file` in the example above) must therefore be enclosed in quotes (`"`).

Restart Docker for the changes to take effect for newly created containers.
Existing containers don't use the new logging configuration automatically.

You can set the logging driver for a specific container by using the
`--log-driver` flag to `docker container create` or `docker run`:

```console
$ docker run \
      --log-driver json-file --log-opt max-size=10m \
      alpine echo hello world
```

### Options

The `json-file` logging driver supports the following logging options:

| Option         | Description                                                                                                                                                                                                   | Example value                                      |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------- |
| `max-size`     | The maximum size of the log before it is rolled. A positive integer plus a unit modifier (`k`, `m`, or `g`; case-insensitive). Defaults to -1 (unlimited).                                          | `--log-opt max-size=10m`                           |
| `max-file`     | The maximum number of log files that can be present. If rolling the logs creates excess files, the oldest file is removed. **Only effective when `max-size` is also set.** A positive integer. Defaults to 1. | `--log-opt max-file=3`                             |
| `labels`       | Applies when starting the Docker daemon. A comma-separated list of logging-related labels this daemon accepts. Used for advanced [log tag options](../log-tags.md).                                              | `--log-opt labels=production_status,geo`           |
| `labels-regex` | Similar to and compatible with `labels`. A regular expression to match logging-related labels. Used for advanced [log tag options](../log-tags.md).                                                              | `--log-opt labels-regex=^(production_status\|geo)` |
| `env`          | Applies when starting the Docker daemon. A comma-separated list of logging-related environment variables this daemon accepts. Used for advanced [log tag options](../log-tags.md).                               | `--log-opt env=os,customer`                        |
| `env-regex`    | Similar to and compatible with `env`. A regular expression to match logging-related environment variables. Used for advanced [log tag options](../log-tags.md).                                                  | `--log-opt env-regex=^(os\|customer)`              |
| `compress`     | Toggles compression for rotated logs. Defaults to `false` (no compression).                                                                                                                                   | `--log-opt compress=true`                          |

### Examples

This example starts an `alpine` container which can have a maximum of 3 log
files no larger than 10 megabytes each.

```console
$ docker run -it --log-opt max-size=10m --log-opt max-file=3 alpine ash
```


---

# Local file logging driver

*Sección: Engine*

The `local` logging driver captures output from container's stdout/stderr and
writes them to an internal storage that's optimized for performance and disk
use.

By default, the `local` driver preserves 100MB of log messages per container and
uses automatic compression to reduce the size on disk. The 100MB default value is based on a 20M default size
for each file and a default count of 5 for the number of such files (to account for log rotation).

> [!WARNING]
>
> The `local` logging driver uses file-based storage. These files are designed
> to be exclusively accessed by the Docker daemon. Interacting with these files
> with external tools may interfere with Docker's logging system and result in
> unexpected behavior, and should be avoided.

## Usage

To use the `local` driver as the default logging driver, set the `log-driver`
and `log-opt` keys to appropriate values in the `daemon.json` file. For more
about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `local` and sets the `max-size`
option.

```json
{
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m"
  }
}
```

Restart Docker for the changes to take effect for newly created containers.
Existing containers don't use the new logging configuration automatically.

You can set the logging driver for a specific container by using the
`--log-driver` flag to `docker container create` or `docker run`:

```console
$ docker run \
      --log-driver local --log-opt max-size=10m \
      alpine echo hello world
```

Note that `local` is a bash reserved keyword, so you may need to quote it in scripts.

### Options

The `local` logging driver supports the following logging options:

| Option     | Description                                                                                                                                                   | Example value              |
| :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------- |
| `max-size` | The maximum size of the log before it's rolled. A positive integer plus a unit modifier (`k`, `m`, or `g`; case-insensitive). Defaults to 20m.      | `--log-opt max-size=10m`   |
| `max-file` | The maximum number of log files that can be present. If rolling the logs creates excess files, the oldest file is removed. A positive integer. Defaults to 5. | `--log-opt max-file=3`     |
| `compress` | Toggle compression of rotated log files. Enabled by default.                                                                                                  | `--log-opt compress=false` |

### Examples

This example starts an `alpine` container which can have a maximum of 3 log
files no larger than 10 megabytes each.

```console
$ docker run -it --log-driver local --log-opt max-size=10m --log-opt max-file=3 alpine ash
```


---

# Splunk logging driver

*Sección: Engine*

The `splunk` logging driver sends container logs to
[HTTP Event Collector](https://dev.splunk.com/enterprise/docs/devtools/httpeventcollector/)
in Splunk Enterprise and Splunk Cloud.

## Usage

You can configure Docker logging to use the `splunk` driver by default or on a
per-container basis.

To use the `splunk` driver as the default logging driver, set the keys
`log-driver` and `log-opts` to appropriate values in the `daemon.json`
configuration file and restart Docker. For example:

```json
{
  "log-driver": "splunk",
  "log-opts": {
    "splunk-token": "",
    "splunk-url": "",
    ...
  }
}
```

For more about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

> [!NOTE]
>
> `log-opts` configuration options in the `daemon.json` configuration file must
> be provided as strings. Boolean and numeric values (such as the value for
> `splunk-gzip` or `splunk-gzip-level`) must therefore be enclosed in quotes
> (`"`).

To use the `splunk` driver for a specific container, use the commandline flags
`--log-driver` and `log-opt` with `docker run`:

```console
$ docker run --log-driver=splunk --log-opt splunk-token=VALUE --log-opt splunk-url=VALUE ...
```

## Splunk options

The following properties let you configure the Splunk logging driver.

- To configure the `splunk` driver across the Docker environment, edit
  `daemon.json` with the key, `"log-opts": {"NAME": "VALUE", ...}`.
- To configure the `splunk` driver for an individual container, use `docker run`
  with the flag, `--log-opt NAME=VALUE ...`.

| Option                      | Required | Description                                                                                                                                                                                                                                                                                                                                |
| :-------------------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `splunk-token`              | required | Splunk HTTP Event Collector token.                                                                                                                                                                                                                                                                                                         |
| `splunk-url`                | required | Path to your Splunk Enterprise, self-service Splunk Cloud instance, or Splunk Cloud managed cluster (including port and scheme used by HTTP Event Collector) in one of the following formats: `https://your_splunk_instance:8088`, `https://input-prd-p-XXXXXXX.cloud.splunk.com:8088`, or `https://http-inputs-XXXXXXXX.splunkcloud.com`. |
| `splunk-source`             | optional | Event source.                                                                                                                                                                                                                                                                                                                              |
| `splunk-sourcetype`         | optional | Event source type.                                                                                                                                                                                                                                                                                                                         |
| `splunk-index`              | optional | Event index.                                                                                                                                                                                                                                                                                                                               |
| `splunk-capath`             | optional | Path to root certificate.                                                                                                                                                                                                                                                                                                                  |
| `splunk-caname`             | optional | Name to use for validating server certificate; by default the hostname of the `splunk-url` is used.                                                                                                                                                                                                                                        |
| `splunk-insecureskipverify` | optional | Ignore server certificate validation.                                                                                                                                                                                                                                                                                                      |
| `splunk-format`             | optional | Message format. Can be `inline`, `json` or `raw`. Defaults to `inline`.                                                                                                                                                                                                                                                                    |
| `splunk-verify-connection`  | optional | Verify on start, that Docker can connect to Splunk server. Defaults to true.                                                                                                                                                                                                                                                               |
| `splunk-gzip`               | optional | Enable/disable gzip compression to send events to Splunk Enterprise or Splunk Cloud instance. Defaults to false.                                                                                                                                                                                                                           |
| `splunk-gzip-level`         | optional | Set compression level for gzip. Valid values are -1 (default), 0 (no compression), 1 (best speed) ... 9 (best compression). Defaults to [DefaultCompression](https://golang.org/pkg/compress/gzip/#DefaultCompression).                                                                                                                    |
| `tag`                       | optional | Specify tag for message, which interpret some markup. Default value is `{{.ID}}` (12 characters of the container ID). Refer to the [log tag option documentation](../log-tags.md) for customizing the log tag format.                                                                                                                         |
| `labels`                    | optional | Comma-separated list of keys of labels, which should be included in message, if these labels are specified for container.                                                                                                                                                                                                                  |
| `labels-regex`              | optional | Similar to and compatible with `labels`. A regular expression to match logging-related labels. Used for advanced [log tag options](../log-tags.md).                                                                                                                                                                                           |
| `env`                       | optional | Comma-separated list of keys of environment variables, which should be included in message, if these variables are specified for container.                                                                                                                                                                                                |
| `env-regex`                 | optional | Similar to and compatible with `env`. A regular expression to match logging-related environment variables. Used for advanced [log tag options](../log-tags.md).                                                                                                                                                                               |

If there is collision between the `label` and `env` keys, the value of the `env`
takes precedence. Both options add additional fields to the attributes of a
logging message.

Below is an example of the logging options specified for the Splunk Enterprise
instance. The instance is installed locally on the same machine on which the
Docker daemon is running.

The path to the root certificate and Common Name is specified using an HTTPS
scheme. This is used for verification. The `SplunkServerDefaultCert` is
automatically generated by Splunk certificates.

```console
$ docker run \
    --log-driver=splunk \
    --log-opt splunk-token=176FCEBF-4CF5-4EDF-91BC-703796522D20 \
    --log-opt splunk-url=https://splunkhost:8088 \
    --log-opt splunk-capath=/path/to/cert/cacert.pem \
    --log-opt splunk-caname=SplunkServerDefaultCert \
    --log-opt tag="{{.Name}}/{{.FullID}}" \
    --log-opt labels=location \
    --log-opt env=TEST \
    --env "TEST=false" \
    --label location=west \
    your/application
```

The `splunk-url` for Splunk instances hosted on Splunk Cloud is in a format
like `https://http-inputs-XXXXXXXX.splunkcloud.com` and does not include a
port specifier.

### Message formats

There are three logging driver messaging formats: `inline` (default), `json`,
and `raw`.

{{< tabs >}}
{{< tab name="Inline" >}}

The default format is `inline` where each log message is embedded as a string.
For example:

```json
{
  "attrs": {
    "env1": "val1",
    "label1": "label1"
  },
  "tag": "MyImage/MyContainer",
  "source": "stdout",
  "line": "my message"
}
```

```json
{
  "attrs": {
    "env1": "val1",
    "label1": "label1"
  },
  "tag": "MyImage/MyContainer",
  "source": "stdout",
  "line": "{\"foo\": \"bar\"}"
}
```

{{< /tab >}}
{{< tab name="JSON" >}}

To format messages as `json` objects, set `--log-opt splunk-format=json`. The
driver attempts to parse every line as a JSON object and send it as an embedded
object. If it can't parse the message, it's sent `inline`. For example:

```json
{
  "attrs": {
    "env1": "val1",
    "label1": "label1"
  },
  "tag": "MyImage/MyContainer",
  "source": "stdout",
  "line": "my message"
}
```

```json
{
  "attrs": {
    "env1": "val1",
    "label1": "label1"
  },
  "tag": "MyImage/MyContainer",
  "source": "stdout",
  "line": {
    "foo": "bar"
  }
}
```

{{< /tab >}}
{{< tab name="Raw" >}}

To format messages as `raw`, set `--log-opt splunk-format=raw`. Attributes
(environment variables and labels) and tags are prefixed to the message. For
example:

```console
MyImage/MyContainer env1=val1 label1=label1 my message
MyImage/MyContainer env1=val1 label1=label1 {"foo": "bar"}
```

{{< /tab >}}
{{< /tabs >}}

## Advanced options

The Splunk logging driver lets you configure a few advanced options by setting
environment variables for the Docker daemon.

| Environment variable name                        | Default value | Description                                                                                                                              |
| :----------------------------------------------- | :------------ | :--------------------------------------------------------------------------------------------------------------------------------------- |
| `SPLUNK_LOGGING_DRIVER_POST_MESSAGES_FREQUENCY`  | `5s`          | The time to wait for more messages to batch.                                                                                             |
| `SPLUNK_LOGGING_DRIVER_POST_MESSAGES_BATCH_SIZE` | `1000`        | The number of messages that should accumulate before sending them in one batch.                                                          |
| `SPLUNK_LOGGING_DRIVER_BUFFER_MAX`               | `10 * 1000`   | The maximum number of messages held in buffer for retries.                                                                               |
| `SPLUNK_LOGGING_DRIVER_CHANNEL_SIZE`             | `4 * 1000`    | The maximum number of pending messages that can be in the channel used to send messages to background logger worker, which batches them. |


---

# Syslog logging driver

*Sección: Engine*

The `syslog` logging driver routes logs to a `syslog` server. The `syslog` protocol uses
a raw string as the log message and supports a limited set of metadata. The syslog
message must be formatted in a specific way to be valid. From a valid message, the
receiver can extract the following information:

- Priority: the logging level, such as `debug`, `warning`, `error`, `info`.
- Timestamp: when the event occurred.
- Hostname: where the event happened.
- Facility: which subsystem logged the message, such as `mail` or `kernel`.
- Process name and process ID (PID): The name and ID of the process that generated the log.

The format is defined in [RFC 5424](https://tools.ietf.org/html/rfc5424) and Docker's syslog driver implements the
[ABNF reference](https://tools.ietf.org/html/rfc5424#section-6) in the following way:

```text
                TIMESTAMP SP HOSTNAME SP APP-NAME SP PROCID SP MSGID
                    +          +             +           |        +
                    |          |             |           |        |
                    |          |             |           |        |
       +------------+          +----+        |           +----+   +---------+
       v                            v        v                v             v
2017-04-01T17:41:05.616647+08:00 a.vm {taskid:aa,version:} 1787791 {taskid:aa,version:}
```

## Usage

To use the `syslog` driver as the default logging driver, set the `log-driver`
and `log-opt` keys to appropriate values in the `daemon.json` file. For more
about configuring Docker using `daemon.json`, see
[daemon.json](/reference/cli/dockerd.md#daemon-configuration-file).

{{% include "daemon-cfg-desktop.md" %}}

The following example sets the log driver to `syslog` and sets the
`syslog-address` option. The `syslog-address` options supports both UDP and TCP;
this example uses UDP.

```json
{
  "log-driver": "syslog",
  "log-opts": {
    "syslog-address": "udp://1.2.3.4:1111"
  }
}
```

Restart Docker for the changes to take effect.

> [!NOTE]
>
> `log-opts` configuration options in the `daemon.json` configuration file must
> be provided as strings. Numeric and Boolean values (such as the value for
> `syslog-tls-skip-verify`) must therefore be enclosed in quotes (`"`).

You can set the logging driver for a specific container by using the
`--log-driver` flag to `docker container create` or `docker run`:

```console
$ docker run \
      --log-driver syslog --log-opt syslog-address=udp://1.2.3.4:1111 \
      alpine echo hello world
```

## Options

The following logging options are supported as options for the `syslog` logging
driver. They can be set as defaults in the `daemon.json`, by adding them as
key-value pairs to the `log-opts` JSON array. They can also be set on a given
container by adding a `--log-opt <key>=<value>` flag for each option when
starting the container.

| Option                   | Description                                                                                                                                                                                                                                                                                                      | Example value                                                                                            |
| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------- |
| `syslog-address`         | The address of an external `syslog` server. The URI specifier may be `[tcp\|udp\|tcp+tls]://host:port`, `unix://path`, or `unixgram://path`. If the transport is `tcp`, `udp`, or `tcp+tls`, the default port is `514`.                                                                                          | `--log-opt syslog-address=tcp+tls://192.168.1.3:514`, `--log-opt syslog-address=unix:///tmp/syslog.sock` |
| `syslog-facility`        | The `syslog` facility to use. Can be the number or name for any valid `syslog` facility. See the [syslog documentation](https://tools.ietf.org/html/rfc5424#section-6.2.1).                                                                                                                                      | `--log-opt syslog-facility=daemon`                                                                       |
| `syslog-tls-ca-cert`     | The absolute path to the trust certificates signed by the CA. Ignored if the address protocol isn't `tcp+tls`.                                                                                                                                                                                                   | `--log-opt syslog-tls-ca-cert=/etc/ca-certificates/custom/ca.pem`                                        |
| `syslog-tls-cert`        | The absolute path to the TLS certificate file. Ignored if the address protocol isn't `tcp+tls`.                                                                                                                                                                                                                  | `--log-opt syslog-tls-cert=/etc/ca-certificates/custom/cert.pem`                                         |
| `syslog-tls-key`         | The absolute path to the TLS key file. Ignored if the address protocol isn't `tcp+tls`.                                                                                                                                                                                                                          | `--log-opt syslog-tls-key=/etc/ca-certificates/custom/key.pem`                                           |
| `syslog-tls-skip-verify` | If set to `true`, TLS verification is skipped when connecting to the `syslog` daemon. Defaults to `false`. Ignored if the address protocol isn't `tcp+tls`.                                                                                                                                                      | `--log-opt syslog-tls-skip-verify=true`                                                                  |
| `tag`                    | A string that's appended to the `APP-NAME` in the `syslog` message. By default, Docker uses the first 12 characters of the container ID to tag log messages. Refer to the [log tag option documentation](../log-tags.md) for customizing the log tag format.                                                        | `--log-opt tag=mailer`                                                                                   |
| `syslog-format`          | The `syslog` message format to use. If not specified the local Unix syslog format is used, without a specified hostname. Specify `rfc3164` for the RFC-3164 compatible format, `rfc5424` for RFC-5424 compatible format, or `rfc5424micro` for RFC-5424 compatible format with microsecond timestamp resolution. | `--log-opt syslog-format=rfc5424micro`                                                                   |
| `labels`                 | Applies when starting the Docker daemon. A comma-separated list of logging-related labels this daemon accepts. Used for advanced [log tag options](../log-tags.md).                                                                                                                                                 | `--log-opt labels=production_status,geo`                                                                 |
| `labels-regex`           | Applies when starting the Docker daemon. Similar to and compatible with `labels`. A regular expression to match logging-related labels. Used for advanced [log tag options](../log-tags.md).                                                                                                                        | `--log-opt labels-regex=^(production_status\|geo)`                                                       |
| `env`                    | Applies when starting the Docker daemon. A comma-separated list of logging-related environment variables this daemon accepts. Used for advanced [log tag options](../log-tags.md).                                                                                                                                  | `--log-opt env=os,customer`                                                                              |
| `env-regex`              | Applies when starting the Docker daemon. Similar to and compatible with `env`. A regular expression to match logging-related environment variables. Used for advanced [log tag options](../log-tags.md).                                                                                                            | `--log-opt env-regex=^(os\|customer)`                                                                    |


---

# Use docker logs with remote logging drivers

*Sección: Engine*

## Overview

You can use the `docker logs` command to read container logs regardless of the
configured logging driver or plugin. Docker Engine uses the [`local`](drivers/local.md)
logging driver to act as cache for reading the latest logs of your containers.
This is called dual logging. By default, the cache has log-file rotation
enabled, and is limited to a maximum of 5 files of 20 MB each (before
compression) per container.

Refer to the [configuration options](#configuration-options) section to customize
these defaults, or to the [disable dual logging](#disable-the-dual-logging-cache)
section to disable this feature.

## Prerequisites

Docker Engine automatically enables dual logging if the configured logging
driver doesn't support reading logs.

The following examples show the result of running a `docker logs` command with
and without dual logging availability:

### Without dual logging capability

When a container is configured with a remote logging driver such as `splunk`, and
dual logging is disabled, an error is displayed when attempting to read container
logs locally:

- Step 1: Configure Docker daemon

  ```console
  $ cat /etc/docker/daemon.json
  {
    "log-driver": "splunk",
    "log-opts": {
      "cache-disabled": "true",
      ... (options for "splunk" logging driver)
    }
  }
  ```

- Step 2: Start the container

  ```console
  $ docker run -d busybox --name testlog top
  ```

- Step 3: Read the container logs

  ```console
  $ docker logs 7d6ac83a89a0
  Error response from daemon: configured logging driver does not support reading
  ```

### With dual logging capability

With the dual logging cache enabled, the `docker logs` command can be used to
read logs, even if the logging driver doesn't support reading logs. The following
example shows a daemon configuration that uses the `splunk` remote logging driver
as a default, with dual logging caching enabled:

- Step 1: Configure Docker daemon

  ```console
  $ cat /etc/docker/daemon.json
  {
    "log-driver": "splunk",
    "log-opts": {
      ... (options for "splunk" logging driver)
    }
  }
  ```

- Step 2: Start the container

  ```console
  $ docker run -d busybox --name testlog top
  ```

- Step 3: Read the container logs

  ```console
  $ docker logs 7d6ac83a89a0
  2019-02-04T19:48:15.423Z [INFO]  core: marked as sealed
  2019-02-04T19:48:15.423Z [INFO]  core: pre-seal teardown starting
  2019-02-04T19:48:15.423Z [INFO]  core: stopping cluster listeners
  2019-02-04T19:48:15.423Z [INFO]  core: shutting down forwarding rpc listeners
  2019-02-04T19:48:15.423Z [INFO]  core: forwarding rpc listeners stopped
  2019-02-04T19:48:15.599Z [INFO]  core: rpc listeners successfully shut down
  2019-02-04T19:48:15.599Z [INFO]  core: cluster listeners successfully shut down
  ```

> [!NOTE]
>
> For logging drivers that support reading logs, such as the `local`, `json-file`
> and `journald` drivers, there is no difference in functionality before or after
> the dual logging capability became available. For these drivers, Logs can be
> read using `docker logs` in both scenarios.

### Configuration options

The dual logging cache accepts the same configuration options as the
[`local` logging driver](drivers/local.md), but with a `cache-` prefix. These options
can be specified per container, and defaults for new containers can be set using
the [daemon configuration file](/reference/cli/dockerd/#daemon-configuration-file).

By default, the cache has log-file rotation enabled, and is limited to a maximum
of 5 files of 20MB each (before compression) per container. Use the configuration
options described below to customize these defaults.

| Option           | Default   | Description                                                                                                                                       |
| :--------------- | :-------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
| `cache-disabled` | `"false"` | Disable local caching. Boolean value passed as a string (`true`, `1`, `0`, or `false`).                                                           |
| `cache-max-size` | `"20m"`   | The maximum size of the cache before it is rotated. A positive integer plus a unit modifier (`k`, `m`, or `g`; case-insensitive).       |
| `cache-max-file` | `"5"`     | The maximum number of cache files that can be present. If rotating the logs creates excess files, the oldest file is removed. A positive integer. |
| `cache-compress` | `"true"`  | Enable or disable compression of rotated log files. Boolean value passed as a string (`true`, `1`, `0`, or `false`).                              |

## Disable the dual logging cache

Use the `cache-disabled` option to disable the dual logging cache. Disabling the
cache can be useful to save storage space in situations where logs are only read
through a remote logging system, and if there is no need to read logs through
`docker logs` for debugging purposes.

Caching can be disabled for individual containers or by default for new containers,
when using the [daemon configuration file](/reference/cli/dockerd/#daemon-configuration-file).

The following example uses the daemon configuration file to use the [`splunk`](drivers/splunk.md)
logging driver as a default, with caching disabled:

```console
$ cat /etc/docker/daemon.json
{
  "log-driver": "splunk",
  "log-opts": {
    "cache-disabled": "true",
    ... (options for "splunk" logging driver)
  }
}
```

> [!NOTE]
>
> For logging drivers that support reading logs, such as the `local`, `json-file`
> and `journald` drivers, dual logging isn't used, and disabling the option has
> no effect.

## Limitations

- If a container using a logging driver or plugin that sends logs remotely
  has a network issue, no `write` to the local cache occurs.
- If a write to `logdriver` fails for any reason (file system full, write
  permissions removed), the cache write fails and is logged in the daemon log.
  The log entry to the cache isn't retried.
- Some logs might be lost from the cache in the default configuration because a
  ring buffer is used to prevent blocking the stdio of the container in case of
  slow file writes. An admin must repair these while the daemon is shut down.


---

# Customize log driver output

*Sección: Engine*

The `tag` log option specifies how to format a tag that identifies the
container's log messages. By default, the system uses the first 12 characters of
the container ID. To override this behavior, specify a `tag` option:

```console
$ docker run --log-driver=fluentd --log-opt fluentd-address=myhost.local:24224 --log-opt tag="mailer"
```

Docker supports some special template markup you can use when specifying a tag's value:

| Markup             | Description                                          |
| ------------------ | ---------------------------------------------------- |
| `{{.ID}}`          | The first 12 characters of the container ID.         |
| `{{.FullID}}`      | The full container ID.                               |
| `{{.Name}}`        | The container name.                                  |
| `{{.ImageID}}`     | The first 12 characters of the container's image ID. |
| `{{.ImageFullID}}` | The container's full image ID.                       |
| `{{.ImageName}}`   | The name of the image used by the container.         |
| `{{.DaemonName}}`  | The name of the Docker program (`docker`).           |

For example, specifying a `--log-opt tag="{{.ImageName}}/{{.Name}}/{{.ID}}"` value yields `syslog` log lines like:

```text
Aug  7 18:33:19 HOSTNAME hello-world/foobar/5790672ab6a0[9103]: Hello from Docker.
```

At startup time, the system sets the `container_name` field and `{{.Name}}` in
the tags. If you use `docker rename` to rename a container, the new name isn't
reflected in the log messages. Instead, these messages continue to use the
original container name.


---

# Use a logging driver plugin

*Sección: Engine*

Docker logging plugins allow you to extend and customize Docker's logging
capabilities beyond those of the [built-in logging drivers](configure.md).
A logging service provider can
[implement their own plugins](/manuals/engine/extend/plugins_logging.md) and make them
available on Docker Hub, or a private registry. This topic shows
how a user of that logging service can configure Docker to use the plugin.

## Install the logging driver plugin

To install a logging driver plugin, use `docker plugin install <org/image>`,
using the information provided by the plugin developer.

You can list all installed plugins using `docker plugin ls`, and you can inspect
a specific plugin using `docker inspect`.

## Configure the plugin as the default logging driver

When the plugin is installed, you can configure the Docker daemon to use it as
the default by setting the plugin's name as the value of the `log-driver`
key in the `daemon.json`, as detailed in the
[logging overview](configure.md#configure-the-default-logging-driver). If the
logging driver supports additional options, you can set those as the values of
the `log-opts` array in the same file.

## Configure a container to use the plugin as the logging driver

After the plugin is installed, you can configure a container to use the plugin
as its logging driver by specifying the `--log-driver` flag to `docker run`, as
detailed in the
[logging overview](configure.md#configure-the-logging-driver-for-a-container).
If the logging driver supports additional options, you can specify them using
one or more `--log-opt` flags with the option name as the key and the option
value as the value.


---

# Manage resources

*Sección: Engine*




---

# Docker contexts

*Sección: Engine*

## Introduction

This guide shows how you can use contexts to manage Docker daemons from a single client.

Each context contains all information required to manage resources on the daemon.
The `docker context` command makes it easy to configure these contexts and switch between them.

As an example, a single Docker client might be configured with two contexts:

- A default context running locally
- A remote, shared context

Once these contexts are configured,
you can use the `docker context use <context-name>` command
to switch between them.

## Prerequisites

To follow the examples in this guide, you'll need:

- A Docker client that supports the top-level `context` command

Run `docker context` to verify that your Docker client supports contexts.

## The anatomy of a context

A context is a combination of several properties. These include:

- Name and description
- Endpoint configuration
- TLS info

To list available contexts, use the `docker context ls` command.

```console
$ docker context ls
NAME        DESCRIPTION                               DOCKER ENDPOINT               ERROR
default *                                             unix:///var/run/docker.sock
```

This shows a single context called "default".
It's configured to talk to a daemon through the local `/var/run/docker.sock` Unix socket.

The asterisk in the `NAME` column indicates that this is the active context.
This means all `docker` commands run against this context,
unless overridden with environment variables such as `DOCKER_HOST` and `DOCKER_CONTEXT`,
or on the command-line with the `--context` and `--host` flags.

Dig a bit deeper with `docker context inspect`.
The following example shows how to inspect the context called `default`.

```console
$ docker context inspect default
[
    {
        "Name": "default",
        "Metadata": {},
        "Endpoints": {
            "docker": {
                "Host": "unix:///var/run/docker.sock",
                "SkipTLSVerify": false
            }
        },
        "TLSMaterial": {},
        "Storage": {
            "MetadataPath": "\u003cIN MEMORY\u003e",
            "TLSPath": "\u003cIN MEMORY\u003e"
        }
    }
]
```

### Create a new context

You can create new contexts with the `docker context create` command.

The following example creates a new context called `docker-test` and specifies
the host endpoint of the context to TCP socket `tcp://docker:2375`.

```console
$ docker context create docker-test --docker host=tcp://docker:2375
docker-test
Successfully created context "docker-test"
```

The new context is stored in a `meta.json` file below `~/.docker/contexts/`.
Each new context you create gets its own `meta.json` stored in a dedicated sub-directory of `~/.docker/contexts/`.

You can view the new context with `docker context ls` and `docker context inspect <context-name>`.

```console
$ docker context ls
NAME          DESCRIPTION                             DOCKER ENDPOINT               ERROR
default *                                             unix:///var/run/docker.sock
docker-test                                           tcp://docker:2375
```

The current context is indicated with an asterisk ("\*").

## Use a different context

You can use `docker context use` to switch between contexts.

The following command will switch the `docker` CLI to use the `docker-test` context.

```console
$ docker context use docker-test
docker-test
Current context is now "docker-test"
```

Verify the operation by listing all contexts and ensuring the asterisk ("\*") is against the `docker-test` context.

```console
$ docker context ls
NAME            DESCRIPTION                           DOCKER ENDPOINT               ERROR
default                                               unix:///var/run/docker.sock
docker-test *                                         tcp://docker:2375
```

`docker` commands will now target endpoints defined in the `docker-test` context.

You can also set the current context using the `DOCKER_CONTEXT` environment variable.
The environment variable overrides the context set with `docker context use`.

Use the appropriate command below to set the context to `docker-test` using an environment variable.

{{< tabs >}}
{{< tab name="PowerShell" >}}

```ps
> $env:DOCKER_CONTEXT='docker-test'
```

{{< /tab >}}
{{< tab name="Bash" >}}

```console
$ export DOCKER_CONTEXT=docker-test
```

{{< /tab >}}
{{< /tabs >}}

Run `docker context ls` to verify that the `docker-test` context is now the
active context.

You can also use the global `--context` flag to override the context.
The following command uses a context called `production`.

```console
$ docker --context production container ls
```

## Exporting and importing Docker contexts

You can use the `docker context export` and `docker context import` commands
to export and import contexts on different hosts.

The `docker context export` command exports an existing context to a file.
The file can be imported on any host that has the `docker` client installed.

### Exporting and importing a context

The following example exports an existing context called `docker-test`.
It will be written to a file called `docker-test.dockercontext`.

```console
$ docker context export docker-test
Written file "docker-test.dockercontext"
```

Check the contents of the export file.

```console
$ cat docker-test.dockercontext
```

Import this file on another host using `docker context import`
to create context with the same configuration.

```console
$ docker context import docker-test docker-test.dockercontext
docker-test
Successfully imported context "docker-test"
```

You can verify that the context was imported with `docker context ls`.

The format of the import command is `docker context import <context-name> <context-file>`.

## Updating a context

You can use `docker context update` to update fields in an existing context.

The following example updates the description field in the existing `docker-test` context.

```console
$ docker context update docker-test --description "Test context"
docker-test
Successfully updated context "docker-test"
```


---

# Docker object labels

*Sección: Engine*

Labels are a mechanism for applying metadata to Docker objects, including:

- Images
- Containers
- Local daemons
- Volumes
- Networks
- Swarm nodes
- Swarm services

You can use labels to organize your images, record licensing information, annotate
relationships between containers, volumes, and networks, or in any way that makes
sense for your business or application.

## Label keys and values

A label is a key-value pair, stored as a string. You can specify multiple labels
for an object, but each key must be unique within an object. If the
same key is given multiple values, the most-recently-written value overwrites
all previous values.

### Key format recommendations

A label key is the left-hand side of the key-value pair. Keys are alphanumeric
strings which may contain periods (`.`), underscores (`_`), slashes (`/`), and hyphens (`-`). Most Docker users use
images created by other organizations, and the following guidelines help to
prevent inadvertent duplication of labels across objects, especially if you plan
to use labels as a mechanism for automation.

- Authors of third-party tools should prefix each label key with the
  reverse DNS notation of a domain they own, such as `com.example.some-label`.

- Don't use a domain in your label key without the domain owner's permission.

- The `com.docker.*`, `io.docker.*`, and `org.dockerproject.*` namespaces are
  reserved by Docker for internal use.

- Label keys should begin and end with a lower-case letter and should only
  contain lower-case alphanumeric characters, the period character (`.`), and
  the hyphen character (`-`). Consecutive periods or hyphens aren't allowed.

- The period character (`.`) separates namespace "fields". Label keys without
  namespaces are reserved for CLI use, allowing users of the CLI to interactively
  label Docker objects using shorter typing-friendly strings.

These guidelines aren't currently enforced and additional guidelines may apply
to specific use cases.

### Value guidelines

Label values can contain any data type that can be represented as a string,
including (but not limited to) JSON, XML, CSV, or YAML. The only requirement is
that the value be serialized to a string first, using a mechanism specific to
the type of structure. For instance, to serialize JSON into a string, you might
use the `JSON.stringify()` JavaScript method.

Since Docker doesn't deserialize the value, you can't treat a JSON or XML
document as a nested structure when querying or filtering by label value unless
you build this functionality into third-party tooling.

## Manage labels on objects

Each type of object with support for labels has mechanisms for adding and
managing them and using them as they relate to that type of object.

Labels on images, containers, local daemons, volumes, and networks are static
for the lifetime of the object. To change these labels you must recreate the
object. Labels on Swarm nodes and services can be updated dynamically.

### Images

Add labels to images using the [`LABEL` instruction](../../build/concepts/dockerfile.md#label) in a Dockerfile:

```dockerfile
LABEL com.example.version="1.0"
LABEL com.example.description="Web application"
```

You can also set labels at build time with the `--label` flag, without needing
a `LABEL` instruction in the Dockerfile:

```console
$ docker build --label "com.example.version=1.0" -t myapp .
```

Inspect labels on an image using `docker inspect`:

```console
$ docker inspect --format='{{json .Config.Labels}}' myapp
```

Filter images by label with [`docker image ls --filter`](/reference/cli/docker/image/ls/#filter):

```console
$ docker image ls --filter "label=com.example.version"
```

### Containers

Override or add labels when starting a container with
[`docker run --label`](/reference/cli/docker/container/run/#label):

```console
$ docker run --label "com.example.env=prod" myapp
```

Inspect labels on a container:

```console
$ docker inspect --format='{{json .Config.Labels}}' mycontainer
```

Filter containers by label with [`docker container ls --filter`](/reference/cli/docker/container/ls/#filter):

```console
$ docker container ls --filter "label=com.example.env=prod"
```

### Local Docker daemons

Add labels to the Docker daemon by passing `--label` flags when starting
`dockerd`, or by setting `"labels"` in the
[daemon configuration file](/reference/cli/dockerd.md#daemon-configuration-file):

```json
{
  "labels": ["com.example.environment=production"]
}
```

View daemon labels with `docker system info`.

### Volumes

Add labels when [creating a volume](/reference/cli/docker/volume/create/):

```console
$ docker volume create --label "com.example.purpose=database" myvolume
```

Inspect volume labels:

```console
$ docker volume inspect myvolume --format='{{json .Labels}}'
```

Filter volumes by label with [`docker volume ls --filter`](/reference/cli/docker/volume/ls/#filter):

```console
$ docker volume ls --filter "label=com.example.purpose"
```

### Networks

Add labels when [creating a network](/reference/cli/docker/network/create/):

```console
$ docker network create --label "com.example.purpose=frontend" mynetwork
```

Inspect network labels:

```console
$ docker network inspect mynetwork --format='{{json .Labels}}'
```

Filter networks by label with [`docker network ls --filter`](/reference/cli/docker/network/ls/#filter):

```console
$ docker network ls --filter "label=com.example.purpose"
```

### Swarm nodes

- [Adding or updating a Swarm node's labels](/reference/cli/docker/node/update/#label-add)
- [Filtering Swarm nodes by label](/reference/cli/docker/node/ls/#filter)

### Swarm services

- [Adding labels when creating a Swarm service](/reference/cli/docker/service/create/#label)
- [Updating a Swarm service's labels](/reference/cli/docker/service/update/)
- [Filtering Swarm services by label](/reference/cli/docker/service/ls/#filter)


---

# Prune unused Docker objects

*Sección: Engine*

Docker takes a conservative approach to cleaning up unused objects (often
referred to as "garbage collection"), such as images, containers, volumes,
networks, and build cache. These objects are generally not removed unless you
explicitly ask Docker to do so. This can cause Docker to use extra disk space.
For each type of object, Docker provides a `prune` command. In addition, you can
use `docker system prune` to clean up multiple types of objects at once
(including unused build cache). This topic shows how to use these `prune`
commands.

## Prune images

The `docker image prune` command allows you to clean up unused images. By
default, `docker image prune` only cleans up _dangling_ images. A dangling image
is one that isn't tagged, and isn't referenced by any container. To remove
dangling images:

```console
$ docker image prune

WARNING! This will remove all dangling images.
Are you sure you want to continue? [y/N] y
```

To remove all images which aren't used by existing containers, use the `-a`
flag:

```console
$ docker image prune -a

WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
```

By default, you are prompted to continue. To bypass the prompt, use the `-f` or
`--force` flag.

You can limit which images are pruned using filtering expressions with the
`--filter` flag. For example, to only consider images created more than 24
hours ago:

```console
$ docker image prune -a --filter "until=24h"
```

Other filtering expressions are available. See the
[`docker image prune` reference](/reference/cli/docker/image/prune/)
for more examples.

## Prune containers

When you stop a container, it isn't automatically removed unless you started it
with the `--rm` flag. To see all containers on the Docker host, including
stopped containers, use `docker ps -a`. You may be surprised how many containers
exist, especially on a development system! A stopped container's writable layers
still take up disk space. To clean this up, you can use the `docker container
prune` command.

```console
$ docker container prune

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
```

By default, you're prompted to continue. To bypass the prompt, use the `-f` or
`--force` flag.

By default, all stopped containers are removed. You can limit the scope using
the `--filter` flag. For instance, the following command only removes
stopped containers older than 24 hours:

```console
$ docker container prune --filter "until=24h"
```

Other filtering expressions are available. See the
[`docker container prune` reference](/reference/cli/docker/container/prune/)
for more examples.

## Prune volumes

Volumes can be used by one or more containers, and take up space on the Docker
host. Volumes are never removed automatically, because to do so could destroy
data.

```console
$ docker volume prune

WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
```

By default, you are prompted to continue. To bypass the prompt, use the `-f` or
`--force` flag.

By default, only **anonymous** unused volumes are removed. Named volumes that
aren't attached to a container are left alone unless you pass `--all` / `-a`.
You can also limit the scope with the `--filter` flag. For instance, the
following command only removes volumes which aren't labelled with the `keep`
label:

```console
$ docker volume prune --filter "label!=keep"
```

Other filtering expressions are available. See the
[`docker volume prune` reference](/reference/cli/docker/volume/prune/)
for more examples.

## Prune networks

Docker networks don't take up much disk space, but they do create `iptables`
rules, bridge network devices, and routing table entries. To clean these things
up, you can use `docker network prune` to clean up networks which aren't used
by any containers.

```console
$ docker network prune

WARNING! This will remove all networks not used by at least one container.
Are you sure you want to continue? [y/N] y
```

By default, you're prompted to continue. To bypass the prompt, use the `-f` or
`--force` flag.

By default, all unused networks are removed. You can limit the scope using
the `--filter` flag. For instance, the following command only removes
networks older than 24 hours:

```console
$ docker network prune --filter "until=24h"
```

Other filtering expressions are available. See the
[`docker network prune` reference](/reference/cli/docker/network/prune/)
for more examples.

## Prune build cache

`docker buildx prune` removes the build cache for the currently selected
builder. If you use multiple builders, each builder maintains its own cache —
use the `--builder` flag to target a specific builder instance.

```console
$ docker buildx prune

WARNING! This will remove all dangling build cache.
Are you sure you want to continue? [y/N] y
```

By default, you're prompted to continue. To bypass the prompt, use the `-f` or
`--force` flag.

See the [`docker buildx prune` reference](/reference/cli/docker/buildx/prune/)
for all options, including `--all` to also remove internal and frontend images.

## Prune everything

The `docker system prune` command is a shortcut that prunes images, containers,
networks, and unused build cache (including BuildKit cache mounts). Volumes
aren't pruned by default. Add `--volumes` to also remove unused **anonymous**
volumes. Named unused volumes are left alone; use `docker volume prune --all`
if you intend to delete those too.

```console
$ docker system prune

WARNING! This will remove:
        - all stopped containers
        - all networks not used by at least one container
        - all dangling images
        - unused build cache

Are you sure you want to continue? [y/N] y
```

To also prune unused anonymous volumes, add the `--volumes` flag:

```console
$ docker system prune --volumes

WARNING! This will remove:
        - all stopped containers
        - all networks not used by at least one container
        - all anonymous volumes not used by at least one container
        - all dangling images
        - unused build cache

Are you sure you want to continue? [y/N] y
```

By default, you're prompted to continue. To bypass the prompt, use the `-f` or
`--force` flag.

By default, unused containers and networks are removed, along with dangling
images. Unused tagged images are kept unless you also pass `-a` / `--all`.
You can further limit the scope with the `--filter` flag. For instance, the
following command removes items older than 24 hours:

```console
$ docker system prune --filter "until=24h"
```

Other filtering expressions are available. See the
[`docker system prune` reference](/reference/cli/docker/system/prune/)
for more examples.


---

# Networking overview

*Sección: Engine*

Container networking refers to the ability for containers to connect to and
communicate with each other, and with non-Docker network services.

Containers have networking enabled by default, and they can make outgoing
connections. A container has no information about what kind of network it's
attached to, or whether its network peers are also Docker containers. A
container only sees a network interface with an IP address, a gateway, a
routing table, DNS services, and other networking details.

This page describes networking from the point of view of the container,
and the concepts around container networking.

When Docker Engine on Linux starts for the first time, it has a single
built-in network called the "default bridge" network. When you run a
container without the `--network` option, it is connected to the default
bridge.

Containers attached to the default bridge have access to network services
outside the Docker host. They use "masquerading" which means, if the
Docker host has Internet access, no additional configuration is needed
for the container to have Internet access.

For example, to run a container on the default bridge network, and have
it ping an Internet host:

```console
$ docker run --rm -ti busybox ping -c1 docker.com
PING docker.com (23.185.0.4): 56 data bytes
64 bytes from 23.185.0.4: seq=0 ttl=62 time=6.564 ms

--- docker.com ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 6.564/6.564/6.564 ms
```

## User-defined networks

With the default configuration, containers attached to the default
bridge network have unrestricted network access to each other using
container IP addresses. They cannot refer to each other by name.

It can be useful to separate groups of containers that should have full
access to each other, but restricted access to containers in other groups.

You can create custom, user-defined networks, and connect groups of containers
to the same network. Once connected to a user-defined network, containers
can communicate with each other using container IP addresses or container names.

The following example creates a network using the `bridge` network driver and
runs a container in that network:

```console
$ docker network create -d bridge my-net
$ docker run --network=my-net -it busybox
```

### Drivers

Docker Engine has a number of network drivers, as well as the default "bridge".
On Linux, the following built-in network drivers are available:

| Driver                          | Description                                                         |
| :------------------------------ | :------------------------------------------------------------------ |
| [bridge](drivers/bridge.md)   | The default network driver.                                         |
| [host](drivers/host.md)       | Remove network isolation between the container and the Docker host. |
| [none](drivers/none.md)       | Completely isolate a container from the host and other containers.  |
| [overlay](drivers/overlay.md) | Swarm Overlay networks connect multiple Docker daemons together.    |
| [ipvlan](drivers/ipvlan.md)   | Connect containers to external VLANs.                               |
| [macvlan](drivers/macvlan.md) | Containers appear as devices on the host's network.                 |

More information can be found in the network driver specific pages, including
their configuration options and details about their functionality.

Native Windows containers have a different set of drivers, see
[Windows container network drivers](https://learn.microsoft.com/en-us/virtualization/windowscontainers/container-networking/network-drivers-topologies).

### Connecting to multiple networks

Connecting a container to a network can be compared to connecting an Ethernet
cable to a physical host. Just as a host can be connected to multiple Ethernet
networks, a container can be connected to multiple Docker networks.

For example, a frontend container may be connected to a bridge network
with external access, and a
[`--internal`](/reference/cli/docker/network/create/#internal) network
to communicate with containers running backend services that do not need
external network access.

A container may also be connected to different types of network. For example,
an `ipvlan` network to provide internet access, and a `bridge` network for
access to local services.

Containers can also share networking stacks, see [Container networks](#container-networks).

When sending packets, if the destination is an address in a directly connected
network, packets are sent to that network. Otherwise, packets are sent to
a default gateway for routing to their destination. In the example above,
the `ipvlan` network's gateway must be the default gateway.

The default gateway is selected by Docker, and may change whenever a
container's network connections change.
To make Docker choose a specific default gateway when creating the container
or connecting a new network, set a gateway priority. See option `gw-priority`
for the [`docker run`](/reference/cli/docker/container/run/) and
[`docker network connect`](/reference/cli/docker/network/connect/) commands.

The default `gw-priority` is `0` and the gateway in the network with the
highest priority is the default gateway. So, when a network should always
be the default gateway, it is enough to set its `gw-priority` to `1`.

```console
$ docker run --network name=gwnet,gw-priority=1 --network anet1 --name myctr myimage
$ docker network connect anet2 myctr
```

## Published ports

When you create or run a container using `docker create` or `docker run`, all
ports of containers on bridge networks are accessible from the Docker host and
other containers connected to the same network. Ports are not accessible from
outside the host or, with the default configuration, from containers in other
networks.

Use the `--publish` or `-p` flag to make a port available outside the host,
and to containers in other bridge networks.

For more information about port mapping, including how to disable it and use
direct routing to containers, see
[port publishing](port-publishing.md).

## IP address and hostname

When creating a network, IPv4 address allocation is enabled by default, it
can be disabled using `--ipv4=false`. IPv6 address allocation can be enabled
using `--ipv6`.

```console
$ docker network create --ipv6 --ipv4=false v6net
```

By default, the container gets an IP address for every Docker network it attaches to.
A container receives an IP address out of the IP subnet of the network.
The Docker daemon performs dynamic subnetting and IP address allocation for containers.
Each network also has a default subnet mask and gateway.

You can connect a running container to multiple networks,
either by passing the `--network` flag multiple times when creating the container,
or using the `docker network connect` command for already running containers.
In both cases, you can use the `--ip` or `--ip6` flags to specify the container's IP address on that particular network.

In the same way, a container's hostname defaults to be the container's ID in Docker.
You can override the hostname using `--hostname`.
When connecting to an existing network using `docker network connect`,
you can use the `--alias` flag to specify an additional network alias for the container on that network.

### Subnet allocation

Docker networks can use either explicitly configured subnets or automatically allocated ones from default pools.

#### Explicit subnet configuration

You can specify exact subnets when creating a network:

```console
$ docker network create --ipv6 --subnet 192.0.2.0/24 --subnet 2001:db8::/64 mynet
```

#### Automatic subnet allocation

When no `--subnet` option is provided, Docker automatically selects a subnet from predefined "default address pools".
These pools can be configured in `/etc/docker/daemon.json`. Docker's built-in default is equivalent to:

```json
{
  "default-address-pools": [
    { "base": "172.17.0.0/16", "size": 16 },
    { "base": "172.18.0.0/16", "size": 16 },
    { "base": "172.19.0.0/16", "size": 16 },
    { "base": "172.20.0.0/14", "size": 16 },
    { "base": "172.24.0.0/14", "size": 16 },
    { "base": "172.28.0.0/14", "size": 16 },
    { "base": "192.168.0.0/16", "size": 20 }
  ]
}
```

- `base`: The subnet that can be allocated from.
- `size`: The prefix length used for each allocated subnet.

When an IPv6 subnet is required and there are no IPv6 addresses in `default-address-pools`, Docker allocates
subnets from a Unique Local Address (ULA) prefix. To use specific IPv6 subnets instead, add them to your
`default-address-pools`. See [Dynamic IPv6 subnet allocation](../daemon/ipv6.md#dynamic-ipv6-subnet-allocation)
for more information.

Docker attempts to avoid address prefixes already in use on the host. However, you may need to customize
`default-address-pools` to prevent routing conflicts in some network environments.

The default pools use large subnets, which limits the number of networks you can create. You can divide base
subnets into smaller pools to support more networks.

For example, this configuration allows Docker to create 256 networks from `172.17.0.0/16`.
Docker will allocate subnets `172.17.0.0/24`, `172.17.1.0/24`, and so on, up to `172.17.255.0/24`:

```json
{
  "default-address-pools": [{ "base": "172.17.0.0/16", "size": 24 }]
}
```

You can also request a subnet with a specific prefix length from the default pools by using unspecified
addresses in the `--subnet` option:

```console
$ docker network create --ipv6 --subnet ::/56 --subnet 0.0.0.0/24 mynet
6686a6746b17228f5052528113ddad0e6d68e2e3905d648e336b33409f2d3b64
$ docker network inspect mynet -f '{{json .IPAM.Config}}' | jq .
[
  {
    "Subnet": "172.19.0.0/24",
    "Gateway": "172.19.0.1"
  },
  {
    "Subnet": "fdd3:6f80:972c::/56",
    "Gateway": "fdd3:6f80:972c::1"
  }
]
```

> [!NOTE]
>
> Support for unspecified addresses in `--subnet` was introduced in Docker 29.0.0.
> If Docker is downgraded to an older version, networks created in this way will become unusable.
> They can be removed and re-created, or will function again if the daemon is restored to 29.0.0 or later.

## DNS services

Containers use the same DNS servers as the host by default, but you can
override this with `--dns`.

By default, containers inherit the DNS settings as defined in the
`/etc/resolv.conf` configuration file.
Containers that attach to the default `bridge` network receive a copy of this file.
Containers that attach to a
[custom network](drivers/bridge.md#use-user-defined-bridge-networks)
use Docker's embedded DNS server.
The embedded DNS server forwards external DNS lookups to the DNS servers configured on the host.
The embedded DNS server address is `127.0.0.11`.
There is no IPv6 equivalent; the IPv4 address works even in IPv6-only containers.
If an application requires an explicit DNS server address, use `127.0.0.11`.

> [!NOTE]
>
> When you configure multiple DNS servers for a container on the default
> `bridge` network, the container's resolver library determines how it queries
> them. Some resolvers query the servers in order. Others query them in parallel
> and use the first response received, even if that response is `NXDOMAIN`.
> On a custom network, Docker's embedded DNS server queries upstream servers in
> order and stops after a successful response or an `NXDOMAIN` response.

You can configure DNS resolution on a per-container basis, using flags for the
`docker run` or `docker create` command used to start the container.
The following table describes the available `docker run` flags related to DNS
configuration.

| Flag           | Description                                                                                                                                                                                                                                           |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--dns`        | The IP address of a DNS server. To specify multiple DNS servers, use multiple `--dns` flags. DNS requests will be forwarded from the container's network namespace so, for example, `--dns=127.0.0.1` refers to the container's own loopback address. |
| `--dns-search` | A DNS search domain to search non-fully qualified hostnames. To specify multiple DNS search prefixes, use multiple `--dns-search` flags.                                                                                                              |
| `--dns-opt`    | A key-value pair representing a DNS option and its value. See your operating system's documentation for `resolv.conf` for valid options.                                                                                                              |
| `--hostname`   | The hostname a container uses for itself. Defaults to the container's ID if not specified.                                                                                                                                                            |

### Custom hosts

Your container will have lines in `/etc/hosts` which define the hostname of the
container itself, as well as `localhost` and a few other common things. Custom
hosts, defined in `/etc/hosts` on the host machine, aren't inherited by
containers. To pass additional hosts into a container, refer to [add entries to
container hosts file](/reference/cli/docker/container/run/#add-host) in the
`docker run` reference documentation.

## Container networks

In addition to user-defined networks, you can attach a container to another
container's networking stack directly, using the `--network
container:<name|id>` flag format.

The following flags aren't supported for containers using the `container:`
networking mode:

- `--add-host`
- `--hostname`
- `--dns`
- `--dns-search`
- `--dns-option`
- `--mac-address`
- `--publish`
- `--publish-all`
- `--expose`

The following example runs a Redis container, with Redis binding to
127.0.0.1, then running the `redis-cli` command and connecting to the Redis
server over 127.0.0.1.

```console
$ docker run -d --name redis redis --bind 127.0.0.1
$ docker run --rm -it --network container:redis redis redis-cli -h 127.0.0.1
```


---

# Use CA certificates with Docker

*Sección: Engine*

> [!CAUTION]
> Best practices should be followed when using Man-in-the-Middle (MITM) CA
> certificates in production containers. If compromised, attackers could
> intercept sensitive data, spoof a trusted service, or perform
> man-in-the-middle attacks. Consult your security team before you proceed.

If your company uses a proxy that inspects HTTPS traffic, you might need to add
the required root certificates to your host machine and your Docker containers
or images. This is because Docker and its containers, when pulling images or
making network requests, need to trust the proxy’s certificates.

On the host, adding the root certificate ensures that any Docker commands (like
`docker pull`) work without issues. For containers, you'll need to add the root
certificate to the container's trust store either during the build process or
at runtime. This ensures that applications running inside the containers can
communicate through the proxy without encountering security warnings or
connection failures.

## Add CA certificate to the host

The following sections describe how to install CA certificates on your macOS or
Windows host. For Linux, refer to the documentation for your distribution.

### macOS

1. Download the CA certificate for your MITM proxy software.
2. Open the **Keychain Access** app.
3. In Keychain Access, select **System**, then switch to the **Certificates** tab.
4. Drag-and-drop the downloaded certificate into the list of certificates. Enter your password if prompted.
5. Find the newly added certificate, double-click it, and expand the **Trust** section.
6. Set **Always Trust** for the certificate. Enter your password if prompted.
7. Start Docker Desktop and verify that `docker pull` works, assuming Docker Desktop is configured to use the MITM proxy.

### Windows

Choose whether you want to install the certificate using the Microsoft
Management Console (MMC) or your web browser.

{{< tabs >}}
{{< tab name="MMC" >}}

1. Download CA certificate for the MITM proxy software.
2. Open the Microsoft Management Console (`mmc.exe`).
3. Add the **Certificates Snap-In** in the MMC.
   1. Select **File** → **Add/Remove Snap-in**, and then select **Certificates** → **Add >**.
   2. Select **Computer Account** and then **Next**.
   3. Select **Local computer** and then select **Finish**.
4. Import the CA certificate:
   1. From the MMC, expand **Certificates (Local Computer)**.
   2. Expand the **Trusted Root Certification Authorities** section.
   3. Right-click **Certificates** and select **All Tasks** and **Import…**.
   4. Follow the prompts to import your CA certificate.
5. Select **Finish** and then **Close**.
6. Start Docker Desktop and verify that `docker pull` succeeds (assuming Docker Desktop is already configured to use the MITM proxy server).

> [!NOTE]
> Depending on the SDK and/or runtime/framework in use, further steps may be
> required beyond adding the CA certificate to the operating system's trust
> store.

{{< /tab >}}
{{< tab name="Web browser" >}}

1. Download the CA certificate for your MITM proxy software.
2. Open your web browser, go to **Settings** and open **Manage certificates**
3. Select the **Trusted Root Certification Authorities** tab.
4. Select **Import**, then browse for the downloaded CA certificate.
5. Select **Open**, then choose **Place all certificates in the following store**.
6. Ensure **Trusted Root Certification Authorities** is selected and select **Next**.
7. Select **Finish** and then **Close**.
8. Start Docker Desktop and verify that `docker pull` succeeds (assuming Docker Desktop is already configured to use the MITM proxy server).

{{< /tab >}}
{{< /tabs >}}

## Add CA certificates to Linux images and containers

If you need to run containerized workloads that rely on internal or custom
certificates, such as in environments with corporate proxies or secure
services, you must ensure that the containers trust these certificates. Without
adding the necessary CA certificates, applications inside your containers may
encounter failed requests or security warnings when attempting to connect to
HTTPS endpoints.

By [adding CA certificates to images](#add-certificates-to-images) at build
time, you ensure that any containers started from the image will trust the
specified certificates. This is particularly important for applications that
require seamless access to internal APIs, databases, or other services during
production.

In cases where rebuilding the image isn't feasible, you can instead [add
certificates to containers](#add-certificates-to-containers) directly. However,
certificates added at runtime won’t persist if the container is destroyed or
recreated, so this method is typically used for temporary fixes or testing
scenarios.

## Add certificates to images

> [!NOTE]
> The following commands are for an Ubuntu base image. If your build uses a
> different Linux distribution, use equivalent commands for package management
> (`apt-get`, `update-ca-certificates`, and so on).

To add ca certificate to a container image when you're building it, add the
following instructions to your Dockerfile.

```dockerfile
# Install the ca-certificate package
RUN apt-get update && apt-get install -y ca-certificates
# Copy the CA certificate from the context to the build container
COPY your_certificate.crt /usr/local/share/ca-certificates/
# Update the CA certificates in the container
RUN update-ca-certificates
```

### Add certificates to containers

> [!NOTE]
> The following commands are for an Ubuntu-based container. If your container
> uses a different Linux distribution, use equivalent commands for package
> management (`apt-get`, `update-ca-certificates`, and so on).

To add a CA certificate to a running Linux container:

1. Download the CA certificate for your MITM proxy software.
2. If the certificate is in a format other than `.crt`, convert it to `.crt` format:

   ```console {title="Example command"}
   $ openssl x509 -in cacert.der -inform DER -out myca.crt
   ```

3. Copy the certificate into the running container:

    ```console
    $ docker cp myca.crt <containerid>:/tmp
    ```

4. Attach to the container:

    ```console
    $ docker exec -it <containerid> sh
    ```

5. Ensure the `ca-certificates` package is installed (required for updating certificates):

    ```console
    # apt-get update && apt-get install -y ca-certificates
    ```

6. Copy the certificate to the correct location for CA certificates:

    ```console
    # cp /tmp/myca.crt /usr/local/share/ca-certificates/root_cert.crt
    ```

7. Update the CA certificates:

    ```console
    # update-ca-certificates
    ```

    ```plaintext {title="Example output"}
    Updating certificates in /etc/ssl/certs...
    rehash: warning: skipping ca-certificates.crt, it does not contain exactly one certificate or CRL
    1 added, 0 removed; done.
    ```

8. Verify that the container can communicate via the MITM proxy:

    ```console
    # curl https://example.com
    ```

    ```plaintext {title="Example output"}
    <!doctype html>
    <html>
    <head>
        <title>Example Domain</title>
    ...
    ```


---

# Network drivers

*Sección: Engine*

Docker's networking subsystem is pluggable, using drivers. Several drivers
exist by default, and provide core networking functionality:

- `bridge`: The default network driver. If you don't specify a driver, this is
  the type of network you are creating. Bridge networks are commonly used when
  your application runs in a container that needs to communicate with other
  containers on the same host.
  See [Bridge network driver](bridge.md).

- `host`: Remove network isolation between the container and the Docker host,
  and use the host's networking directly.
  See [Host network driver](host.md).

- `overlay`: Overlay networks connect multiple Docker daemons together and
  enable Swarm services and containers to communicate across nodes. This
  strategy removes the need to do OS-level routing.
  See [Overlay network driver](overlay.md).

- `ipvlan`: IPvlan networks give users total control over both IPv4 and IPv6
  addressing. The VLAN driver builds on top of that in giving operators complete
  control of layer 2 VLAN tagging and even IPvlan L3 routing for users
  interested in underlay network integration.
  See [IPvlan network driver](ipvlan.md).

- `macvlan`: Macvlan networks allow you to assign a MAC address to a container,
  making it appear as a physical device on your network. The Docker daemon
  routes traffic to containers by their MAC addresses. Using the `macvlan`
  driver is sometimes the best choice when dealing with legacy applications that
  expect to be directly connected to the physical network, rather than routed
  through the Docker host's network stack.
  See [Macvlan network driver](macvlan.md).

- `none`: Completely isolate a container from the host and other containers.
  `none` is not available for Swarm services.
  See [None network driver](none.md).

- [Network plugins](/engine/extend/plugins_network/): You can install and use
  third-party network plugins with Docker.

### Network driver summary

- The default bridge network is good for running containers that don't require
  special networking capabilities.
- User-defined bridge networks enable containers on the same Docker host to
  communicate with each other. A user-defined network typically defines an
  isolated network for multiple containers belonging to a common project or
  component.
- Host network shares the host's network with the container. When you use this
  driver, the container's network isn't isolated from the host.
- Overlay networks are best when you need containers running on different
  Docker hosts to communicate, or when multiple applications work together
  using Swarm services.
- Macvlan networks are best when you are migrating from a VM setup or need your
  containers to look like physical hosts on your network, each with a unique
  MAC address.
- IPvlan is similar to Macvlan, but doesn't assign unique MAC addresses to
  containers. Consider using IPvlan when there's a restriction on the number of
  MAC addresses that can be assigned to a network interface or port.
- Third-party network plugins allow you to integrate Docker with specialized
  network stacks.

## Next steps

Each driver page includes detailed explanations, configuration options, and
hands-on usage examples to help you work with that driver effectively.


---

# Bridge network driver

*Sección: Engine*

A Docker bridge network has an IPv4 subnet and, optionally, an IPv6 subnet.
Each container connected to the bridge network has a network interface with
addresses in the network's subnets. By default, it:

- Allows unrestricted network access to containers in the network from
  the host, and from other containers connected to the same bridge network.
- Blocks access from containers in other networks and from outside the
  Docker host.
- Uses masquerading to give containers external network access. Devices on
  the host's external networks only see the IP address of the Docker host.
- Supports port publishing, where network traffic is forwarded between
  container ports and ports on host IP addresses. The published ports
  can be accessed from outside the Docker host, on its IP addresses.

In terms of Docker, a bridge network uses a software bridge which lets
containers connected to the same bridge network communicate, while providing
isolation from containers that aren't connected to that bridge network. By
default, the Docker bridge driver automatically installs rules in the host
machine so that containers connected to different bridge networks can only
communicate with each other using published ports.

Bridge networks apply to containers running on the same Docker daemon host.
For communication among containers running on different Docker daemon hosts, you
can either manage routing at the OS level, or you can use an
[overlay network](overlay.md).

When you start Docker, a [default bridge network](#use-the-default-bridge-network) (also
called `bridge`) is created automatically, and newly-started containers connect
to it unless otherwise specified. You can also create user-defined custom bridge
networks. **User-defined bridge networks are superior to the default `bridge`
network.**

## Differences between user-defined bridges and the default bridge

- **User-defined bridges provide automatic DNS resolution between containers**.

  Containers on the default bridge network can only access each other by IP
  addresses, unless you use the [`--link` option](../links.md), which is
  considered legacy. On a user-defined bridge network, containers can resolve
  each other by name or alias.

  Imagine an application with a web front-end and a database back-end. If you call
  your containers `web` and `db`, the web container can connect to the db container
  at `db`, no matter which Docker host the application stack is running on.

  If you run the same application stack on the default bridge network, you need
  to manually create links between the containers (using the legacy `--link`
  flag). These links need to be created in both directions, so you can see this
  gets complex with more than two containers which need to communicate.
  Alternatively, you can manipulate the `/etc/hosts` files within the containers,
  but this creates problems that are difficult to debug.

- **User-defined bridges provide better isolation**.

  All containers without a `--network` specified, are attached to the default bridge network. This can be a risk, as unrelated stacks/services/containers are then able to communicate.

  Using a user-defined network provides a scoped network in which only containers attached to that network are able to communicate.

- **Containers can be attached and detached from user-defined networks on the fly**.

  During a container's lifetime, you can connect or disconnect it from
  user-defined networks on the fly. To remove a container from the default
  bridge network, you need to stop the container and recreate it with different
  network options.

- **Each user-defined network creates a configurable bridge**.

  If your containers use the default bridge network, you can configure it, but
  all the containers use the same settings, such as MTU and `iptables` rules.
  In addition, configuring the default bridge network happens outside of Docker
  itself, and requires a restart of Docker.

  User-defined bridge networks are created and configured using
  `docker network create`. If different groups of applications have different
  network requirements, you can configure each user-defined bridge separately,
  as you create it.

- **Linked containers on the default bridge network share environment variables**.

  Originally, the only way to share environment variables between two containers
  was to link them using the [`--link` flag](../links.md). This type of
  variable sharing isn't possible with user-defined networks. However, there
  are superior ways to share environment variables. A few ideas:
  - Multiple containers can mount a file or directory containing the shared
    information, using a Docker volume.

  - Multiple containers can be started together using `docker-compose` and the
    compose file can define the shared variables.

  - You can use swarm services instead of standalone containers, and take
    advantage of shared [secrets](../../swarm/secrets.md) and
    [configs](../../swarm/configs.md).

Containers connected to the same user-defined bridge network effectively expose all ports
to each other. For a port to be accessible to containers or non-Docker hosts on
different networks, that port must be _published_ using the `-p` or `--publish`
flag.

## Options

The following table describes the driver-specific options that you can pass to
`--opt` when creating a custom network using the `bridge` driver.

| Option                                                                                          | Default                     | Description                                                                                                          |
| ----------------------------------------------------------------------------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `com.docker.network.bridge.name`                                                                |                             | Interface name to use when creating the Linux bridge.                                                                |
| `com.docker.network.bridge.enable_ip_masquerade`                                                | `true`                      | Enable IP masquerading.                                                                                              |
| `com.docker.network.host_ipv4`<br/>`com.docker.network.host_ipv6`                               |                             | Address to use for source NAT. See [Port publishing](../port-publishing.md#masquerade-or-snat-for-outgoing-packets). |
| `com.docker.network.bridge.gateway_mode_ipv4`<br/>`com.docker.network.bridge.gateway_mode_ipv6` | `nat`                       | Control external connectivity. See [Port publishing](../port-publishing.md#gateway-modes).                           |
| `com.docker.network.bridge.enable_icc`                                                          | `true`                      | Enable or Disable inter-container connectivity.                                                                      |
| `com.docker.network.bridge.host_binding_ipv4`                                                   | all IPv4 and IPv6 addresses | Default IP when binding container ports.                                                                             |
| `com.docker.network.driver.mtu`                                                                 | `0` (no limit)              | Set the containers network Maximum Transmission Unit (MTU).                                                          |
| `com.docker.network.container_iface_prefix`                                                     | `eth`                       | Set a custom prefix for container interfaces.                                                                        |
| `com.docker.network.bridge.inhibit_ipv4`                                                        | `false`                     | Prevent Docker from [assigning an IP address](#skip-bridge-ip-address-configuration) to the bridge.                  |

Some of these options are also available as flags to the `dockerd` CLI, and you
can use them to configure the default `docker0` bridge when starting the Docker
daemon. The following table shows which options have equivalent flags in the
`dockerd` CLI.

| Option                                           | Flag        |
| ------------------------------------------------ | ----------- |
| `com.docker.network.bridge.name`                 | -           |
| `com.docker.network.bridge.enable_ip_masquerade` | `--ip-masq` |
| `com.docker.network.bridge.enable_icc`           | `--icc`     |
| `com.docker.network.bridge.host_binding_ipv4`    | `--ip`      |
| `com.docker.network.driver.mtu`                  | `--mtu`     |
| `com.docker.network.container_iface_prefix`      | -           |

The Docker daemon supports a `--bridge` flag, which you can use to define
your own `docker0` bridge. Use this option if you want to run multiple daemon
instances on the same host. For details, see
[Run multiple daemons](/reference/cli/dockerd.md#run-multiple-daemons).

### Default host binding address

When no host address is given in port publishing options like `-p 80`
or `-p 8080:80`, the default is to make the container's port 80 available on all
host addresses, IPv4 and IPv6.

The bridge network driver option `com.docker.network.bridge.host_binding_ipv4`
can be used to modify the default address for published ports.

Despite the option's name, it is possible to specify an IPv6 address.

When the default binding address is an address assigned to a specific interface,
the container's port will only be accessible via that address.

Setting the default binding address to `::` means published ports will only be
available on the host's IPv6 addresses. However, setting it to `0.0.0.0` means it
will be available on the host's IPv4 and IPv6 addresses.

To restrict a published port to IPv4 only, the address must be included in the
container's publishing options. For example, `-p 0.0.0.0:8080:80`.

## Manage a user-defined bridge

Use the `docker network create` command to create a user-defined bridge
network.

```console
$ docker network create my-net
```

You can specify the subnet, the IP address range, the gateway, and other
options. See the
[docker network create](/reference/cli/docker/network/create/#specify-advanced-options)
reference or the output of `docker network create --help` for details.

Use the `docker network rm` command to remove a user-defined bridge
network. If containers are currently connected to the network,
[disconnect them](#disconnect-a-container-from-a-user-defined-bridge)
first.

```console
$ docker network rm my-net
```

> **What's really happening?**
>
> When you create or remove a user-defined bridge or connect or disconnect a
> container from a user-defined bridge, Docker uses tools specific to the
> operating system to manage the underlying network infrastructure (such as adding
> or removing bridge devices or configuring `iptables` rules on Linux). These
> details should be considered implementation details. Let Docker manage your
> user-defined networks for you.

## Connect a container to a user-defined bridge

When you create a new container, you can specify one or more `--network` flags.
This example connects an Nginx container to the `my-net` network. It also
publishes port 80 in the container to port 8080 on the Docker host, so external
clients can access that port. Any other container connected to the `my-net`
network has access to all ports on the `my-nginx` container, and vice versa.

```console
$ docker create --name my-nginx \
  --network my-net \
  --publish 8080:80 \
  nginx:latest
```

To connect a **running** container to an existing user-defined bridge, use the
`docker network connect` command. The following command connects an already-running
`my-nginx` container to an already-existing `my-net` network:

```console
$ docker network connect my-net my-nginx
```

## Disconnect a container from a user-defined bridge

To disconnect a running container from a user-defined bridge, use the
`docker network disconnect` command. The following command disconnects
the `my-nginx` container from the `my-net` network.

```console
$ docker network disconnect my-net my-nginx
```

## Use IPv6 in a user-defined bridge network

When you create your network, you can specify the `--ipv6` flag to enable IPv6.

```console
$ docker network create --ipv6 --subnet 2001:db8:1234::/64 my-net
```

If you do not provide a `--subnet` option, a Unique Local Address (ULA) prefix
will be chosen automatically.

## IPv6-only bridge networks

To skip IPv4 address configuration on the bridge and in its containers, create
the network with option `--ipv4=false`, and enable IPv6 using `--ipv6`.

```console
$ docker network create --ipv6 --ipv4=false v6net
```

IPv4 address configuration cannot be disabled in the default bridge network.

## Use the default bridge network

The default `bridge` network is considered a legacy detail of Docker and is not
recommended for production use. Configuring it is a manual operation, and it has
[technical shortcomings](#differences-between-user-defined-bridges-and-the-default-bridge).

### Connect a container to the default bridge network

If you do not specify a network using the `--network` flag, and you do specify a
network driver, your container is connected to the default `bridge` network by
default. Containers connected to the default `bridge` network can communicate,
but only by IP address, unless they're linked using the
[legacy `--link` flag](../links.md).

### Configure the default bridge network

To configure the default `bridge` network, you specify options in `daemon.json`.
Here is an example `daemon.json` with several options specified. Only specify
the settings you need to customize.

```json
{
  "bip": "192.168.1.1/24",
  "fixed-cidr": "192.168.1.0/25",
  "mtu": 1500,
  "default-gateway": "192.168.1.254",
  "dns": ["10.20.1.2", "10.20.1.3"]
}
```

In this example:

- The bridge's address is "192.168.1.1/24" (from `bip`).
- The bridge network's subnet is "192.168.1.0/24" (from `bip`).
- Container addresses will be allocated from "192.168.1.0/25" (from `fixed-cidr`).

### Use IPv6 with the default bridge network

IPv6 can be enabled for the default bridge using the following options in
`daemon.json`, or their command line equivalents.

These three options only affect the default bridge, they are not used by
user-defined networks. The addresses in below are examples from the
IPv6 documentation range.

- Option `ipv6` is required.
- Option `bip6` is optional, it specifies the address of the default bridge, which
  will be used as the default gateway by containers. It also specifies the subnet
  for the bridge network.
- Option `fixed-cidr-v6` is optional, it specifies the address range Docker may
  automatically allocate to containers.
  - The prefix should normally be `/64` or shorter.
  - For experimentation on a local network, it is better to use a Unique Local
    Address (ULA) prefix (matching `fd00::/8`) than a Link Local prefix (matching
    `fe80::/10`).
- Option `default-gateway-v6` is optional. If unspecified, the default is the first
  address in the `fixed-cidr-v6` subnet.

```json
{
  "ipv6": true,
  "bip6": "2001:db8::1111/64",
  "fixed-cidr-v6": "2001:db8::/64",
  "default-gateway-v6": "2001:db8:abcd::89"
}
```

If no `bip6` is specified, `fixed-cidr-v6` defines the subnet for the bridge
network. If no `bip6` or `fixed-cidr-v6` is specified, a ULA prefix will be
chosen.

Restart Docker for changes to take effect.

## Connection limit for bridge networks

Due to limitations set by the Linux kernel, bridge networks become unstable and
inter-container communications may break when 1000 containers or more connect
to a single network.

For more information about this limitation, see
[moby/moby#44973](https://github.com/moby/moby/issues/44973#issuecomment-1543747718).

## Skip Bridge IP address configuration

The bridge is normally assigned the network's `--gateway` address, which is
used as the default route from the bridge network to other networks.

The `com.docker.network.bridge.inhibit_ipv4` option lets you create a network
without the IPv4 gateway address being assigned to the bridge. This is useful
if you want to configure the gateway IP address for the bridge manually. For
instance if you add a physical interface to your bridge, and need it to have
the gateway address.

With this configuration, north-south traffic (to and from the bridge network)
won't work unless you've manually configured the gateway address on the bridge,
or a device attached to it.

This option can only be used with user-defined bridge networks.

## Usage examples

This section provides hands-on examples for working with bridge networks.

### Use the default bridge network

This example shows how the default `bridge` network works. You start two
`alpine` containers on the default bridge and test how they communicate.

> [!NOTE]
> The default `bridge` network is not recommended for production. Use
> user-defined bridge networks instead.

1. List current networks:

   ```console
   $ docker network ls

   NETWORK ID          NAME                DRIVER              SCOPE
   17e324f45964        bridge              bridge              local
   6ed54d316334        host                host                local
   7092879f2cc8        none                null                local
   ```

   The default `bridge` network is listed, along with `host` and `none`.

2. Start two `alpine` containers running `ash`. The `-dit` flags mean detached,
   interactive, and with a TTY. Since you haven't specified a `--network` flag,
   the containers connect to the default `bridge` network.

   ```console
   $ docker run -dit --name alpine1 alpine ash
   $ docker run -dit --name alpine2 alpine ash
   ```

   Verify both containers are running:

   ```console
   $ docker container ls

   CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
   602dbf1edc81        alpine              "ash"               4 seconds ago       Up 3 seconds                            alpine2
   da33b7aa74b0        alpine              "ash"               17 seconds ago      Up 16 seconds                           alpine1
   ```

3. Inspect the `bridge` network to see connected containers:

   ```console
   $ docker network inspect bridge
   ```

   The output shows both containers connected, with their assigned IP addresses
   (`172.17.0.2` for `alpine1` and `172.17.0.3` for `alpine2`).

4. Connect to `alpine1`:

   ```console
   $ docker attach alpine1

   / #
   ```

   Show the network interfaces for `alpine1` from within the container:

   ```console
   # ip addr show

   1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
       link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
       inet 127.0.0.1/8 scope host lo
          valid_lft forever preferred_lft forever
       inet6 ::1/128 scope host
          valid_lft forever preferred_lft forever
   27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
       link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
       inet 172.17.0.2/16 scope global eth0
          valid_lft forever preferred_lft forever
   ```

   In this example, the `eth0` interface has the IP address `172.17.0.2`.

5. From within `alpine1`, verify you can connect to the internet:

   ```console
   # ping -c 2 google.com

   PING google.com (172.217.3.174): 56 data bytes
   64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.841 ms
   64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.897 ms

   --- google.com ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 9.841/9.869/9.897 ms
   ```

6. Ping the second container by its IP address:

   ```console
   # ping -c 2 172.17.0.3

   PING 172.17.0.3 (172.17.0.3): 56 data bytes
   64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
   64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms

   --- 172.17.0.3 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.086/0.090/0.094 ms
   ```

   This succeeds. Now try pinging by container name:

   ```console
   # ping -c 2 alpine2

   ping: bad address 'alpine2'
   ```

   On the default bridge network, containers can't resolve each other by name.

7. Detach from `alpine1` without stopping it using `CTRL+p CTRL+q`.

8. Clean up: stop the containers and remove them.

   ```console
   $ docker container stop alpine1 alpine2
   $ docker container rm alpine1 alpine2
   ```

   Stopped containers lose their IP addresses.

### Use user-defined bridge networks

This example shows how user-defined bridge networks provide better isolation
and automatic DNS resolution between containers.

1. Create the `alpine-net` network:

   ```console
   $ docker network create --driver bridge alpine-net
   ```

2. List Docker's networks:

   ```console
   $ docker network ls

   NETWORK ID          NAME                DRIVER              SCOPE
   e9261a8c9a19        alpine-net          bridge              local
   17e324f45964        bridge              bridge              local
   6ed54d316334        host                host                local
   7092879f2cc8        none                null                local
   ```

   Inspect the `alpine-net` network:

   ```console
   $ docker network inspect alpine-net
   ```

   This shows the network's gateway (for example, `172.18.0.1`) and that no
   containers are connected yet.

3. Create four containers. Three connect to `alpine-net`, and one connects to
   the default `bridge`. Then connect one container to both networks:

   ```console
   $ docker run -dit --name alpine1 --network alpine-net alpine ash
   $ docker run -dit --name alpine2 --network alpine-net alpine ash
   $ docker run -dit --name alpine3 alpine ash
   $ docker run -dit --name alpine4 --network alpine-net alpine ash
   $ docker network connect bridge alpine4
   ```

   Verify all containers are running:

   ```console
   $ docker container ls

   CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
   156849ccd902        alpine              "ash"               41 seconds ago       Up 41 seconds                           alpine4
   fa1340b8d83e        alpine              "ash"               51 seconds ago       Up 51 seconds                           alpine3
   a535d969081e        alpine              "ash"               About a minute ago   Up About a minute                       alpine2
   0a02c449a6e9        alpine              "ash"               About a minute ago   Up About a minute                       alpine1
   ```

4. Inspect both networks again to see which containers are connected:

   ```console
   $ docker network inspect bridge
   ```

   Containers `alpine3` and `alpine4` are connected to the `bridge` network.

   ```console
   $ docker network inspect alpine-net
   ```

   Containers `alpine1`, `alpine2`, and `alpine4` are connected to
   `alpine-net`.

5. On user-defined networks, containers can resolve each other by name. Connect
   to `alpine1` and test:

   > [!NOTE]
   > Automatic service discovery only resolves custom container names, not
   > default automatically generated names.

   ```console
   $ docker container attach alpine1

   # ping -c 2 alpine2

   PING alpine2 (172.18.0.3): 56 data bytes
   64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.085 ms
   64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.090 ms

   --- alpine2 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.085/0.087/0.090 ms

   # ping -c 2 alpine4

   PING alpine4 (172.18.0.4): 56 data bytes
   64 bytes from 172.18.0.4: seq=0 ttl=64 time=0.076 ms
   64 bytes from 172.18.0.4: seq=1 ttl=64 time=0.091 ms

   --- alpine4 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.076/0.083/0.091 ms
   ```

6. From `alpine1`, you can't connect to `alpine3` because it's on a different
   network:

   ```console
   # ping -c 2 alpine3

   ping: bad address 'alpine3'
   ```

   You also can't connect by IP address. If `alpine3`'s IP is `172.17.0.2`:

   ```console
   # ping -c 2 172.17.0.2

   PING 172.17.0.2 (172.17.0.2): 56 data bytes

   --- 172.17.0.2 ping statistics ---
   2 packets transmitted, 0 packets received, 100% packet loss
   ```

   Detach from `alpine1` using `CTRL+p CTRL+q`.

7. Since `alpine4` is connected to both networks, it can reach all containers.
   However, you need to use `alpine3`'s IP address:

   ```console
   $ docker container attach alpine4

   # ping -c 2 alpine1

   PING alpine1 (172.18.0.2): 56 data bytes
   64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.074 ms
   64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.082 ms

   --- alpine1 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.074/0.078/0.082 ms

   # ping -c 2 alpine2

   PING alpine2 (172.18.0.3): 56 data bytes
   64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.075 ms
   64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.080 ms

   --- alpine2 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.075/0.077/0.080 ms

   # ping -c 2 alpine3
   ping: bad address 'alpine3'

   # ping -c 2 172.17.0.2

   PING 172.17.0.2 (172.17.0.2): 56 data bytes
   64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.089 ms
   64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.075 ms

   --- 172.17.0.2 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.075/0.082/0.089 ms
   ```

8. Verify all containers can connect to the internet:

   ```console
   # ping -c 2 google.com

   PING google.com (172.217.3.174): 56 data bytes
   64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.778 ms
   64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.634 ms

   --- google.com ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 9.634/9.706/9.778 ms
   ```

   Detach with `CTRL+p CTRL+q` and repeat for `alpine3` and `alpine1` if
   desired.

9. Clean up:

   ```console
   $ docker container stop alpine1 alpine2 alpine3 alpine4
   $ docker container rm alpine1 alpine2 alpine3 alpine4
   $ docker network rm alpine-net
   ```

## Next steps

- Learn about [networking from the container's point of view](../index.md)
- Learn about [overlay networks](overlay.md)
- Learn about [Macvlan networks](macvlan.md)


---

# Host network driver

*Sección: Engine*

If you use the `host` network mode for a container, that container's network
stack isn't isolated from the Docker host (the container shares the host's
networking namespace), and the container doesn't get its own IP-address allocated.
For instance, if you run a container which binds to port 80 and you use `host`
networking, the container's application is available on port 80 on the host's IP
address.

> [!NOTE]
>
> Given that the container does not have its own IP-address when using
> `host` mode networking, [port mapping](../port-publishing.md) doesn't
> take effect, and the `-p`, `--publish`, `-P`, and `--publish-all` options are
> ignored, producing a warning instead:
>
> ```console
> WARNING: Published ports are discarded when using host network mode
> ```

Host mode networking can be useful for the following use cases:

- To optimize performance
- In situations where a container needs to handle a large range of ports

This is because it doesn't require network address translation (NAT), and no "userland-proxy" is created for each port.

## Platform support

The host networking driver is supported on:

- Docker Engine on Linux
- Docker Desktop version 4.34 and later (requires enabling the feature in
  Settings)

> [!NOTE]
> For Docker Desktop users, see the [Docker Desktop section](#docker-desktop)
> below for setup instructions.

You can also use a `host` network for a swarm service, by passing `--network host`
to the `docker service create` command. In this case, control traffic (traffic
related to managing the swarm and the service) is still sent across an overlay
network, but the individual swarm service containers send data using the Docker
daemon's host network and ports. This creates some extra limitations. For instance,
if a service container binds to port 80, only one service container can run on a
given swarm node.

## Docker Desktop

Host networking is supported on Docker Desktop version 4.34 and later.
To enable this feature:

1. Sign in to your Docker account in Docker Desktop.
2. Navigate to **Settings**.
3. Under the **Resources** tab, select **Network**.
4. Check the **Enable host networking** option.
5. Select **Apply and restart**.

This feature works in both directions. This means you can
access a server that is running in a container from your host and you can access
servers running on your host from any container that is started with host
networking enabled. TCP as well as UDP are supported as communication protocols.

### Examples

The following command starts netcat in a container that listens on port `8000`:

```console
$ docker run --rm -it --net=host nicolaka/netshoot nc -lkv 0.0.0.0 8000
```

Port `8000` will then be available on the host and you can connect to it with the following
command from another terminal:

```console
$ nc localhost 8000
```

What you type in here will then appear on the terminal where the container is
running.

To access a service running on the host from the container, you can start a container with
host networking enabled with this command:

```console
$ docker run --rm -it --net=host nicolaka/netshoot
```

If you then want to access a service on your host from the container (in this
example a web server running on port `80`), you can do it like this:

```console
$ nc localhost 80
```

### Limitations

- Processes inside the container cannot bind to the IP addresses of the host
  because the container has no direct access to the interfaces of the host.
- The host network feature of Docker Desktop works on layer 4. This means that
  unlike with Docker on Linux, network protocols that operate below TCP or UDP are
  not supported.
- This feature doesn't work with Enhanced Container Isolation enabled, since
  isolating your containers from the host and allowing them access to the host
  network contradict each other.
- Only Linux containers are supported. Host networking does not work with
  Windows containers.

## Usage example

This example shows how to start an Nginx container that binds directly to port
80 on the Docker host. From a networking perspective, this provides the same
level of isolation as if Nginx were running directly on the host, but the
container remains isolated in all other aspects (storage, process namespace,
user namespace).

### Prerequisites

- Port 80 must be available on the Docker host. To make Nginx listen on a
  different port, see the [Nginx image documentation](https://hub.docker.com/_/nginx/).
- The host networking driver only works on Linux hosts, and as an opt-in
  feature in Docker Desktop version 4.34 and later.

### Steps

1. Create and start the container as a detached process. The `--rm` option
   removes the container when it exits. The `-d` flag starts it in the
   background:

   ```console
   $ docker run --rm -d --network host --name my_nginx nginx
   ```

2. Access Nginx by browsing to [http://localhost:80/](http://localhost:80/).

3. Examine your network stack:

   Check all network interfaces and verify that no new interface was created:

   ```console
   $ ip addr show
   ```

   Verify which process is bound to port 80 using `netstat`. You need `sudo`
   because the process is owned by the Docker daemon user:

   ```console
   $ sudo netstat -tulpn | grep :80
   ```

4. Stop the container. It's removed automatically because of the `--rm` option:

   ```console
   $ docker container stop my_nginx
   ```

## Next steps

- Learn about [networking from the container's point of view](../index.md)
- Learn about [bridge networks](bridge.md)
- Learn about [overlay networks](overlay.md)
- Learn about [Macvlan networks](macvlan.md)


---

# IPvlan network driver

*Sección: Engine*

The IPvlan driver gives users total control over both IPv4 and IPv6 addressing.
The VLAN driver builds on top of that in giving operators complete control of
layer 2 VLAN tagging and even IPvlan L3 routing for users interested in underlay
network integration. For overlay deployments that abstract away physical constraints
see the [multi-host overlay](overlay.md) driver.

IPvlan is a new twist on the tried and true network virtualization technique.
The Linux implementations are extremely lightweight because rather than using
the traditional Linux bridge for isolation, they are associated to a Linux
Ethernet interface or sub-interface to enforce separation between networks and
connectivity to the physical network.

IPvlan offers a number of unique features and plenty of room for further
innovations with the various modes. Two high level advantages of these approaches
are, the positive performance implications of bypassing the Linux bridge and the
simplicity of having fewer moving parts. Removing the bridge that traditionally
resides in between the Docker host NIC and container interface leaves a simple
setup consisting of container interfaces, attached directly to the Docker host
interface. This result is easy to access for external facing services as there
is no need for port mappings in these scenarios.

## Options

The following table describes the driver-specific options that you can pass to
`--opt` when creating a network using the `ipvlan` driver.

| Option        | Default  | Description                                                           |
| ------------- | -------- | --------------------------------------------------------------------- |
| `ipvlan_mode` | `l2`     | Sets the IPvlan operating mode. Can be one of: `l2`, `l3`, `l3s`      |
| `ipvlan_flag` | `bridge` | Sets the IPvlan mode flag. Can be one of: `bridge`, `private`, `vepa` |
| `parent`      |          | Specifies the parent interface to use.                                |

## Examples

### Prerequisites

- The examples on this page are all single host.
- All examples can be performed on a single host running Docker. Any
  example using a sub-interface like `eth0.10` can be replaced with `eth0` or
  any other valid parent interface on the Docker host. Sub-interfaces with a `.`
  are created on the fly. `-o parent` interfaces can also be left out of the
  `docker network create` all together and the driver will create a `dummy`
  interface that will enable local host connectivity to perform the examples.
- Kernel requirements:
  - IPvlan Linux kernel v4.2+ (support for earlier kernels exists but is buggy). To check your current kernel version, use `uname -r`

### IPvlan L2 mode example usage

An example of the IPvlan `L2` mode topology is shown in the following image.
The driver is specified with `-d driver_name` option. In this case `-d ipvlan`.

![Simple IPvlan L2 Mode Example](images/ipvlan_l2_simple.png)

The parent interface in the next example `-o parent=eth0` is configured as follows:

```console
$ ip addr show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
```

Use the network from the host's interface as the `--subnet` in the
`docker network create`. The container will be attached to the same network as
the host interface as set via the `-o parent=` option.

Create the IPvlan network and run a container attaching to it:

```console
# IPvlan  (-o ipvlan_mode= Defaults to L2 mode if not specified)
$ docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    --gateway=192.168.1.1 \
    -o ipvlan_mode=l2 \
    -o parent=eth0 db_net

# Start a container on the db_net network
$ docker run --net=db_net -it --rm alpine /bin/sh

# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.
```

The default mode for IPvlan is `l2`. If `-o ipvlan_mode=` is left unspecified,
the default mode will be used. Similarly, if the `--gateway` is left empty, the
first usable address on the network will be set as the gateway. For example, if
the subnet provided in the network create is `--subnet=192.168.1.0/24` then the
gateway the container receives is `192.168.1.1`.

To help understand how this mode interacts with other hosts, the following
figure shows the same layer 2 segment between two Docker hosts that applies to
and IPvlan L2 mode.

![Multiple IPvlan hosts](images/macvlan-bridge-ipvlan-l2.webp?w=700)

The following will create the exact same network as the network `db_net` created
earlier, with the driver defaults for `--gateway=192.168.1.1` and `-o ipvlan_mode=l2`.

```console
# IPvlan  (-o ipvlan_mode= Defaults to L2 mode if not specified)
$ docker network create -d ipvlan \
    --subnet=192.168.1.0/24 \
    -o parent=eth0 db_net_ipv

# Start a container with an explicit name in daemon mode
$ docker run --net=db_net_ipv --name=ipv1 -itd alpine /bin/sh

# Start a second container and ping using the container name
# to see the docker included name resolution functionality
$ docker run --net=db_net_ipv --name=ipv2 -it --rm alpine /bin/sh
$ ping -c 4 ipv1

# NOTE: the containers can NOT ping the underlying host interfaces as
# they are intentionally filtered by Linux for additional isolation.
```

The drivers also support the `--internal` flag that will completely isolate
containers on a network from any communications external to that network. Since
network isolation is tightly coupled to the network's parent interface the result
of leaving the `-o parent=` option off of a `docker network create` is the exact
same as the `--internal` option. If the parent interface is not specified or the
`--internal` flag is used, a netlink type `dummy` parent interface is created
for the user and used as the parent interface effectively isolating the network
completely.

The following two `docker network create` examples result in identical networks
that you can attach container to:

```console
# Empty '-o parent=' creates an isolated network
$ docker network create -d ipvlan \
    --subnet=192.168.10.0/24 isolated1

# Explicit '--internal' flag is the same:
$ docker network create -d ipvlan \
    --subnet=192.168.11.0/24 --internal isolated2

# Even the '--subnet=' can be left empty and the default
# IPAM subnet of 172.18.0.0/16 will be assigned
$ docker network create -d ipvlan isolated3

$ docker run --net=isolated1 --name=cid1 -it --rm alpine /bin/sh
$ docker run --net=isolated2 --name=cid2 -it --rm alpine /bin/sh
$ docker run --net=isolated3 --name=cid3 -it --rm alpine /bin/sh

# To attach to any use `docker exec` and start a shell
$ docker exec -it cid1 /bin/sh
$ docker exec -it cid2 /bin/sh
$ docker exec -it cid3 /bin/sh
```

### IPvlan 802.1Q trunk L2 mode example usage

Architecturally, IPvlan L2 mode trunking is the same as Macvlan with regard to
gateways and L2 path isolation. There are nuances that can be advantageous for
CAM table pressure in ToR switches, one MAC per port and MAC exhaustion on a
host's parent NIC to name a few. The 802.1Q trunk scenario looks the same. Both
modes adhere to tagging standards and have seamless integration with the physical
network for underlay integration and hardware vendor plugin integrations.

Hosts on the same VLAN are typically on the same subnet and almost always are
grouped together based on their security policy. In most scenarios, a multi-tier
application is tiered into different subnets because the security profile of each
process requires some form of isolation. For example, hosting your credit card
processing on the same virtual network as the frontend webserver would be a
regulatory compliance issue, along with circumventing the long standing best
practice of layered defense in depth architectures. VLANs or the equivocal VNI
(Virtual Network Identifier) when using the Overlay driver, are the first step
in isolating tenant traffic.

![Docker VLANs in-depth](images/vlans-deeper-look.webp)

The Linux sub-interface tagged with a VLAN can either already exist or will be
created when you call a `docker network create`. `docker network rm` will delete
the sub-interface. Parent interfaces such as `eth0` are not deleted, only
sub-interfaces with a netlink parent index > 0.

For the driver to add/delete the VLAN sub-interfaces the format needs to be
`interface_name.vlan_tag`. Other sub-interface naming can be used as the
specified parent, but the link will not be deleted automatically when
`docker network rm` is invoked.

The option to use either existing parent VLAN sub-interfaces or let Docker manage
them enables the user to either completely manage the Linux interfaces and
networking or let Docker create and delete the VLAN parent sub-interfaces
(netlink `ip link`) with no effort from the user.

For example: use `eth0.10` to denote a sub-interface of `eth0` tagged with the
VLAN id of `10`. The equivalent `ip link` command would be
`ip link add link eth0 name eth0.10 type vlan id 10`.

The example creates the VLAN tagged networks and then starts two containers to
test connectivity between containers. Different VLANs cannot ping one another
without a router routing between the two networks. The default namespace is not
reachable per IPvlan design in order to isolate container namespaces from the
underlying host.

#### VLAN ID 20

In the first network tagged and isolated by the Docker host, `eth0.20` is the
parent interface tagged with VLAN id `20` specified with `-o parent=eth0.20`.
Other naming formats can be used, but the links need to be added and deleted
manually using `ip link` or Linux configuration files. As long as the `-o parent`
exists, anything can be used if it is compliant with Linux netlink.

```console
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
$ docker network create -d ipvlan \
    --subnet=192.168.20.0/24 \
    --gateway=192.168.20.1 \
    -o parent=eth0.20 ipvlan20

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan20 -it --name ivlan_test1 --rm alpine /bin/sh
$ docker run --net=ipvlan20 -it --name ivlan_test2 --rm alpine /bin/sh
```

#### VLAN ID 30

In the second network, tagged and isolated by the Docker host, `eth0.30` is the
parent interface tagged with VLAN id `30` specified with `-o parent=eth0.30`. The
`ipvlan_mode=` defaults to l2 mode `ipvlan_mode=l2`. It can also be explicitly
set with the same result as shown in the next example.

```console
# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged.
$ docker network create -d ipvlan \
    --subnet=192.168.30.0/24 \
    --gateway=192.168.30.1 \
    -o parent=eth0.30 \
    -o ipvlan_mode=l2 ipvlan30

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan30 -it --name ivlan_test3 --rm alpine /bin/sh
$ docker run --net=ipvlan30 -it --name ivlan_test4 --rm alpine /bin/sh
```

The gateway is set inside of the container as the default gateway. That gateway
would typically be an external router on the network.

```console
$$ ip route
  default via 192.168.30.1 dev eth0
  192.168.30.0/24 dev eth0  src 192.168.30.2
```

Example: Multi-Subnet IPvlan L2 Mode starting two containers on the same subnet
and pinging one another. In order for the `192.168.114.0/24` to reach
`192.168.116.0/24` it requires an external router in L2 mode. L3 mode can route
between subnets that share a common `-o parent=`.

Secondary addresses on network routers are common as an address space becomes
exhausted to add another secondary to an L3 VLAN interface or commonly referred
to as a "switched virtual interface" (SVI).

```console
$ docker network create -d ipvlan \
    --subnet=192.168.114.0/24 --subnet=192.168.116.0/24 \
    --gateway=192.168.114.254 --gateway=192.168.116.254 \
    -o parent=eth0.114 \
    -o ipvlan_mode=l2 ipvlan114

$ docker run --net=ipvlan114 --ip=192.168.114.10 -it --rm alpine /bin/sh
$ docker run --net=ipvlan114 --ip=192.168.114.11 -it --rm alpine /bin/sh
```

A key takeaway is, operators have the ability to map their physical network into
their virtual network for integrating containers into their environment with no
operational overhauls required. NetOps drops an 802.1Q trunk into the
Docker host. That virtual link would be the `-o parent=` passed in the network
creation. For untagged (non-VLAN) links, it is as simple as `-o parent=eth0` or
for 802.1Q trunks with VLAN IDs each network gets mapped to the corresponding
VLAN/Subnet from the network.

An example being, NetOps provides VLAN ID and the associated subnets for VLANs
being passed on the Ethernet link to the Docker host server. Those values are
plugged into the `docker network create` commands when provisioning the
Docker networks. These are persistent configurations that are applied every time
Docker Engine starts which alleviates having to manage often complex
configuration files. The network interfaces can also be managed manually by
being pre-created and Docker networking will never modify them, and use them
as parent interfaces. Example mappings from NetOps to Docker network commands
are as follows:

- VLAN: 10, Subnet: 172.16.80.0/24, Gateway: 172.16.80.1
  - `--subnet=172.16.80.0/24 --gateway=172.16.80.1 -o parent=eth0.10`
- VLAN: 20, IP subnet: 172.16.50.0/22, Gateway: 172.16.50.1
  - `--subnet=172.16.50.0/22 --gateway=172.16.50.1 -o parent=eth0.20`
- VLAN: 30, Subnet: 10.1.100.0/16, Gateway: 10.1.100.1
  - `--subnet=10.1.100.0/16 --gateway=10.1.100.1 -o parent=eth0.30`

### IPvlan L3 mode example

IPvlan will require routes to be distributed to each endpoint. The driver only
builds the IPvlan L3 mode port and attaches the container to the interface. Route
distribution throughout a cluster is beyond the initial implementation of this
single host scoped driver. In L3 mode, the Docker host is very similar to a
router starting new networks in the container. They are on networks that the
upstream network will not know about without route distribution. For those
curious how IPvlan L3 will fit into container networking, see the following
examples.

![Docker IPvlan L2 mode](images/ipvlan-l3.webp?w=500)

IPvlan L3 mode drops all broadcast and multicast traffic. This reason alone
makes IPvlan L3 mode a prime candidate for those looking for massive scale and
predictable network integrations. It is predictable and in turn will lead to
greater uptimes because there is no bridging involved. Bridging loops have been
responsible for high profile outages that can be hard to pinpoint depending on
the size of the failure domain. This is due to the cascading nature of BPDUs
(Bridge Port Data Units) that are flooded throughout a broadcast domain (VLAN)
to find and block topology loops. Eliminating bridging domains, or at the least,
keeping them isolated to a pair of ToRs (top of rack switches) will reduce hard
to troubleshoot bridging instabilities. IPvlan L2 modes is well suited for
isolated VLANs only trunked into a pair of ToRs that can provide a loop-free
non-blocking fabric. The next step further is to route at the edge via IPvlan L3
mode that reduces a failure domain to a local host only.

- L3 mode needs to be on a separate subnet as the default namespace since it
  requires a netlink route in the default namespace pointing to the IPvlan parent
  interface.
- The parent interface used in this example is `eth0` and it is on the subnet
  `192.168.1.0/24`. Notice the `docker network` is not on the same subnet
  as `eth0`.
- Unlike IPvlan l2 modes, different subnets/networks can ping one another as
  long as they share the same parent interface `-o parent=`.

```console
$$ ip a show eth0
3: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:39:45:2e brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.250/24 brd 192.168.1.255 scope global eth0
```

- A traditional gateway doesn't mean much to an L3 mode IPvlan interface since
  there is no broadcast traffic allowed. Because of that, the container default
  gateway points to the containers `eth0` device. See below for CLI output
  of `ip route` or `ip -6 route` from inside an L3 container for details.

The mode `-o ipvlan_mode=l3` must be explicitly specified since the default
IPvlan mode is `l2`.

The following example does not specify a parent interface. The network drivers
will create a dummy type link for the user rather than rejecting the network
creation and isolating containers from only communicating with one another.

```console
# Create the IPvlan L3 network
$ docker network create -d ipvlan \
    --subnet=192.168.214.0/24 \
    --subnet=10.1.214.0/24 \
    -o ipvlan_mode=l3 ipnet210

# Test 192.168.214.0/24 connectivity
$ docker run --net=ipnet210 --ip=192.168.214.10 -itd alpine /bin/sh
$ docker run --net=ipnet210 --ip=10.1.214.10 -itd alpine /bin/sh

# Test L3 connectivity from 10.1.214.0/24 to 192.168.214.0/24
$ docker run --net=ipnet210 --ip=192.168.214.9 -it --rm alpine ping -c 2 10.1.214.10

# Test L3 connectivity from 192.168.214.0/24 to 10.1.214.0/24
$ docker run --net=ipnet210 --ip=10.1.214.9 -it --rm alpine ping -c 2 192.168.214.10

```

> [!NOTE]
>
> Notice that there is no `--gateway=` option in the network create. The field
> is ignored if one is specified `l3` mode. Take a look at the container routing
> table from inside of the container:
>
> ```console
> # Inside an L3 mode container
> $$ ip route
>  default dev eth0
>   192.168.214.0/24 dev eth0  src 192.168.214.10
> ```

In order to ping the containers from a remote Docker host or the container be
able to ping a remote host, the remote host or the physical network in between
need to have a route pointing to the host IP address of the container's Docker
host eth interface.

### Dual stack IPv4 IPv6 IPvlan L2 mode

- Not only does Libnetwork give you complete control over IPv4 addressing, but
  it also gives you total control over IPv6 addressing as well as feature parity
  between the two address families.

- The next example will start with IPv6 only. Start two containers on the same
  VLAN `139` and ping one another. Since the IPv4 subnet is not specified, the
  default IPAM will provision a default IPv4 subnet. That subnet is isolated
  unless the upstream network is explicitly routing it on VLAN `139`.

```console
# Create a v6 network
$ docker network create -d ipvlan \
    --ipv6 --subnet=2001:db8:abc2::/64 --gateway=2001:db8:abc2::22 \
    -o parent=eth0.139 v6ipvlan139

# Start a container on the network
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh
```

View the container eth0 interface and v6 routing table:

```console
# Inside the IPv6 container
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc2::1/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc2::/64 dev eth0  proto kernel  metric 256
default via 2001:db8:abc2::22 dev eth0  metric 1024
```

Start a second container and ping the first container's v6 address.

```console
# Test L2 connectivity over IPv6
$ docker run --net=v6ipvlan139 -it --rm alpine /bin/sh

# Inside the second IPv6 container
$$ ip a show eth0
75: eth0@if55: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link tentative dadfailed
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc2::2/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ping6 2001:db8:abc2::1
PING 2001:db8:abc2::1 (2001:db8:abc2::1): 56 data bytes
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=0 ttl=64 time=0.044 ms
64 bytes from 2001:db8:abc2::1%eth0: icmp_seq=1 ttl=64 time=0.058 ms

2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.044/0.051/0.058/0.000 ms
```

The next example with setup a dual stack IPv4/IPv6 network with an example
VLAN ID of `140`.

Next create a network with two IPv4 subnets and one IPv6 subnets, all of which
have explicit gateways:

```console
$ docker network create -d ipvlan \
    --subnet=192.168.140.0/24 --subnet=192.168.142.0/24 \
    --gateway=192.168.140.1 --gateway=192.168.142.1 \
    --subnet=2001:db8:abc9::/64 --gateway=2001:db8:abc9::22 \
    -o parent=eth0.140 \
    -o ipvlan_mode=l2 ipvlan140
```

Start a container and view eth0 and both v4 & v6 routing tables:

```console
$ docker run --net=ipvlan140 --ip6=2001:db8:abc2::51 -it --rm alpine /bin/sh

$ ip a show eth0
78: eth0@if77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.140.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc9::1/64 scope link nodad
       valid_lft forever preferred_lft forever

$$ ip route
default via 192.168.140.1 dev eth0
192.168.140.0/24 dev eth0  proto kernel  scope link  src 192.168.140.2

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc9::/64 dev eth0  proto kernel  metric 256
default via 2001:db8:abc9::22 dev eth0  metric 1024
```

Start a second container with a specific `--ip4` address and ping the first host
using IPv4 packets:

```console
$ docker run --net=ipvlan140 --ip=192.168.140.10 -it --rm alpine /bin/sh
```

> [!NOTE]
>
> Different subnets on the same parent interface in IPvlan `L2` mode cannot ping
> one another. That requires a router to proxy-arp the requests with a secondary
> subnet. However, IPvlan `L3` will route the unicast traffic between disparate
> subnets as long as they share the same `-o parent` parent link.

### Use router-assigned IPv6 addresses

The previous examples assign IPv6 addresses from a subnet managed by Docker's
IPAM. On an `ipvlan` network, you can instead let containers receive IPv6
addresses directly from a router on the parent network, using stateless
address autoconfiguration (SLAAC).

When an `ipvlan` network has no IPv6 subnet, Docker disables IPv6 on the
container's interface, so it can't accept the router advertisements that SLAAC
relies on. To re-enable IPv6 on the interface, set its `disable_ipv6` sysctl
to `0` when you connect the container to the network:

```console
$ docker network connect \
    --driver-opt="com.docker.network.endpoint.sysctls=net.ipv6.conf.IFNAME.disable_ipv6=0" \
    my-ipvlan-net my-container
```

Use the literal string `IFNAME` in the sysctl name. Docker replaces it with
the name of the container's interface on this network. `disable_ipv6` is a
per-interface sysctl, so it must be set with the `endpoint.sysctls`
driver option rather than `docker run --sysctl`. For more details, see
[`docker network connect`](/reference/cli/docker/network/connect/#sysctl).

### Dual stack IPv4 IPv6 IPvlan L3 mode

Example: IPvlan L3 Mode Dual Stack IPv4/IPv6, Multi-Subnet w/ 802.1Q VLAN Tag:118

As in all of the examples, a tagged VLAN interface does not have to be used. The
sub-interfaces can be swapped with `eth0`, `eth1`, `bond0` or any other valid
interface on the host other then the `lo` loopback.

The primary difference you will see is that L3 mode does not create a default
route with a next-hop but rather sets a default route pointing to `dev eth` only
since ARP/Broadcasts/Multicast are all filtered by Linux as per the design. Since
the parent interface is essentially acting as a router, the parent interface IP
and subnet needs to be different from the container networks. That is the opposite
of bridge and L2 modes, which need to be on the same subnet (broadcast domain)
in order to forward broadcast and multicast packets.

```console
# Create an IPv6+IPv4 Dual Stack IPvlan L3 network
# Gateways for both v4 and v6 are set to a dev e.g. 'default dev eth0'
$ docker network create -d ipvlan \
    --subnet=192.168.110.0/24 \
    --subnet=192.168.112.0/24 \
    --ipv6 --subnet=2001:db8:abc6::/64 \
    -o parent=eth0 \
    -o ipvlan_mode=l3 ipnet110


# Start a few of containers on the network (ipnet110)
# in separate terminals and check connectivity
$ docker run --net=ipnet110 -it --rm alpine /bin/sh
# Start a second container specifying the v6 address
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::10 -it --rm alpine /bin/sh
# Start a third specifying the IPv4 address
$ docker run --net=ipnet110 --ip=192.168.112.30 -it --rm alpine /bin/sh
# Start a 4th specifying both the IPv4 and IPv6 addresses
$ docker run --net=ipnet110 --ip6=2001:db8:abc6::50 --ip=192.168.112.50 -it --rm alpine /bin/sh
```

Interface and routing table outputs are as follows:

```console
$$ ip a show eth0
63: eth0@if59: <BROADCAST,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default
    link/ether 00:50:56:2b:29:40 brd ff:ff:ff:ff:ff:ff
    inet 192.168.112.2/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc4::250:56ff:fe2b:2940/64 scope link
       valid_lft forever preferred_lft forever
    inet6 2001:db8:abc6::10/64 scope link nodad
       valid_lft forever preferred_lft forever

# Note the default route is the eth device because ARPs are filtered.
$$ ip route
  default dev eth0  scope link
  192.168.112.0/24 dev eth0  proto kernel  scope link  src 192.168.112.2

$$ ip -6 route
2001:db8:abc4::/64 dev eth0  proto kernel  metric 256
2001:db8:abc6::/64 dev eth0  proto kernel  metric 256
default dev eth0  metric 1024
```

> [!NOTE]
>
> There may be a bug when specifying `--ip6=` addresses when you delete a
> container with a specified v6 address and then start a new container with the
> same v6 address it throws the following like the address isn't properly being
> released to the v6 pool. It will fail to unmount the container and be left dead.

```console
docker: Error response from daemon: Address already in use.
```

### Manually create 802.1Q links

#### VLAN ID 40

If a user does not want the driver to create the VLAN sub-interface, it needs to
exist before running `docker network create`. If you have sub-interface
naming that is not `interface.vlan_id` it is honored in the `-o parent=` option
again as long as the interface exists and is up.

Links, when manually created, can be named anything as long as they exist when
the network is created. Manually created links do not get deleted regardless of
the name when the network is deleted with `docker network rm`.

```console
# create a new sub-interface tied to dot1q vlan 40
$ ip link add link eth0 name eth0.40 type vlan id 40

# enable the new sub-interface
$ ip link set eth0.40 up

# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
$ docker network create -d ipvlan \
    --subnet=192.168.40.0/24 \
    --gateway=192.168.40.1 \
    -o parent=eth0.40 ipvlan40

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
```

Example: VLAN sub-interface manually created with any name:

```console
# create a new sub interface tied to dot1q vlan 40
$ ip link add link eth0 name foo type vlan id 40

# enable the new sub-interface
$ ip link set foo up

# now add networks and hosts as you would normally by attaching to the master (sub)interface that is tagged
$ docker network create -d ipvlan \
    --subnet=192.168.40.0/24 --gateway=192.168.40.1 \
    -o parent=foo ipvlan40

# in two separate terminals, start a Docker container and the containers can now ping one another.
$ docker run --net=ipvlan40 -it --name ivlan_test5 --rm alpine /bin/sh
$ docker run --net=ipvlan40 -it --name ivlan_test6 --rm alpine /bin/sh
```

Manually created links can be cleaned up with:

```console
$ ip link del foo
```

As with all of the Libnetwork drivers, they can be mixed and matched, even as
far as running 3rd party ecosystem drivers in parallel for maximum flexibility
to the Docker user.


---

# Macvlan network driver

*Sección: Engine*

Some applications, especially legacy applications or applications which monitor
network traffic, expect to be directly connected to the physical network. In
this type of situation, you can use the `macvlan` network driver to assign a MAC
address to each container's virtual network interface, making it appear to be
a physical network interface directly connected to the physical network. In this
case, you need to designate a physical interface on your Docker host to use for
the Macvlan, as well as the subnet and gateway of the network. You can even
isolate your Macvlan networks using different physical network interfaces.

## Platform support and requirements

- The macvlan driver only works on Linux hosts. It is not supported on
  Docker Desktop for Mac or Windows, or Docker Engine on Windows.
- Most cloud providers block macvlan networking. You may need physical access to
  your networking equipment.
- Requires at least Linux kernel version 3.9 (version 4.0 or later is
  recommended).
- The macvlan driver is not supported in rootless mode.

## Considerations

- You may unintentionally degrade your network due to IP address
  exhaustion or to "VLAN spread", a situation that occurs when you have an
  inappropriately large number of unique MAC addresses in your network.

- Your networking equipment needs to be able to handle "promiscuous mode",
  where one physical interface can be assigned multiple MAC addresses.

- If your application can work using a bridge (on a single Docker host) or
  overlay (to communicate across multiple Docker hosts), these solutions may be
  better in the long term.

- Containers attached to a macvlan network cannot communicate with the host
  directly, this is a restriction in the Linux kernel. If you need communication
  between the host and the containers, you can connect the containers to a
  bridge network as well as the macvlan. It is also possible to create a
  macvlan interface on the host with the same parent interface, and assign it
  an IP address in the Docker network's subnet.

## Options

The following table describes the driver-specific options that you can pass to
`--opt` when creating a network using the `macvlan` driver.

| Option         | Default  | Description                                                                   |
| -------------- | -------- | ----------------------------------------------------------------------------- |
| `macvlan_mode` | `bridge` | Sets the Macvlan mode. Can be one of: `bridge`, `vepa`, `passthru`, `private` |
| `parent`       |          | Specifies the parent interface to use.                                        |

## Create a Macvlan network

When you create a Macvlan network, it can either be in bridge mode or 802.1Q
trunk bridge mode.

- In bridge mode, Macvlan traffic goes through a physical device on the host.

- In 802.1Q trunk bridge mode, traffic goes through an 802.1Q sub-interface
  which Docker creates on the fly. This allows you to control routing and
  filtering at a more granular level.

### Bridge mode

To create a `macvlan` network which bridges with a given physical network
interface, use `--driver macvlan` with the `docker network create` command. You
also need to specify the `parent`, which is the interface the traffic will
physically go through on the Docker host.

```console
$ docker network create -d macvlan \
  --subnet=172.16.86.0/24 \
  --gateway=172.16.86.1 \
  -o parent=eth0 pub_net
```

If you need to exclude IP addresses from being used in the `macvlan` network, such
as when a given IP address is already in use, use `--aux-addresses`:

```console
$ docker network create -d macvlan \
  --subnet=192.168.32.0/24 \
  --ip-range=192.168.32.128/25 \
  --gateway=192.168.32.254 \
  --aux-address="my-router=192.168.32.129" \
  -o parent=eth0 macnet32
```

### 802.1Q trunk bridge mode

If you specify a `parent` interface name with a dot included, such as `eth0.50`,
Docker interprets that as a sub-interface of `eth0` and creates the sub-interface
automatically.

```console
$ docker network create -d macvlan \
    --subnet=192.168.50.0/24 \
    --gateway=192.168.50.1 \
    -o parent=eth0.50 macvlan50
```

### Use an IPvlan instead of Macvlan

An `ipvlan` network created with option `-o ipvlan_mode=l2` is similar
to a macvlan network. The main difference is that the `ipvlan` driver
doesn't assign a MAC address to each container, the layer-2 network stack
is shared by devices in the ipvlan network. So, containers use the parent
interface's MAC address.

The network will see fewer MAC addresses, and the host's MAC address will be
associated with the IP address of each container.

The choice of network type depends on your environment and requirements.
There are some notes about the trade-offs in the [Linux kernel
documentation](https://docs.kernel.org/networking/ipvlan.html#what-to-choose-macvlan-vs-ipvlan).

```console
$ docker network create -d ipvlan \
    --subnet=192.168.210.0/24 \
    --gateway=192.168.210.254 \
     -o ipvlan_mode=l2 -o parent=eth0 ipvlan210
```

## Use IPv6

If you have [configured the Docker daemon to allow IPv6](../../daemon/ipv6.md),
you can use dual-stack IPv4/IPv6 `macvlan` networks.

```console
$ docker network create -d macvlan \
    --subnet=192.168.216.0/24 --subnet=192.168.218.0/24 \
    --gateway=192.168.216.1 --gateway=192.168.218.1 \
    --subnet=2001:db8:abc8::/64 --gateway=2001:db8:abc8::10 \
     -o parent=eth0.218 \
     -o macvlan_mode=bridge macvlan216
```

### Use router-assigned IPv6 addresses

The previous example assigns IPv6 addresses from a subnet managed by Docker's
IPAM. On a `macvlan` network, you can instead let containers receive IPv6
addresses directly from a router on the parent network, using stateless
address autoconfiguration (SLAAC).

When a `macvlan` network has no IPv6 subnet, Docker disables IPv6 on the
container's interface, so it can't accept the router advertisements that SLAAC
relies on. To re-enable IPv6 on the interface, set its `disable_ipv6` sysctl
to `0` when you connect the container to the network:

```console
$ docker network connect \
    --driver-opt="com.docker.network.endpoint.sysctls=net.ipv6.conf.IFNAME.disable_ipv6=0" \
    my-macvlan-net my-container
```

Use the literal string `IFNAME` in the sysctl name. Docker replaces it with
the name of the container's interface on this network. `disable_ipv6` is a
per-interface sysctl, so it must be set with the `endpoint.sysctls`
driver option rather than `docker run --sysctl`. For more details, see
[`docker network connect`](/reference/cli/docker/network/connect/#sysctl).

## Usage examples

This section provides hands-on examples for working with macvlan networks,
including bridge mode and 802.1Q trunk bridge mode.

> [!NOTE]
> These examples assume your ethernet interface is `eth0`. If your device has a
> different name, use that instead.

### Bridge mode example

In bridge mode, your traffic flows through `eth0` and Docker routes traffic to
your container using its MAC address. To network devices on your network, your
container appears to be physically attached to the network.

1. Create a macvlan network called `my-macvlan-net`. Modify the `subnet`,
   `gateway`, and `parent` values to match your environment:

   ```console
   $ docker network create -d macvlan \
     --subnet=172.16.86.0/24 \
     --gateway=172.16.86.1 \
     -o parent=eth0 \
     my-macvlan-net
   ```

   Verify the network was created:

   ```console
   $ docker network ls
   $ docker network inspect my-macvlan-net
   ```

2. Start an `alpine` container and attach it to the `my-macvlan-net` network.
   The `-dit` flags start the container in the background. The `--rm` flag
   removes the container when it stops:

   ```console
   $ docker run --rm -dit \
     --network my-macvlan-net \
     --name my-macvlan-alpine \
     alpine:latest \
     ash
   ```

3. Inspect the container and notice the `MacAddress` key within the `Networks`
   section:

   ```console
   $ docker container inspect my-macvlan-alpine
   ```

   Look for output similar to:

   ```json
   "Networks": {
     "my-macvlan-net": {
       "Gateway": "172.16.86.1",
       "IPAddress": "172.16.86.2",
       "IPPrefixLen": 24,
       "MacAddress": "02:42:ac:10:56:02",
       ...
     }
   }
   ```

4. Check how the container sees its own network interfaces:

   ```console
   $ docker exec my-macvlan-alpine ip addr show eth0

   9: eth0@tunl0: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
   link/ether 02:42:ac:10:56:02 brd ff:ff:ff:ff:ff:ff
   inet 172.16.86.2/24 brd 172.16.86.255 scope global eth0
      valid_lft forever preferred_lft forever
   ```

   Check the routing table:

   ```console
   $ docker exec my-macvlan-alpine ip route

   default via 172.16.86.1 dev eth0
   172.16.86.0/24 dev eth0 scope link  src 172.16.86.2
   ```

5. Stop the container (Docker removes it automatically) and remove the network:

   ```console
   $ docker container stop my-macvlan-alpine
   $ docker network rm my-macvlan-net
   ```

### 802.1Q trunked bridge mode example

In 802.1Q trunk bridge mode, your traffic flows through a sub-interface of
`eth0` (called `eth0.10`) and Docker routes traffic to your container using its
MAC address. To network devices on your network, your container appears to be
physically attached to the network.

1. Create a macvlan network called `my-8021q-macvlan-net`. Modify the `subnet`,
   `gateway`, and `parent` values to match your environment:

   ```console
   $ docker network create -d macvlan \
     --subnet=172.16.86.0/24 \
     --gateway=172.16.86.1 \
     -o parent=eth0.10 \
     my-8021q-macvlan-net
   ```

   Verify the network was created and has parent `eth0.10`. You can use `ip addr
show` on the Docker host to verify that the interface `eth0.10` exists:

   ```console
   $ docker network ls
   $ docker network inspect my-8021q-macvlan-net
   ```

2. Start an `alpine` container and attach it to the `my-8021q-macvlan-net`
   network:

   ```console
   $ docker run --rm -itd \
     --network my-8021q-macvlan-net \
     --name my-second-macvlan-alpine \
     alpine:latest \
     ash
   ```

3. Inspect the container and notice the `MacAddress` key:

   ```console
   $ docker container inspect my-second-macvlan-alpine
   ```

   Look for the `Networks` section with the MAC address.

4. Check how the container sees its own network interfaces:

   ```console
   $ docker exec my-second-macvlan-alpine ip addr show eth0

   11: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
   link/ether 02:42:ac:10:56:02 brd ff:ff:ff:ff:ff:ff
   inet 172.16.86.2/24 brd 172.16.86.255 scope global eth0
      valid_lft forever preferred_lft forever
   ```

   Check the routing table:

   ```console
   $ docker exec my-second-macvlan-alpine ip route

   default via 172.16.86.1 dev eth0
   172.16.86.0/24 dev eth0 scope link  src 172.16.86.2
   ```

5. Stop the container and remove the network:

   ```console
   $ docker container stop my-second-macvlan-alpine
   $ docker network rm my-8021q-macvlan-net
   ```


---

# None network driver

*Sección: Engine*

If you want to completely isolate the networking stack of a container, you can
use the `--network none` flag when starting the container. Within the container,
only the loopback device is created.

The following example shows the output of `ip link show` in an `alpine`
container using the `none` network driver.

```console
$ docker run --rm --network none alpine:latest ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
```

No IPv6 loopback address is configured for containers using the `none` driver.

```console
$ docker run --rm --network none --name no-net-alpine alpine:latest ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
```

## Next steps

- Learn about [networking from the container's point of view](../index.md)
- Learn about [host networking](host.md)
- Learn about [bridge networks](bridge.md)
- Learn about [overlay networks](overlay.md)
- Learn about [Macvlan networks](macvlan.md)


---

# Overlay network driver

*Sección: Engine*

The `overlay` network driver creates a distributed network among multiple
Docker daemon hosts. This network sits on top of (overlays) the host-specific
networks, allowing containers connected to it to communicate securely when
encryption is enabled. Docker transparently handles routing of each packet to
and from the correct Docker daemon host and the correct destination container.

You can create user-defined `overlay` networks using `docker network create`,
in the same way that you can create user-defined `bridge` networks. Services
or containers can be connected to more than one network at a time. Services or
containers can only communicate across networks they're each connected to.

Overlay networks are often used to create a connection between Swarm services,
but you can also use it to connect standalone containers running on different
hosts. When using standalone containers, it's still required that you use
Swarm mode to establish a connection between the hosts.

This page describes overlay networks in general, and when used with standalone
containers. For information about overlay for Swarm services, see
[Manage Swarm service networks](../../swarm/networking.md).

## Requirements

Docker hosts must be part of a swarm to use overlay networks, even when
connecting standalone containers. The following ports must be open between
participating hosts:

| Ports                  | Description                                                                                                                                             |
| :--------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `2377/tcp`             | The default Swarm control plane port, is configurable with [`docker swarm join --listen-addr`](/reference/cli/docker/swarm/join/#listen-addr) |
| `4789/udp`             | The default overlay traffic port, configurable with [`docker swarm init --data-path-port`](/reference/cli/docker/swarm/init/#data-path-port)          |
| `7946/tcp`, `7946/udp` | Used for communication among nodes, not configurable                                                                                                    |

## Create an overlay network

To create an overlay network that containers on other Docker hosts can connect to,
run the following command:

```console
$ docker network create -d overlay --attachable my-attachable-overlay
```

The `--attachable` option enables both standalone containers
and Swarm services to connect to the overlay network.
Without `--attachable`, only Swarm services can connect to the network.

You can specify the IP address range, subnet, gateway, and other options. See
`docker network create --help` for details.

## Encrypt traffic on an overlay network

Use the `--opt encrypted` flag to encrypt the application data
transmitted over the overlay network:

```console
$ docker network create \
  --opt encrypted \
  --driver overlay \
  --attachable \
  my-attachable-multi-host-network
```

This enables IPsec encryption at the level of the Virtual Extensible LAN (VXLAN).
This encryption imposes a non-negligible performance penalty,
so you should test this option before using it in production.

> [!WARNING]
>
> Don't attach Windows containers to encrypted overlay networks.
>
> Overlay network encryption isn't supported on Windows.
> Swarm doesn't report an error when a Windows host
> attempts to connect to an encrypted overlay network,
> but networking for the Windows containers is affected as follows:
>
> - Windows containers can't communicate with Linux containers on the network
> - Data traffic between Windows containers on the network isn't encrypted

## Attach a container to an overlay network

Adding containers to an overlay network gives them the ability to communicate
with other containers without having to set up routing on the individual Docker
daemon hosts. A prerequisite for doing this is that the hosts have joined the same Swarm.

To join an overlay network named `multi-host-network` with a `busybox` container:

```console
$ docker run --network multi-host-network busybox sh
```

> [!NOTE]
>
> This only works if the overlay network is attachable
> (created with the `--attachable` flag).

## Container discovery

Publishing ports of a container on an overlay network opens the ports to other
containers on the same network. Containers are discoverable by doing a DNS lookup
using the container name.

| Flag value                      | Description                                                                                                                                                 |
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-p 8080:80`                    | Map TCP port 80 in the container to port `8080` on the overlay network.                                                                                     |
| `-p 8080:80/udp`                | Map UDP port 80 in the container to port `8080` on the overlay network.                                                                                     |
| `-p 8080:80/sctp`               | Map SCTP port 80 in the container to port `8080` on the overlay network.                                                                                    |
| `-p 8080:80/tcp -p 8080:80/udp` | Map TCP port 80 in the container to TCP port `8080` on the overlay network, and map UDP port 80 in the container to UDP port `8080` on the overlay network. |

## Connection limit for overlay networks

Due to limitations set by the Linux kernel, overlay networks become unstable and
inter-container communications may break when 1000 containers are co-located on
the same host.

For more information about this limitation, see
[moby/moby#44973](https://github.com/moby/moby/issues/44973#issuecomment-1543747718).

## Usage examples

This section provides hands-on examples for working with overlay networks. These
examples cover swarm services and standalone containers on multiple Docker hosts.

### Prerequisites

All examples require at least a single-node swarm. Initialize one by running
`docker swarm init` on the host. You can run these examples on multi-node
swarms as well.

### Use the default overlay network

This example shows how the default overlay network works with swarm services.
You'll create an `nginx` service and examine the network from the service
containers' perspective.

#### Prerequisites for multi-node setup

This walkthrough requires three Docker hosts that can communicate with each
other on the same network with no firewall blocking traffic between them:

- `manager`: Functions as both manager and worker
- `worker-1`: Functions as worker only
- `worker-2`: Functions as worker only

If you don't have three hosts available, you can set up three virtual machines
on a cloud provider with Docker installed.

#### Create the swarm

1. On `manager`, initialize the swarm. If the host has one network interface,
   the `--advertise-addr` flag is optional:

   ```console
   $ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>
   ```

   Save the join token displayed for use with workers.

2. On `worker-1`, join the swarm:

   ```console
   $ docker swarm join --token <TOKEN> \
     --advertise-addr <IP-ADDRESS-OF-WORKER-1> \
     <IP-ADDRESS-OF-MANAGER>:2377
   ```

3. On `worker-2`, join the swarm:

   ```console
   $ docker swarm join --token <TOKEN> \
     --advertise-addr <IP-ADDRESS-OF-WORKER-2> \
     <IP-ADDRESS-OF-MANAGER>:2377
   ```

4. On `manager`, list all nodes:

   ```console
   $ docker node ls

   ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
   d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
   nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
   ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
   ```

   Filter by role if needed:

   ```console
   $ docker node ls --filter role=manager
   $ docker node ls --filter role=worker
   ```

5. List Docker networks on all hosts. Each now has an overlay network called
   `ingress` and a bridge network called `docker_gwbridge`:

   ```console
   $ docker network ls

   NETWORK ID          NAME                DRIVER              SCOPE
   495c570066be        bridge              bridge              local
   961c6cae9945        docker_gwbridge     bridge              local
   ff35ceda3643        host                host                local
   trtnl4tqnc3n        ingress             overlay             swarm
   c8357deec9cb        none                null                local
   ```

The `docker_gwbridge` connects the `ingress` network to the Docker host's
network interface. If you create services without specifying a network, they
connect to `ingress`. It's recommended to use separate overlay networks for each
application or group of related applications.

#### Create the services

1. On `manager`, create a new overlay network:

   ```console
   $ docker network create -d overlay nginx-net
   ```

   The overlay network is automatically created on worker nodes when they run
   service tasks that need it.

2. On `manager`, create a 5-replica Nginx service connected to `nginx-net`:

   > [!NOTE]
   > Services can only be created on a manager.

   ```console
   $ docker service create \
     --name my-nginx \
     --publish target=80,published=80 \
     --replicas=5 \
     --network nginx-net \
     nginx
   ```

   The default `ingress` publish mode means you can browse to port 80 on any
   node and connect to one of the 5 service tasks, even if no tasks run on that
   node.

3. Monitor service creation progress:

   ```console
   $ docker service ls
   ```

4. Inspect the `nginx-net` network on all hosts. The `Containers` section lists
   all service tasks connected to the overlay network from that host.

5. From `manager`, inspect the service:

   ```console
   $ docker service inspect my-nginx
   ```

   Notice the information about ports and endpoints.

6. Create a second network and update the service to use it:

   ```console
   $ docker network create -d overlay nginx-net-2
   $ docker service update \
     --network-add nginx-net-2 \
     --network-rm nginx-net \
     my-nginx
   ```

7. Verify the update completed:

   ```console
   $ docker service ls
   ```

   Inspect both networks to verify containers moved from `nginx-net` to
   `nginx-net-2`.

   > [!NOTE]
   > Overlay networks are automatically created on swarm worker nodes as needed,
   > but aren't automatically removed.

8. Clean up:

   ```console
   $ docker service rm my-nginx
   $ docker network rm nginx-net nginx-net-2
   ```

### Use a user-defined overlay network

This example shows the recommended approach for production services using custom
overlay networks.

#### Prerequisites

This assumes the swarm is already set up and you're on a manager node.

#### Steps

1. Create a user-defined overlay network:

   ```console
   $ docker network create -d overlay my-overlay
   ```

2. Start a service using the overlay network, publishing port 80 to port 8080:

   ```console
   $ docker service create \
     --name my-nginx \
     --network my-overlay \
     --replicas 1 \
     --publish published=8080,target=80 \
     nginx:latest
   ```

3. Verify the service task is connected to the network:

   ```console
   $ docker network inspect my-overlay
   ```

   Check the `Containers` section for the `my-nginx` service task.

4. Clean up:

   ```console
   $ docker service rm my-nginx
   $ docker network rm my-overlay
   ```

### Use an overlay network for standalone containers

This example demonstrates DNS container discovery between standalone containers
on different Docker hosts using an overlay network.

#### Prerequisites

You need two Docker hosts that can communicate with each other with the
following ports open between them:

- TCP port 2377
- TCP and UDP port 7946
- UDP port 4789

This example refers to the hosts as `host1` and `host2`.

#### Steps

1. Set up the swarm:

   On `host1`, initialize a swarm:

   ```console
   $ docker swarm init
   Swarm initialized: current node (vz1mm9am11qcmo979tlrlox42) is now a manager.

   To add a worker to this swarm, run the following command:

       docker swarm join --token SWMTKN-1-5g90q48weqrtqryq4kj6ow0e8xm9wmv9o6vgqc5j320ymybd5c-8ex8j0bc40s6hgvy5ui5gl4gy 172.31.47.252:2377
   ```

   On `host2`, join the swarm using the token from the previous output:

   ```console
   $ docker swarm join --token <your_token> <your_ip_address>:2377
   This node joined a swarm as a worker.
   ```

   If the join fails, run `docker swarm leave --force` on `host2`, verify
   network and firewall settings, and try again.

2. On `host1`, create an attachable overlay network:

   ```console
   $ docker network create --driver=overlay --attachable test-net
   uqsof8phj3ak0rq9k86zta6ht
   ```

   Note the returned network ID.

3. On `host1`, start an interactive container that connects to `test-net`:

   ```console
   $ docker run -it --name alpine1 --network test-net alpine
   / #
   ```

4. On `host2`, list available networks. Notice that `test-net` doesn't exist yet:

   ```console
   $ docker network ls
   NETWORK ID          NAME                DRIVER              SCOPE
   ec299350b504        bridge              bridge              local
   66e77d0d0e9a        docker_gwbridge     bridge              local
   9f6ae26ccb82        host                host                local
   omvdxqrda80z        ingress             overlay             swarm
   b65c952a4b2b        none                null                local
   ```

5. On `host2`, start a detached, interactive container that connects to
   `test-net`:

   ```console
   $ docker run -dit --name alpine2 --network test-net alpine
   fb635f5ece59563e7b8b99556f816d24e6949a5f6a5b1fbd92ca244db17a4342
   ```

   > [!NOTE]
   > Automatic DNS container discovery only works with unique container names.

6. On `host2`, verify that `test-net` was created with the same network ID as on
   `host1`:

   ```console
   $ docker network ls
   NETWORK ID          NAME                DRIVER              SCOPE
   ...
   uqsof8phj3ak        test-net            overlay             swarm
   ```

7. On `host1`, ping `alpine2` from within `alpine1`:

   ```console
   / # ping -c 2 alpine2
   PING alpine2 (10.0.0.5): 56 data bytes
   64 bytes from 10.0.0.5: seq=0 ttl=64 time=0.600 ms
   64 bytes from 10.0.0.5: seq=1 ttl=64 time=0.555 ms

   --- alpine2 ping statistics ---
   2 packets transmitted, 2 packets received, 0% packet loss
   round-trip min/avg/max = 0.555/0.577/0.600 ms
   ```

   The two containers communicate over the overlay network connecting the two
   hosts. You can also run another container on `host2` and ping `alpine1`:

   ```console
   $ docker run -it --rm --name alpine3 --network test-net alpine
   / # ping -c 2 alpine1
   / # exit
   ```

8. On `host1`, close the `alpine1` session (which stops the container):

   ```console
   / # exit
   ```

9. Clean up. You must stop and remove containers on each host independently:

   On `host2`:

   ```console
   $ docker container stop alpine2
   $ docker network ls
   $ docker container rm alpine2
   ```

   When you stop `alpine2`, `test-net` disappears from `host2`.

   On `host1`:

   ```console
   $ docker container rm alpine1
   $ docker network rm test-net
   ```

## Next steps

- Learn about [networking from the container's point of view](../index.md)
- Learn about [standalone bridge networks](bridge.md)
- Learn about [Macvlan networks](macvlan.md)


---

# Docker with iptables

*Sección: Engine*

Docker creates iptables rules in the host's network namespace for bridge
networks. For bridge and other network types, iptables rules for DNS are
also created in the container's network namespace.

Creation of iptables rules can be disabled using daemon options `iptables`
and `ip6tables`, see [Prevent Docker from manipulating firewall rules](packet-filtering-firewalls.md#prevent-docker-from-manipulating-firewall-rules).
However, this is not recommended for most users as it will likely break
container networking.

### Docker and iptables chains

To support bridge and overlay networks, Docker creates the following custom
`iptables` chains in the `filter` table:

* `DOCKER-USER`
    * A placeholder for user-defined rules that will be processed before rules
      in the `DOCKER-FORWARD` and `DOCKER` chains.
* `DOCKER-FORWARD`
    * The first stage of processing for Docker's networks. Rules that pass packets
      that are not related to established connections to the other Docker chains,
      as well as rules to accept packets that are part of established connections.
* `DOCKER`, `DOCKER-BRIDGE`, `DOCKER-INTERNAL`
    * Rules that determine whether a packet that is not part of an established 
      connection should be accepted, based on the port forwarding configuration
      of running containers.
* `DOCKER-CT`
    * Per-bridge connection tracking rules.
* `DOCKER-INGRESS`
    * Rules related to Swarm networking.

In the `FORWARD` chain, Docker adds rules that unconditionally jump to the
`DOCKER-USER`, `DOCKER-FORWARD` and `DOCKER-INGRESS` chains.

In the `nat` table, Docker creates chain `DOCKER` and adds rules to implement
masquerading and port-mapping.

Docker requires IP Forwarding to be enabled on the host for its default
bridge network configuration. If it enables IP Forwarding, it also sets the
default policy of the iptables `FORWARD` chain in the `filter` table to `DROP`.

### Add iptables policies before Docker's rules

Packets that get accepted or rejected by rules in these custom chains will not
be seen by user-defined rules appended to the `FORWARD` chain. So, to add
additional rules to filter these packets, use the `DOCKER-USER` chain.

Rules appended to the `FORWARD` chain will be processed after Docker's rules.

> [!NOTE]
>
> By default, remote hosts can only reach a container through a port published
> to one of the Docker host's addresses. Sending packets to the container's own
> IP address instead ("direct routed" access) is not allowed.
>
> These packets are dropped by a rule in the `raw` table's `PREROUTING` chain,
> which is processed before the `filter` table. So, they never reach the
> `DOCKER-USER` chain, and a rule in `DOCKER-USER` cannot allow them.
>
> Any packet that reaches the host's firewall rules already addressed to a
> container is treated this way. For example, a Kubernetes CNI plugin may
> translate a Service address to a container address before the packet reaches
> the host's `PREROUTING` rules. Docker cannot distinguish the result from a
> packet routed to the container by a remote host. Which host interface these
> packets arrive on depends on the plugin's data path — for an overlay network
> it is normally the tunnel device.
>
> To allow direct routed access to a container's *published* ports, use network
> option `com.docker.network.bridge.trusted_host_interfaces`, or daemon option
> `allow-direct-routing`. Unpublished ports are still protected. See
> [Direct routing to containers in bridge networks](port-publishing.md#direct-routing-to-containers-in-bridge-networks).
> To allow direct routed access to all container ports, published or not, see
> [Gateway modes](port-publishing.md#gateway-modes).

### Match the original IP and ports for requests

When packets arrive to the `DOCKER-USER` chain, they have already passed through
a Destination Network Address Translation (DNAT) filter. That means that the
`iptables` flags you use can only match internal IP addresses and ports of
containers.

If you want to match traffic based on the original IP and port in the network
request, you must use the
[`conntrack` iptables extension](https://ipset.netfilter.org/iptables-extensions.man.html#lbAO).
For example:

```console
$ sudo iptables -I DOCKER-USER -p tcp -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
$ sudo iptables -I DOCKER-USER -p tcp -m conntrack --ctorigdst 198.51.100.2 --ctorigdstport 80 -j ACCEPT
```

> [!IMPORTANT]
>
> Using the `conntrack` extension may result in degraded performance.

### Allow forwarding between host interfaces

If Docker has set the default policy of the `FORWARD` chain in the `filter`
table to `DROP`, a rule in `DOCKER-USER` can be used to allow forwarding
between host interfaces. For example:

```console
$ iptables -I DOCKER-USER -i src_if -o dst_if -j ACCEPT
```

### Restrict external connections to containers

By default, all external source IPs are allowed to connect to ports that have
been published to the Docker host's addresses.

To allow only a specific IP or network to access the containers, insert a
negated rule at the top of the `DOCKER-USER` filter chain. For example, the
following rule drops packets from all IP addresses except `192.0.2.2`:

```console
$ iptables -I DOCKER-USER -i ext_if ! -s 192.0.2.2 -j DROP
```

You will need to change `ext_if` to correspond with your
host's actual external interface. You could instead allow connections from a
source subnet. The following rule only allows access from the subnet `192.0.2.0/24`:

```console
$ iptables -I DOCKER-USER -i ext_if ! -s 192.0.2.0/24 -j DROP
```

Finally, you can specify a range of IP addresses to accept using `--src-range`
(Remember to also add `-m iprange` when using `--src-range` or `--dst-range`):

```console
$ iptables -I DOCKER-USER -m iprange -i ext_if ! --src-range 192.0.2.1-192.0.2.3 -j DROP
```

You can combine `-s` or `--src-range` with `-d` or `--dst-range` to control both
the source and destination. For example, if the Docker host has addresses
`2001:db8:1111::2` and `2001:db8:2222::2`, you can make rules specific to
`2001:db8:1111::2` and leave `2001:db8:2222::2` open.

You may need to allow responses from servers outside the permitted external address
ranges. For example, containers may send DNS or HTTP requests to hosts that are
not allowed to access the container's services. The following rule accepts any
incoming or outgoing packet belonging to a flow that has already been accepted
by other rules. It must be placed before `DROP` rules that restrict access from
external address ranges.

```console
$ iptables -I DOCKER-USER -m state --state RELATED,ESTABLISHED -j ACCEPT
```

For more information about iptables configuration and advanced usage,
refer to the [Netfilter.org HOWTO](https://www.netfilter.org/documentation/HOWTO/NAT-HOWTO.html).


---

# Docker with nftables

*Sección: Engine*

> [!WARNING]
>
> Support for nftables introduced in Docker 29.0.0 is experimental, configuration
> options, behavior and implementation may all change in future releases.
> The rules for overlay networks have not yet been migrated from iptables.
> Therefore, nftables cannot be enabled when the Docker daemon is running in
> Swarm mode.

To use nftables instead of iptables, use Docker Engine option
`--firewall-backend=nftables` on its command line, or `"firewall-backend": "nftables"`
in its configuration file. You may also need to modify IP forwarding configuration
on the host, and migrate rules from the iptables `DOCKER-USER` chain, see
[migrating from iptables to nftables](#migrating-from-iptables-to-nftables).

For bridge networks, Docker creates nftables rules in the host's network
namespace. For bridge and other network types, nftables rules for DNS are
also created in the container's network namespace.

Creation of nftables rules can be disabled using daemon options `iptables`
and `ip6tables`. _These options apply to both iptables and nftables._
See [Prevent Docker from manipulating firewall rules](packet-filtering-firewalls.md#prevent-docker-from-manipulating-firewall-rules).
However, this is not recommended for most users as it will likely break
container networking.

## Docker's nftables tables

For bridge networks, Docker creates two tables, `ip docker-bridges` and
`ip6 docker-bridges`.

Each table contains a number of [base chains](https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Adding_base_chains),
and further chains are added for each bridge network. The moby project
has some [internal documentation](https://github.com/moby/moby/blob/master/integration/network/bridge/nftablesdoc/index.md)
describing its nftables, and how they depend on network and container
configuration. However, the tables and their rules are likely to change
between Docker Engine releases.

> [!NOTE]
>
> Do not modify Docker's tables directly as the modifications are likely to
> be lost, Docker expects to have full ownership of its tables.

> [!NOTE]
>
> Because iptables has a fixed set of chains, equivalent to nftables base
> chains, all rules are included in those chains. The `DOCKER-USER` chain
> is supplied as a way to insert rules into the `filter` table's `FORWARD`
> chain, to run before Docker's rules.
> In Docker's nftables implementation, there is no `DOCKER-USER` chain.
> Instead, rules can be added in separate tables, with base chains that
> have the same types and hook points as Docker's base chains. If necessary,
> [base chain priority](https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains#Base_chain_priority)
> can be used to tell nftables which order to call the chains in.
> Docker uses well known [priority values](https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook) for each of its base chains.

## Migrating from iptables to nftables

If the Docker daemon has been running with the iptables firewall backend,
restarting it with the nftables backend will delete most of Docker's iptables
chains and rules, and create nftables rules instead.

If IP forwarding is not enabled, Docker will report an error when creating
a bridge network that needs it. Because of the default bridge, if IPv4
forwarding is disabled, the error will be reported during daemon startup.
See [IP forwarding](#ip-forwarding).

If you have rules in the `DOCKER-USER` chain, see [Migrating
`DOCKER-USER`](#migrating-docker-user).

You may need to manually update the iptables `FORWARD` policy if it has
been set to `DROP` by Docker with iptables, or as part of your host's
firewall configuration. See [FORWARD policy in iptables](#forward-policy-in-iptables).

### IP forwarding

IP forwarding on the Docker host enables Docker functionality including port
publishing, communication between bridge networks, and direct routing from
outside the host to containers in bridge networks.

When running with iptables, depending on network and daemon configuration,
Docker may enable IPv4 and IPv6 forwarding on the host.

With its nftables firewall backend enabled, Docker will not enable IP forwarding
itself. It will report an error if forwarding is needed, but not already enabled.
To disable Docker's check for IP forwarding, letting it start and create networks
when it determines that forwarding is disabled, use Daemon option `--ip-forward=false`,
or `"ip-forward": false` in its configuration file.

> [!WARNING]
>
> When enabling IP forwarding, make sure you have firewall rules to block
> unwanted forwarding between non-Docker interfaces.

> [!NOTE]
>
> If you stop Docker to migrate to nftables, Docker may have already enabled
> IP forwarding on your system. After a reboot, if no other service re-enables
> forwarding, Docker will fail to start.

If Docker is in a VM that has a single network interface and no other
software running, there is probably no unwanted forwarding to block.
But, on a physical host with multiple network interfaces, forwarding
between those interfaces should probably be blocked with nftables rules
unless the host is acting as a router.

To enable IP forwarding on the host, set the following sysctls:

- `net.ipv4.ip_forward=1`
- `net.ipv6.conf.all.forwarding=1`

If your host uses `systemd`, you may be able to use `systemd-sysctl`. For
example, by editing `/etc/sysctl.d/99-sysctl.conf`.

If the host is running `firewalld`, you may be able to use it to block
unwanted forwarding. Docker's bridges are in a firewalld zone called
`docker`, it creates a forwarding policy called `docker-forwarding` that
accepts forwarding from `ANY` zone to the `docker` zone.

For example, to use nftables to block forwarding between interfaces `eth0`
and `eth1`, you could use:

```console
table inet no-ext-forwarding {
	chain no-ext-forwarding {
		type filter hook forward priority filter; policy accept;
		iifname "eth0" oifname "eth1" drop
		iifname "eth1" oifname "eth0" drop
	}
}
```

### FORWARD policy in iptables

An iptables chain with `FORWARD` policy `DROP` will drop packets that have
been accepted by Docker's nftables rules, because the packet will be processed
by the iptables chains as well as Docker's nftables chains.

Some features, including port publishing, will not work unless the `DROP`
policy is removed, or additional iptables rules are added to the iptables
`FORWARD` chain to accept Docker-related traffic.

When Docker is using iptables, and it enables IP forwarding on the host,
it sets the default policy of the iptables `FORWARD` chain to `DROP`. So,
if you stop Docker to migrate to nftables, it may have set a `DROP` that
you need to remove. It will be removed anyway on reboot.

To keep using rules in `DOCKER-USER` that rely on the chain having policy
`DROP`, you must add explicit `ACCEPT` rules for Docker related traffic.

To check the current iptables `FORWARD` policy, use:

```console
$ iptables -L FORWARD
Chain FORWARD (policy DROP)
target     prot opt source               destination
$ ip6tables -L FORWARD
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
```

To set the iptables policies to `ACCEPT` for IPv4 and IPv6:

```console
$ iptables -P FORWARD ACCEPT
$ ip6tables -P FORWARD ACCEPT
```

### Migrating `DOCKER-USER`

With firewall backend "iptables", rules added to the iptables `DOCKER-USER`
are processed before Docker's rules in the filter table's `FORWARD` chain.

When starting the daemon with nftables after running with iptables, Docker
will not remove the jump from the `FORWARD` chain to `DOCKER-USER`. So,
rules created in `DOCKER-USER` will continue to run until the jump is
removed or the host is rebooted.

When starting with nftables, the daemon will not add the jump. So, unless
there is an existing jump, rules in `DOCKER-USER` will be ignored.

#### Migrating ACCEPT rules

Some rules in the `DOCKER-USER` chain will continue to work. For example, if a
packet is dropped, it will be dropped before or after the nftables rules in
Docker's `filter-FORWARD` chain. But other rules, particularly `ACCEPT` rules
to override Docker's `DROP` rules, will not work.

In nftables, an "accept" rule is not final. It terminates processing
for its base chain, but the accepted packet will still be processed by
other base chains, which may drop it.

To override Docker's `drop` rule, you must use a firewall mark. Select a
mark not already in use on your host, and use Docker Engine option
`--bridge-accept-fwmark`.

For example, `--bridge-accept-fwmark=1` tells the daemon to accept any
packet with an `fwmark` value of `1`. Optionally, you can supply a mask
to match specific bits in the mark, `--bridge-accept-fwmark=0x1/0x3`.

Then, instead of accepting the packet in `DOCKER-USER`, add the firewall
mark you have chosen and Docker will not drop it.

The firewall mark must be added before Docker's rules run. So if the mark
is added in a chain with type `filter` and hook `forward`, it must have
priority `filter - 1` or lower.

> [!NOTE]
>
> By default, remote hosts can only reach a container through a port published
> to one of the Docker host's addresses. Sending packets to the container's own
> IP address instead ("direct routed" access) is not allowed.
>
> These packets are dropped by a rule in the `raw-PREROUTING` chain of the
> `docker-bridges` tables. Because a drop is final, a rule in one of your own
> tables cannot allow them. And, because that chain runs at the `prerouting`
> hook, before Docker's `filter-FORWARD` rules, a firewall mark added with
> `--bridge-accept-fwmark` has no effect on it.
>
> Any packet that reaches the host's firewall rules already addressed to a
> container is treated this way. For example, a Kubernetes CNI plugin may
> translate a Service address to a container address before the packet reaches
> the host's pre-routing rules. Docker cannot distinguish the result from a
> packet routed to the container by a remote host. Which host interface these
> packets arrive on depends on the plugin's data path — for an overlay network
> it is normally the tunnel device.
>
> To allow direct routed access to a container's *published* ports, use network
> option `com.docker.network.bridge.trusted_host_interfaces`, or daemon option
> `allow-direct-routing`. Unpublished ports are still protected. See
> [Direct routing to containers in bridge networks](port-publishing.md#direct-routing-to-containers-in-bridge-networks).
> To allow direct routed access to all container ports, published or not, see
> [Gateway modes](port-publishing.md#gateway-modes).

#### Replacing `DOCKER-USER` with an nftables table

Because nftables doesn't have pre-defined chains, to replace the `DOCKER-USER`
chain you can create your own table and add chains and rules to it.

The `DOCKER-USER` chain has type `filter` and hook `forward`, so it can
only have rules in the filter forward chain. The base chains in your
table can have any `type` or `hook`. If your rules need to run before
Docker's rules, give the base chains a lower `priority` number than
Docker's chain. Or, a higher priority to make sure they run after Docker's
rules.

Docker's base chains use the priority values defined at
[priority values](https://wiki.nftables.org/wiki-nftables/index.php/Netfilter_hooks#Priority_within_hook)

#### Example: restricting external connections to containers

By default, any remote host can connect to ports published to the Docker
host's external addresses.

To allow only a specific IP or network to access the containers, create a
table with a base chain that has a drop rule. For example, the
following table drops packets from all IP addresses except `192.0.2.2`:

```console
table ip my-table {
	chain my-filter-forward {
		type filter hook forward priority filter; policy accept;
		iifname "ext_if" ip saddr != 192.0.2.2 counter drop
	}
}
```

You will need to change `ext_if` to your host's external interface name.

You could instead accept connections from a source subnet. The following
table only accepts access from the subnet `192.0.2.0/24`:

```console
table ip my-table {
	chain my-filter-forward {
		type filter hook forward priority filter; policy accept;
		iifname "ext_if" ip saddr != 192.0.2.0/24 counter drop
	}
}
```

If you are running other services on the host that use IP forwarding
and need to be accessed by different external hosts, you will need more
specific filters. For example, to match the default prefix `br-` of
bridge devices belonging to Docker's user-defined bridge networks:

```console
table ip my-table {
	chain my-filter-forward {
		type filter hook forward priority filter; policy accept;
		iifname "ext_if" oifname "br-*" ip saddr != 192.0.2.0/24 counter drop
	}
}
```

For more information about nftables configuration and advanced usage,
refer to the [nftables wiki](https://wiki.nftables.org/wiki-nftables/index.php/Main_Page).


---

# Legacy container links

*Sección: Engine*

> [!WARNING]
>
> Links on the default `bridge` network are deprecated and scheduled for removal
> in Docker Engine 30.0. Starting with Docker Engine 29.6, Docker emits a
> deprecation warning when you create a container with these links. Links on
> non-default networks remain supported. Use user-defined networks instead of
> the legacy `--link` flag whenever possible.
>
> See [Differences between user-defined bridges and the default bridge](drivers/bridge.md#differences-between-user-defined-bridges-and-the-default-bridge)
> for some alternatives to using `--link`.

The information in this section explains legacy container links within the
Docker default `bridge` network which is created automatically when you install
Docker.

Before the [Docker networks feature](../../reference/api/ai-governance/index.md), you could use the
Docker link feature to allow containers to discover each other and securely
transfer information about one container to another container. With the
introduction of the Docker networks feature, you can still create links but they
behave differently between default `bridge` network and
[user defined networks](drivers/bridge.md#differences-between-user-defined-bridges-and-the-default-bridge).

This section briefly discusses connecting via a network port and then goes into
detail on container linking in default `bridge` network.

## Connect using network port mapping

Publishing a port with `-p` or `-P` is not container linking. It exposes a
container port on the host. For the current reference, see
[Published ports](port-publishing.md).

Let's say you used this command to run a simple Python Flask application:

```console
$ docker run -d -P training/webapp python app.py
```

When that container was created, the `-P` flag was used to automatically map
any network port inside it to a random high port within an *ephemeral port
range* on your Docker host. Next, when `docker ps` was run, you saw that port
5000 in the container was bound to port 49155 on the host.

```console
$ docker ps nostalgic_morse

CONTAINER ID  IMAGE                   COMMAND       CREATED        STATUS        PORTS                    NAMES
bc533791f3f5  training/webapp:latest  python app.py 5 seconds ago  Up 2 seconds  0.0.0.0:49155->5000/tcp  nostalgic_morse
```

You also saw how you can bind a container's ports to a specific port using
the `-p` flag. Here port 80 of the host is mapped to port 5000 of the
container:

```console
$ docker run -d -p 80:5000 training/webapp python app.py
```

And you saw why this isn't such a great idea because it constrains you to
only one container on that specific port.

Instead, you may specify a range of host ports to bind a container port to
that is different than the default *ephemeral port range*:

```console
$ docker run -d -p 8000-9000:5000 training/webapp python app.py
```

This would bind port 5000 in the container to a randomly available port
between 8000 and 9000 on the host.

There are also a few other ways you can configure the `-p` flag. By
default the `-p` flag binds the specified port to all interfaces on
the host machine. But you can also specify a binding to a specific
interface, for example only to the `localhost`.

```console
$ docker run -d -p 127.0.0.1:80:5000 training/webapp python app.py
```

This would bind port 5000 inside the container to port 80 on the
`localhost` or `127.0.0.1` interface on the host machine.

Or, to bind port 5000 of the container to a dynamic port but only on the
`localhost`, you could use:

```console
$ docker run -d -p 127.0.0.1::5000 training/webapp python app.py
```

You can also bind UDP and SCTP (typically used by telecom protocols such as SIGTRAN, Diameter, and S1AP/X2AP) ports by adding a trailing `/udp` or `/sctp`. For example:

```console
$ docker run -d -p 127.0.0.1:80:5000/udp training/webapp python app.py
```

You also learned about the useful `docker port` shortcut which showed us the
current port bindings. This is also useful for showing you specific port
configurations. For example, if you've bound the container port to the
`localhost` on the host machine, then the `docker port` output reflects that.

```console
$ docker port nostalgic_morse 5000

127.0.0.1:49155
```

> [!NOTE]
>
> The `-p` flag can be used multiple times to configure multiple ports.

## Connect with the linking system

> [!NOTE]
>
> This section covers the legacy link feature in the default `bridge` network.
> Refer to [differences between user-defined bridges and the default bridge](drivers/bridge.md#differences-between-user-defined-bridges-and-the-default-bridge)
> for more information on links in user-defined networks.

Network port mappings are not the only way Docker containers can connect to one
another. Docker also has a linking system that allows you to link multiple
containers together and send connection information from one to another. When
containers are linked, information about a source container can be sent to a
recipient container. This allows the recipient to see selected data describing
aspects of the source container.

### The importance of naming

To establish links, Docker relies on the names of your containers.
You've already seen that each container you create has an automatically
created name; indeed you've become familiar with our old friend
`nostalgic_morse` during this guide. You can also name containers
yourself. This naming provides two useful functions:

1. It can be useful to name containers that do specific functions in a way
   that makes it easier for you to remember them, for example naming a
   container containing a web application `web`.

2. It provides Docker with a reference point that allows it to refer to other
   containers, for example, you can specify to link the container `web` to container `db`.

You can name your container by using the `--name` flag, for example:

```console
$ docker run -d -P --name web training/webapp python app.py
```

This launches a new container and uses the `--name` flag to
name the container `web`. You can see the container's name using the
`docker ps` command.

```console
$ docker ps -l

CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES
aed84ee21bde  training/webapp:latest python app.py  12 hours ago  Up 2 seconds 0.0.0.0:49154->5000/tcp  web
```

You can also use `docker inspect` to return the container's name.


> [!NOTE]
>
> Container names must be unique. That means you can only call
> one container `web`. If you want to reuse a container name you must delete
> the old container (with `docker container rm`) before you can create a new
> container with the same name. As an alternative you can use the `--rm`
> flag with the `docker run` command. This deletes the container
> immediately after it is stopped.

## Communication across links

Links allow containers to discover each other and securely transfer information
about one container to another container. When you set up a link, you create a
conduit between a source container and a recipient container. The recipient can
then access select data about the source. To create a link, you use the `--link`
flag. First, create a new container, this time one containing a database.

```console
$ docker run -d --name db training/postgres
```

This creates a new container called `db` from the `training/postgres`
image, which contains a PostgreSQL database.

Now, you need to delete the `web` container you created previously so you can replace it
with a linked one:

```console
$ docker container rm -f web
```

Now, create a new `web` container and link it with your `db` container.

```console
$ docker run -d -P --name web --link db:db training/webapp python app.py
```

This links the new `web` container with the `db` container you created
earlier. The `--link` flag takes the form:

    --link <name or id>:alias

Where `name` is the name of the container we're linking to and `alias` is an
alias for the link name. That alias is used shortly.
The `--link` flag also takes the form:

    --link <name or id>

In this case the alias matches the name. You could write the previous
example as:

```console
$ docker run -d -P --name web --link db training/webapp python app.py
```

Next, inspect your linked containers with `docker inspect`:


```console
$ docker inspect -f "{{ .HostConfig.Links }}" web

[/db:/web/db]
```


You can see that the `web` container is now linked to the `db` container
`web/db`. Which allows it to access information about the `db` container.

So what does linking the containers actually do? You've learned that a link allows a
source container to provide information about itself to a recipient container. In
our example, the recipient, `web`, can access information about the source `db`. To do
this, Docker creates a secure tunnel between the containers that doesn't need to
expose any ports externally on the container; when we started the
`db` container we did not use either the `-P` or `-p` flags. That's a big benefit of
linking: we don't need to expose the source container, here the PostgreSQL database, to
the network.

Docker exposes connectivity information for the source container to the
recipient container in two ways:

* Environment variables,
* Updating the `/etc/hosts` file.

### Environment variables

> [!WARNING]
>
> Legacy-link environment variables were deprecated in Docker Engine 28.4, are
> disabled by default in Docker Engine 29.0, and are scheduled for removal in
> Docker Engine 30.0. In Docker Engine 29.x, set
> `DOCKER_KEEP_DEPRECATED_LEGACY_LINKS_ENV_VARS=1` in the `dockerd` process
> environment and restart the daemon to temporarily re-enable them.

Docker creates several environment variables when you link containers. Docker
automatically creates environment variables in the target container based on
the `--link` parameters. It also exposes all environment variables
originating from Docker from the source container. These include variables from:

* the `ENV` commands in the source container's Dockerfile
* the `-e`, `--env`, and `--env-file` options on the `docker run`
command when the source container is started

These environment variables enable programmatic discovery from within the
target container of information related to the source container.

> [!WARNING]
>
> It is important to understand that all environment variables originating
> from Docker within a container are made available to any container
> that links to it. This could have serious security implications if sensitive
> data is stored in them.

Docker sets an `<alias>_NAME` environment variable for each target container
listed in the `--link` parameter. For example, if a new container called
`web` is linked to a database container called `db` via `--link db:webdb`,
then Docker creates a `WEBDB_NAME=/web/webdb` variable in the `web` container.

Docker also defines a set of environment variables for each port exposed by the
source container. Each variable has a unique prefix in the form `<name>_PORT_<port>_<protocol>`

The components in this prefix are:

* the alias `<name>` specified in the `--link` parameter (for example, `webdb`)
* the `<port>` number exposed
* a `<protocol>` which is either TCP or UDP

Docker uses this prefix format to define three distinct environment variables:

* The `prefix_ADDR` variable contains the IP Address from the URL, for
example `WEBDB_PORT_5432_TCP_ADDR=172.17.0.82`.
* The `prefix_PORT` variable contains just the port number from the URL of
example `WEBDB_PORT_5432_TCP_PORT=5432`.
* The `prefix_PROTO` variable contains just the protocol from the URL of
example `WEBDB_PORT_5432_TCP_PROTO=tcp`.

If the container exposes multiple ports, an environment variable set is
defined for each one. This means, for example, if a container exposes 4 ports
that Docker creates 12 environment variables, 3 for each port.

Additionally, Docker creates an environment variable called `<alias>_PORT`.
This variable contains the URL of the source container's first exposed port.
The 'first' port is defined as the exposed port with the lowest number.
For example, consider the `WEBDB_PORT=tcp://172.17.0.82:5432` variable. If
that port is used for both tcp and udp, then the tcp one is specified.

Finally, Docker also exposes each Docker originated environment variable
from the source container as an environment variable in the target. For each
variable Docker creates an `<alias>_ENV_<name>` variable in the target
container. The variable's value is set to the value Docker used when it
started the source container.

Returning back to our database example, you can run the `env`
command to list the specified container's environment variables.

```console
$ docker run --rm --name web2 --link db:db training/webapp env

<...>
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_ADDR=172.17.0.5
<...>
```

You can see that Docker has created a series of environment variables with
useful information about the source `db` container. Each variable is prefixed
with
`DB_`, which is populated from the `alias` you specified above. If the `alias`
were `db1`, the variables would be prefixed with `DB1_`. You can use these
environment variables to configure your applications to connect to the database
on the `db` container. The connection is secure and private; only the
linked `web` container can communicate with the `db` container.

### Important notes on Docker environment variables

Unlike host entries in the [`/etc/hosts` file](#updating-the-etchosts-file),
IP addresses stored in the environment variables are not automatically updated
if the source container is restarted. We recommend using the host entries in
`/etc/hosts` to resolve the IP address of linked containers.

These environment variables are only set for the first process in the
container. Some daemons, such as `sshd`, scrub them when spawning shells
for connection.

### Updating the `/etc/hosts` file

In addition to the environment variables, Docker adds a host entry for the
source container to the `/etc/hosts` file. Here's an entry for the `web`
container:

```console
$ docker run -t -i --rm --link db:webdb training/webapp /bin/bash

root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde
<...>
172.17.0.5  webdb 6e5cdeb2d300 db
```

You can see two relevant host entries. The first is an entry for the `web`
container that uses the Container ID as a host name. The second entry uses the
link alias to reference the IP address of the `db` container. In addition to
the alias you provide, the linked container's name, if unique from the alias
provided to the `--link` parameter, and the linked container's hostname are
also added to `/etc/hosts` for the linked container's IP address. You can ping
that host via any of these entries:

```console
root@aed84ee21bde:/opt/webapp# apt-get install -yqq inetutils-ping
root@aed84ee21bde:/opt/webapp# ping webdb

PING webdb (172.17.0.5): 48 data bytes
56 bytes from 172.17.0.5: icmp_seq=0 ttl=64 time=0.267 ms
56 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.250 ms
56 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.256 ms
```

> [!NOTE]
>
> In the example, you had to install `ping` because it was not included
> in the container initially.

Here, you used the `ping` command to ping the `db` container using its host entry,
which resolves to `172.17.0.5`. You can use this host entry to configure an application
to make use of your `db` container.

> [!NOTE]
>
> You can link multiple recipient containers to a single source. For
> example, you could have multiple (differently named) web containers attached to your
>`db` container.

If you restart the source container, the `/etc/hosts` files on the linked containers
are automatically updated with the source container's new IP address,
allowing linked communication to continue.

```console
$ docker restart db
db

$ docker run -t -i --rm --link db:db training/webapp /bin/bash

root@aed84ee21bde:/opt/webapp# cat /etc/hosts
172.17.0.7  aed84ee21bde
<...>
172.17.0.9  db
```


---

# Packet filtering and firewalls

*Sección: Engine*

On Linux, Docker creates firewall rules to implement network
isolation, [port publishing](port-publishing.md) and filtering.

Because these rules are required for the correct functioning of Docker bridge
networks, you should not modify the rules created by Docker.

This page describes options that control Docker's firewall rules to
implement functionality including port publishing, and NAT/masquerading.

> [!NOTE]
> 
> Docker creates firewall rules for bridge networks.
> 
> No rules are created for `ipvlan`, `macvlan` or `host` networking.

## Firewall backend

By default, Docker Engine creates its firewall rules using iptables,
see [Docker with iptables](firewall-iptables.md). It also has
support for nftables, see [Docker with nftables](firewall-nftables.md).

For bridge networks, iptables and nftables have the same functionality.

Docker Engine option `firewall-backend` can be used to select whether
iptables or nftables is used. See
[daemon configuration](https://docs.docker.com/reference/cli/dockerd/).

## Docker on a router

On Linux, Docker needs "IP Forwarding" enabled on the host. So, it enables
the `sysctl` settings `net.ipv4.ip_forward` and `net.ipv6.conf.all.forwarding`
if they are not already enabled when it starts. When it does that, it also
configures the firewall to drop forwarded packets unless they are explicitly
accepted.

When Docker sets the default forwarding policy to "drop", it will prevent
your Docker host from acting as a router. This is the recommended setting when
IP Forwarding is enabled, unless router functionality is required.

To stop Docker from setting the forwarding policy to "drop", include
`"ip-forward-no-drop": true` in `/etc/docker/daemon.json`, or add option
`--ip-forward-no-drop` to the `dockerd` command line.

> [!NOTE]
>
> With the experimental nftables backend, Docker does not enable IP forwarding
> itself, and it will not create a default "drop" nftables policy. See
> [Migrating from iptables to nftables](firewall-nftables.md#migrating-from-iptables-to-nftables).

## Prevent Docker from manipulating firewall rules

Setting the `iptables` or `ip6tables` keys to `false` in
[daemon configuration](https://docs.docker.com/reference/cli/dockerd/), will
prevent Docker from creating most of its `iptables` or `nftables` rules. But,
this option is not appropriate for most users, it is likely to break
container networking for the Docker Engine.

For example, with Docker's firewalling disabled and no replacement
rules, containers in bridge networks will not be able to access
internet hosts by masquerading, but all of their ports will be accessible
to hosts on the local network.

It is not possible to completely prevent Docker from creating firewall
rules, and creating rules after-the-fact is extremely involved and beyond
the scope of these instructions.

## Integration with firewalld

If you are running Docker with the `iptables` or `ip6tables` options set to
`true`, and [firewalld](https://firewalld.org) is enabled on your system, in
addition to its usual iptables or nftables rules, Docker creates a `firewalld`
zone called `docker`, with target `ACCEPT`.

All bridge network interfaces created by Docker (for example, `docker0`) are
inserted into the `docker` zone.

Docker also creates a forwarding policy called `docker-forwarding` that allows
forwarding from `ANY` zone to the `docker` zone.

## Docker and ufw

[Uncomplicated Firewall](https://launchpad.net/ufw)
(ufw) is a frontend that ships with Debian and Ubuntu,
and it lets you manage firewall rules. Docker and ufw use firewall rules in
ways that make them incompatible with each other.

When you publish a container's ports using Docker, traffic to and from that
container gets diverted before it goes through the ufw firewall settings.
Docker routes container traffic in the `nat` table, which means that packets
are diverted before it reaches the `INPUT` and `OUTPUT` chains that ufw uses.
Packets are routed before the firewall rules can be applied,
effectively ignoring your firewall configuration.


---

# Port publishing and mapping

*Sección: Engine*

By default, for both IPv4 and IPv6, the Docker daemon blocks access to ports that
have not been published. Published container ports are mapped to host IP addresses.
To do this, it uses firewall rules to perform Network Address Translation (NAT),
Port Address Translation (PAT), and masquerading.

For example, `docker run -p 8080:80 [...]` creates a mapping
between port 8080 on any address on the Docker host, and the container's
port 80. Outgoing connections from the container will masquerade, using
the Docker host's IP address.

## Publishing ports

When you create or run a container using `docker create` or `docker run`, all
ports of containers on bridge networks are accessible from the Docker host and
other containers connected to the same network. Ports are not accessible from
outside the host or, with the default configuration, from containers in other
networks.

Use the `--publish` or `-p` flag to make a port available outside the host,
and to containers in other bridge networks.

This creates a firewall rule in the host,
mapping a container port to a port on the Docker host to the outside world.
Here are some examples:

| Flag value                      | Description                                                                                                                                             |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-p 8080:80`                    | Map port `8080` on the Docker host to TCP port `80` in the container.                                                                                   |
| `-p 192.168.1.100:8080:80`      | Map port `8080` on the Docker host IP `192.168.1.100` to TCP port `80` in the container.                                                                |
| `-p 8080:80/udp`                | Map port `8080` on the Docker host to UDP port `80` in the container.                                                                                   |
| `-p 8080:80/tcp -p 8080:80/udp` | Map TCP port `8080` on the Docker host to TCP port `80` in the container, and map UDP port `8080` on the Docker host to UDP port `80` in the container. |

> [!IMPORTANT]
>
> Publishing container ports is insecure by default. Meaning, when you publish
> a container's ports it becomes available not only to the Docker host, but to
> the outside world as well.
>
> If you include the localhost IP address (`127.0.0.1`, or `::1`) with the
> publish flag, only the Docker host can access the published container port.
>
> ```console
> $ docker run -p 127.0.0.1:8080:80 -p '[::1]:8080:80' nginx
> ```
>
> > [!WARNING]
> >
> > In releases older than 28.0.0, hosts within the same L2 segment (for example,
> > hosts connected to the same network switch) can reach ports published to localhost.
> > For more information, see
> > [moby/moby#45610](https://github.com/moby/moby/issues/45610)

Ports on the host's IPv6 addresses will map to the container's IPv4 address
if no host IP is given in a port mapping, the bridge network is IPv4-only,
and `--userland-proxy=true` (default).

## Direct routing

Port mapping ensures that published ports are accessible on the host's
network addresses, which are likely to be routable for any external
clients. No routes are normally set up in the host's network for container
addresses that exist within a host.

But, particularly with IPv6 you may prefer to avoid using NAT and instead
arrange for external routing to container addresses ("direct routing").

To access containers on a bridge network from outside the Docker host,
you must first set up routing to the bridge network via an address on the
Docker host. This can be achieved using static routes, Border Gateway Protocol (BGP),
or any other means appropriate for your network. For example, within
a local layer 2 network, remote hosts can set up static routes to a container
network via the Docker daemon host's address on the local network.

### Direct routing to containers in bridge networks

By default, remote hosts are not allowed direct access to container IP
addresses in Docker's Linux bridge networks. They can only access ports
published to host IP addresses.

To allow direct access to any published port, on any container, in any
Linux bridge network, use daemon option `"allow-direct-routing": true`
in `/etc/docker/daemon.json` or the equivalent `--allow-direct-routing`.

To allow direct routing from anywhere to containers in a specific bridge
network, see [Gateway modes](#gateway-modes).

Or, to allow direct routing via specific host interfaces, to a specific
bridge network, use the following option when creating the network:
- `com.docker.network.bridge.trusted_host_interfaces`

#### Example

Create a network where published ports on container IP addresses can be
accessed directly from interfaces `vxlan.1` and `eth3`:

```console
$ docker network create --subnet 192.0.2.0/24 --ip-range 192.0.2.0/29 -o com.docker.network.bridge.trusted_host_interfaces="vxlan.1:eth3" mynet
```

Run a container in that network, publishing its port 80 to port 8080 on
the host's loopback interface:

```console
$ docker run -d --ip 192.0.2.100 -p 127.0.0.1:8080:80 nginx
```

The web server running on the container's port 80 can now be accessed
from the Docker host at `http://127.0.0.1:8080`, or directly at
`http://192.0.2.100:80`. If remote hosts on networks connected to
interfaces `vxlan.1` and `eth3` have a route to the `192.0.2.0/24`
network inside the Docker host, they can also access the web server
via `http://192.0.2.100:80`.

## Gateway modes

The bridge network driver has the following options:
- `com.docker.network.bridge.gateway_mode_ipv6`
- `com.docker.network.bridge.gateway_mode_ipv4`

Each of these can be set to one of the gateway modes:
- `nat`
- `nat-unprotected`
- `routed`
- `isolated`

The default is `nat`, NAT and masquerading rules are set up for each
published container port. Packets leaving the host will use a host address.

With mode `routed`, no NAT or masquerading rules are set up, but firewall
rules are still set up so that only published container ports are accessible.
Outgoing packets from the container will use the container's address,
not a host address.

To access a published port in a `routed` network, remote hosts must have
a route to the container network via an external address on the Docker
host ("direct routing"). Hosts on the local layer-2 network can set up
direct routing without needing any additional network configuration.
Hosts outside the local network can only use direct routing to the
container if the network's routers are configured to enable it.

In a `nat` mode network, publishing a port to an address on the loopback
interface means remote hosts cannot access it. Other published container
ports in `routed` and `nat` networks are always accessible from remote
hosts using direct routing, unless the Docker host's firewall has additional
restrictions.

> [!NOTE]
>
> When a port is published to a specific host address in `nat` mode, if
> IP forwarding is enabled on the Docker host, the published port can be
> accessed via other host interfaces using direct routing to the host
> address.
>
> For example, a Docker host with IP forwarding enabled has two NICs with
> addresses `192.168.100.10/24` and `10.0.0.10/24`.
> When a port is published to `192.168.100.10`, a host in the `10.0.0.0/24`
> subnet can access that port by routing to `192.168.100.10` via `10.0.0.10`.

In `nat-unprotected` mode, unpublished container ports are also
accessible using direct routing, no port filtering rules are set up.
This mode is included for compatibility with legacy default behaviour.

The gateway mode also affects communication between containers that
are connected to different Docker networks on the same host.
- In `nat` and `nat-unprotected` modes, containers in other bridge
  networks can only access published ports via the host addresses they
  are published to. Direct routing from other networks is not allowed.
- In `routed` mode containers in other networks can use direct
  routing to access ports, without going via a host address.

In `routed` mode, a host port in a `-p` or `--publish` port mapping is
not used, and the host address is only used to decide whether to apply
the mapping to IPv4 or IPv6. So, when a mapping only applies to `routed`
mode, only addresses `0.0.0.0` or `::` should be used, and a host port
should not be given. If a specific address or port is given, it will
have no effect on the published port and a warning message will be
logged.

Mode `isolated` can only be used when the network is also created with
CLI flag `--internal`, or equivalent. An address is normally assigned to the
bridge device in an `internal` network. So, processes on the Docker host can
access the network, and containers in the network can access host services
listening on that bridge address (including services listening on "any" host
address, `0.0.0.0` or `::`). No address is assigned to the bridge when the
network is created with gateway mode `isolated`.

### Example

Create a network suitable for direct routing for IPv6, with NAT enabled
for IPv4:
```console
$ docker network create --ipv6 --subnet 2001:db8::/64 -o com.docker.network.bridge.gateway_mode_ipv6=routed mynet
```

Create a container with a published port:
```console
$ docker run --network=mynet -p 8080:80 myimage
```

Then:
- Only container port 80 will be open, for IPv4 and IPv6.
- For IPv6, using `routed` mode, port 80 will be open on the container's IP
  address. Port 8080 will not be opened on the host's IP addresses, and
  outgoing packets will use the container's IP address.
- For IPv4, using the default `nat` mode, the container's port 80 will be
  accessible via port 8080 on the host's IP addresses, as well as directly
  from within the Docker host. But, container port 80 cannot be accessed
  directly from outside the host.
  Connections originating from the container will masquerade, using the
  host's IP address.

In `docker inspect`, this port mapping will be shown as follows. Note that
there is no `HostPort` for IPv6, because it is using `routed` mode:
```console
$ docker container inspect <id> --format "{{json .NetworkSettings.Ports}}"
{"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"},{"HostIp":"::","HostPort":""}]}
```

Alternatively, to make the mapping IPv6-only, disabling IPv4 access to the
container's port 80, use the unspecified IPv6 address `[::]` and do not
include a host port number:
```console
$ docker run --network mynet -p '[::]::80'
```

## Setting the default bind address for containers

By default, when a container's ports are mapped without any specific host
address, the Docker daemon publishes ports to all host addresses
(`0.0.0.0` and `[::]`).

For example, the following command publishes port 8080 to all network
interfaces on the host, on both IPv4 and IPv6 addresses, potentially
making them available to the outside world.

```console
docker run -p 8080:80 nginx
```

You can change the default binding address for published container ports so that
they're only accessible to the Docker host by default. To do that, you can
configure the daemon to use the loopback address (`127.0.0.1`) instead.

> [!WARNING]
>
> In releases older than 28.0.0, hosts within the same L2 segment (for example,
> hosts connected to the same network switch) can reach ports published to
> localhost. For more information, see
> [moby/moby#45610](https://github.com/moby/moby/issues/45610)

To configure this setting for user-defined bridge networks, use
the `com.docker.network.bridge.host_binding_ipv4`
[driver option](drivers/bridge.md#default-host-binding-address) when you
create the network. Despite the option name, it is possible to specify an
IPv6 address.

```console
$ docker network create mybridge \
  -o "com.docker.network.bridge.host_binding_ipv4=127.0.0.1"
```

Or, to set the default binding address for containers in all user-defined
bridge networks, use daemon configuration option `default-network-opts`.
For example:

```json
{
  "default-network-opts": {
    "bridge": {
      "com.docker.network.bridge.host_binding_ipv4": "127.0.0.1"
    }
  }
}
```

> [!NOTE]
>
> Setting the default binding address to `::` means port bindings with no host
> address specified will work for any IPv6 address on the host. But, `0.0.0.0`
> means any IPv4 or IPv6 address.
>
> Changing the default bind address doesn't have any effect on Swarm services.
> Swarm services are always exposed on the `0.0.0.0` network interface.

### Masquerade or SNAT for outgoing packets

NAT is enabled by default for bridge networks, meaning outgoing packets
from containers are masqueraded. The source address of packets leaving
the Docker host is changed to an address on the host interface the packet
is sent on.

Masquerading can be disabled for a user-defined bridge network by using
the `com.docker.network.bridge.enable_ip_masquerade` driver option when
creating the network. For example:
```console
$ docker network create mybridge \
  -o com.docker.network.bridge.enable_ip_masquerade=false ...
```

To use a specific source address for outgoing packets for a user-defined
network, instead of letting masquerading select an address, use options
`com.docker.network.host_ipv4` and `com.docker.network.host_ipv6` to
specify the Source NAT (SNAT) address to use. The
`com.docker.network.bridge.enable_ip_masquerade` option must
be `true`, the default, for these options to have any effect.

### Default bridge

To set the default binding for the default bridge network, configure the `"ip"`
key in the `daemon.json` configuration file:

```json
{
  "ip": "127.0.0.1"
}
```

This changes the default binding address to `127.0.0.1` for published container
ports on the default bridge network.
Restart the daemon for this change to take effect.
Alternatively, you can use the `dockerd --ip` flag when starting the daemon.


---

# Docker Engine 17.03 release notes

*Sección: Engine*

## 17.03.3-ce
2018-08-30

### Runtime

* Update go-connections to d217f8e [#28](https://github.com/docker/engine/pull/28)

## 17.03.2-ce
2017-05-29

### Networking

- Fix a concurrency issue preventing network creation [#33273](https://github.com/moby/moby/pull/33273)

### Runtime

- Relabel secrets path to avoid a Permission Denied on selinux enabled systems [#33236](https://github.com/moby/moby/pull/33236) (ref [#32529](https://github.com/moby/moby/pull/32529)
- Fix cases where local volume were not properly relabeled if needed [#33236](https://github.com/moby/moby/pull/33236) (ref [#29428](https://github.com/moby/moby/pull/29428))
- Fix an issue while upgrading if a plugin rootfs was still mounted [#33236](https://github.com/moby/moby/pull/33236) (ref [#32525](https://github.com/moby/moby/pull/32525))
- Fix an issue where volume wouldn't default to the `rprivate` propagation mode [#33236](https://github.com/moby/moby/pull/33236) (ref [#32851](https://github.com/moby/moby/pull/32851))
- Fix a panic that could occur when a volume driver could not be retrieved [#33236](https://github.com/moby/moby/pull/33236) (ref [#32347](https://github.com/moby/moby/pull/32347))
+ Add a warning in `docker info` when the `overlay` or `overlay2` graphdriver is used on a filesystem without `d_type` support [#33236](https://github.com/moby/moby/pull/33236) (ref [#31290](https://github.com/moby/moby/pull/31290))
- Fix an issue with backporting mount spec to older volumes [#33207](https://github.com/moby/moby/pull/33207)
- Fix issue where a failed unmount can lead to data loss on local volume remove [#33120](https://github.com/moby/moby/pull/33120)

### Swarm Mode

- Fix a case where tasks could get killed unexpectedly [#33118](https://github.com/moby/moby/pull/33118)
- Fix an issue preventing to deploy services if the registry cannot be reached despite the needed images being locally present [#33117](https://github.com/moby/moby/pull/33117)

## 17.03.1-ce
2017-03-27

### Remote API (v1.27) & Client

* Fix autoremove on older api [#31692](https://github.com/docker/docker/pull/31692)
* Fix default network customization for a stack [#31258](https://github.com/docker/docker/pull/31258/)
* Correct CPU usage calculation in presence of offline CPUs and newer Linux [#31802](https://github.com/docker/docker/pull/31802)
* Fix issue where service healthcheck is `{}` in remote API [#30197](https://github.com/docker/docker/pull/30197)

### Runtime

* Update runc to 54296cf40ad8143b62dbcaa1d90e520a2136ddfe [#31666](https://github.com/docker/docker/pull/31666)
 * Ignore cgroup2 mountpoints [opencontainers/runc#1266](https://github.com/opencontainers/runc/pull/1266)
* Update containerd to 4ab9917febca54791c5f071a9d1f404867857fcc [#31662](https://github.com/docker/docker/pull/31662) [#31852](https://github.com/docker/docker/pull/31852)
 * Register healtcheck service before calling restore() [docker/containerd#609](https://github.com/docker/containerd/pull/609)
* Fix `docker exec` not working after unattended upgrades that reload apparmor profiles [#31773](https://github.com/docker/docker/pull/31773)
* Fix unmounting layer without merge dir with Overlay2 [#31069](https://github.com/docker/docker/pull/31069)
* Do not ignore "volume in use" errors when force-delete [#31450](https://github.com/docker/docker/pull/31450)

### Swarm Mode

* Update swarmkit to 17756457ad6dc4d8a639a1f0b7a85d1b65a617bb [#31807](https://github.com/docker/docker/pull/31807)
 * Scheduler now correctly considers tasks which have been assigned to a node but aren't yet running [docker/swarmkit#1980](https://github.com/docker/swarmkit/pull/1980)
 * Allow removal of a network when only dead tasks reference it [docker/swarmkit#2018](https://github.com/docker/swarmkit/pull/2018)
 * Retry failed network allocations less aggressively [docker/swarmkit#2021](https://github.com/docker/swarmkit/pull/2021)
 * Avoid network allocation for tasks that are no longer running [docker/swarmkit#2017](https://github.com/docker/swarmkit/pull/2017)
 * Bookkeeping fixes inside network allocator allocator [docker/swarmkit#2019](https://github.com/docker/swarmkit/pull/2019) [docker/swarmkit#2020](https://github.com/docker/swarmkit/pull/2020)

### Windows

* Cleanup HCS on restore [#31503](https://github.com/docker/docker/pull/31503)

## 17.03.0-ce
2017-03-01

> [!IMPORTANT]
>
> Starting with this release, Docker is on a monthly release cycle and uses a new YY.MM versioning scheme to reflect this. Two channels are available: monthly and quarterly. Any given monthly release will only receive security and bugfixes until the next monthly release is available. Quarterly releases receive security and bugfixes for 4 months after initial release. This release includes bugfixes for 1.13.1 but there are no major feature additions and the API version stays the same. Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk.

### Client

* Fix panic in `docker stats --format` [#30776](https://github.com/docker/docker/pull/30776)

### Contrib

* Update various `bash` and `zsh` completion scripts [#30823](https://github.com/docker/docker/pull/30823), [#30945](https://github.com/docker/docker/pull/30945) and more...
* Block obsolete socket families in default seccomp profile - mitigates unpatched kernels' CVE-2017-6074 [#29076](https://github.com/docker/docker/pull/29076)

### Networking

* Fix bug on overlay encryption keys rotation in cross-datacenter swarm [#30727](https://github.com/docker/docker/pull/30727)
* Fix side effect panic in overlay encryption and network control plane communication failure ("No installed keys could decrypt the message") on frequent swarm leader re-election [#25608](https://github.com/docker/docker/pull/25608)
* Several fixes around system responsiveness and datapath programming when using overlay network with external kv-store [docker/libnetwork#1639](https://github.com/docker/libnetwork/pull/1639), [docker/libnetwork#1632](https://github.com/docker/libnetwork/pull/1632) and more...
* Discard incoming plain vxlan packets for encrypted overlay network [#31170](https://github.com/docker/docker/pull/31170)
* Release the network attachment on allocation failure [#31073](https://github.com/docker/docker/pull/31073)
* Fix port allocation when multiple published ports map to the same target port [docker/swarmkit#1835](https://github.com/docker/swarmkit/pull/1835)

### Runtime

* Fix a deadlock in docker logs [#30223](https://github.com/docker/docker/pull/30223)
* Fix CPU spin waiting for log write events [#31070](https://github.com/docker/docker/pull/31070)
* Fix a possible crash when using journald [#31231](https://github.com/docker/docker/pull/31231) [#31263](https://github.com/docker/docker/pull/31263)
* Fix a panic on close of nil channel [#31274](https://github.com/docker/docker/pull/31274)
* Fix duplicate mount point for `--volumes-from` in `docker run` [#29563](https://github.com/docker/docker/pull/29563)
* Fix `--cache-from` does not cache last step [#31189](https://github.com/docker/docker/pull/31189)

### Swarm Mode

* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279)
* Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938)
* Fix extraneous task creations for global services that led to confusing replica counts in `docker service ls` [docker/swarmkit#1957](https://github.com/docker/swarmkit/pull/1957)
* Fix problem that made rolling updates slow when `task-history-limit` was set to 1 [docker/swarmkit#1948](https://github.com/docker/swarmkit/pull/1948)
* Restart tasks elsewhere, if appropriate, when they are shut down as a result of nodes no longer satisfying constraints [docker/swarmkit#1958](https://github.com/docker/swarmkit/pull/1958)
* (experimental)


---

# Docker Engine 17.04 release notes

*Sección: Engine*

## 17.04.0-ce
2017-04-05

### Builder

* Disable container logging for build containers [#29552](https://github.com/docker/docker/pull/29552)
* Fix use of `**/` in `.dockerignore` [#29043](https://github.com/docker/docker/pull/29043)

### Client

+ Sort `docker stack ls` by name [#31085](https://github.com/docker/docker/pull/31085)
+ Flags for specifying bind mount consistency [#31047](https://github.com/docker/docker/pull/31047)
* Output of docker CLI --help is now wrapped to the terminal width [#28751](https://github.com/docker/docker/pull/28751)
* Suppress image digest in docker ps [#30848](https://github.com/docker/docker/pull/30848)
* Hide command options that are related to Windows [#30788](https://github.com/docker/docker/pull/30788)
* Fix `docker plugin install` prompt to accept "enter" for the "N" default [#30769](https://github.com/docker/docker/pull/30769)
+ Add `truncate` function for Go templates [#30484](https://github.com/docker/docker/pull/30484)
* Support expanded syntax of ports in `stack deploy` [#30476](https://github.com/docker/docker/pull/30476)
* Support expanded syntax of mounts in `stack deploy` [#30597](https://github.com/docker/docker/pull/30597) [#31795](https://github.com/docker/docker/pull/31795)
+ Add `--add-host` for docker build [#30383](https://github.com/docker/docker/pull/30383)
+ Add `.CreatedAt` placeholder for `docker network ls --format` [#29900](https://github.com/docker/docker/pull/29900)
* Update order of `--secret-rm` and `--secret-add` [#29802](https://github.com/docker/docker/pull/29802)
+ Add `--filter enabled=true` for `docker plugin ls` [#28627](https://github.com/docker/docker/pull/28627)
+ Add `--format` to `docker service ls` [#28199](https://github.com/docker/docker/pull/28199)
+ Add `publish` and `expose` filter for `docker ps --filter` [#27557](https://github.com/docker/docker/pull/27557)
* Support multiple service IDs on `docker service ps` [#25234](https://github.com/docker/docker/pull/25234)
+ Allow swarm join with `--availability=drain` [#24993](https://github.com/docker/docker/pull/24993)
* Docker inspect now shows "docker-default" when AppArmor is enabled and no other profile was defined [#27083](https://github.com/docker/docker/pull/27083)

### Logging

+ Implement optional ring buffer for container logs [#28762](https://github.com/docker/docker/pull/28762)
+ Add `--log-opt awslogs-create-group=<true|false>` for awslogs (CloudWatch) to support creation of log groups as needed [#29504](https://github.com/docker/docker/pull/29504)
- Fix segfault when using the gcplogs logging driver with a "static" binary [#29478](https://github.com/docker/docker/pull/29478)


### Networking

* Check parameter `--ip`, `--ip6` and `--link-local-ip` in `docker network connect` [#30807](https://github.com/docker/docker/pull/30807)
+ Added support for `dns-search` [#30117](https://github.com/docker/docker/pull/30117)
+ Added --verbose option for docker network inspect to show task details from all swarm nodes [#31710](https://github.com/docker/docker/pull/31710)
* Clear stale datapath encryption states when joining the cluster [docker/libnetwork#1354](https://github.com/docker/libnetwork/pull/1354)
+ Ensure iptables initialization only happens once [docker/libnetwork#1676](https://github.com/docker/libnetwork/pull/1676)
* Fix bad order of iptables filter rules [docker/libnetwork#961](https://github.com/docker/libnetwork/pull/961)
+ Add anonymous container alias to service record on attachable network [docker/libnetwork#1651](https://github.com/docker/libnetwork/pull/1651)
+ Support for `com.docker.network.container_iface_prefix` driver label [docker/libnetwork#1667](https://github.com/docker/libnetwork/pull/1667)
+ Improve network list performance by omitting network details that are not used [#30673](https://github.com/docker/docker/pull/30673)

### Runtime

* Handle paused container when restoring without live-restore set [#31704](https://github.com/docker/docker/pull/31704)
- Do not allow sub second in healthcheck options in Dockerfile [#31177](https://github.com/docker/docker/pull/31177)
* Support name and id prefix in `secret update` [#30856](https://github.com/docker/docker/pull/30856)
* Use binary frame for websocket attach endpoint [#30460](https://github.com/docker/docker/pull/30460)
* Fix linux mount calls not applying propagation type changes [#30416](https://github.com/docker/docker/pull/30416)
* Fix ExecIds leak on failed `exec -i` [#30340](https://github.com/docker/docker/pull/30340)
* Prune named but untagged images if `danglingOnly=true` [#30330](https://github.com/docker/docker/pull/30330)
+ Add daemon flag to set `no_new_priv` as default for unprivileged containers [#29984](https://github.com/docker/docker/pull/29984)
+ Add daemon option `--default-shm-size` [#29692](https://github.com/docker/docker/pull/29692)
+ Support registry mirror config reload [#29650](https://github.com/docker/docker/pull/29650)
- Ignore the daemon log config when building images [#29552](https://github.com/docker/docker/pull/29552)
* Move secret name or ID prefix resolving from client to daemon [#29218](https://github.com/docker/docker/pull/29218)
+ Allow adding rules to `cgroup devices.allow` on container create/run [#22563](https://github.com/docker/docker/pull/22563)
- Fix `cpu.cfs_quota_us` being reset when running `systemd daemon-reload` [#31736](https://github.com/docker/docker/pull/31736)

### Swarm Mode

+ Topology-aware scheduling [#30725](https://github.com/docker/docker/pull/30725)
+ Automatic service rollback on failure [#31108](https://github.com/docker/docker/pull/31108)
+ Worker and manager on the same node are now connected through a UNIX socket [docker/swarmkit#1828](https://github.com/docker/swarmkit/pull/1828), [docker/swarmkit#1850](https://github.com/docker/swarmkit/pull/1850), [docker/swarmkit#1851](https://github.com/docker/swarmkit/pull/1851)
* Improve raft transport package [docker/swarmkit#1748](https://github.com/docker/swarmkit/pull/1748)
* No automatic manager shutdown on demotion/removal [docker/swarmkit#1829](https://github.com/docker/swarmkit/pull/1829)
* Use TransferLeadership to make leader demotion safer [docker/swarmkit#1939](https://github.com/docker/swarmkit/pull/1939)
* Decrease default monitoring period [docker/swarmkit#1967](https://github.com/docker/swarmkit/pull/1967)
+ Add Service logs formatting [#31672](https://github.com/docker/docker/pull/31672)
* Fix service logs API to be able to specify stream [#31313](https://github.com/docker/docker/pull/31313)
+ Add `--stop-signal` for `service create` and `service update` [#30754](https://github.com/docker/docker/pull/30754)
+ Add `--read-only` for `service create` and `service update` [#30162](https://github.com/docker/docker/pull/30162)
+ Renew the context after communicating with the registry [#31586](https://github.com/docker/docker/pull/31586)
+ (experimental) Add `--tail` and `--since` options to `docker service logs` [#31500](https://github.com/docker/docker/pull/31500)
+ (experimental) Add `--no-task-ids` and `--no-trunc` options to `docker service logs` [#31672](https://github.com/docker/docker/pull/31672)

### Windows

* Block pulling Windows images on non-Windows daemons [#29001](https://github.com/docker/docker/pull/29001)


---

# Docker Engine 17.05 release notes

*Sección: Engine*

## 17.05.0-ce
2017-05-04

### Builder

+ Add multi-stage build support [#31257](https://github.com/docker/docker/pull/31257) [#32063](https://github.com/docker/docker/pull/32063)
+ Allow using build-time args (`ARG`) in `FROM` [#31352](https://github.com/docker/docker/pull/31352)
+ Add an option for specifying build target [#32496](https://github.com/docker/docker/pull/32496)
* Accept `-f -` to read Dockerfile from `stdin`, but use local context for building [#31236](https://github.com/docker/docker/pull/31236)
* The values of default build time arguments (e.g `HTTP_PROXY`) are no longer displayed in docker image history unless a corresponding `ARG` instruction is written in the Dockerfile. [#31584](https://github.com/docker/docker/pull/31584)
- Fix setting command if a custom shell is used in a parent image [#32236](https://github.com/docker/docker/pull/32236)
- Fix `docker build --label` when the label includes single quotes and a space [#31750](https://github.com/docker/docker/pull/31750)

### Client

* Add `--mount` flag to `docker run` and `docker create` [#32251](https://github.com/docker/docker/pull/32251)
* Add `--type=secret` to `docker inspect` [#32124](https://github.com/docker/docker/pull/32124)
* Add `--format` option to `docker secret ls` [#31552](https://github.com/docker/docker/pull/31552)
* Add `--filter` option to `docker secret ls` [#30810](https://github.com/docker/docker/pull/30810)
* Add `--filter scope=<swarm|local>` to `docker network ls` [#31529](https://github.com/docker/docker/pull/31529)
* Add `--cpus` support to `docker update` [#31148](https://github.com/docker/docker/pull/31148)
* Add label filter to `docker system prune` and other `prune` commands [#30740](https://github.com/docker/docker/pull/30740)
* `docker stack rm` now accepts multiple stacks as input [#32110](https://github.com/docker/docker/pull/32110)
* Improve `docker version --format` option when the client has downgraded the API version [#31022](https://github.com/docker/docker/pull/31022)
* Prompt when using an encrypted client certificate to connect to a docker daemon [#31364](https://github.com/docker/docker/pull/31364)
* Display created tags on successful `docker build` [#32077](https://github.com/docker/docker/pull/32077)
* Cleanup compose convert error messages [#32087](https://github.com/moby/moby/pull/32087)

### Contrib

+ Add support for building docker debs for Ubuntu 17.04 Zesty on amd64 [#32435](https://github.com/docker/docker/pull/32435)

### Daemon

- Fix `--api-cors-header` being ignored if `--api-enable-cors` is not set [#32174](https://github.com/docker/docker/pull/32174)
- Cleanup docker tmp dir on start [#31741](https://github.com/docker/docker/pull/31741)
- Deprecate `--graph` flag in favor or `--data-root` [#28696](https://github.com/docker/docker/pull/28696)

### Logging

+ Add support for logging driver plugins [#28403](https://github.com/docker/docker/pull/28403)
* Add support for showing logs of individual tasks to `docker service logs`, and add `/task/{id}/logs` REST endpoint [#32015](https://github.com/docker/docker/pull/32015)
* Add `--log-opt env-regex` option to match environment variables using a regular expression [#27565](https://github.com/docker/docker/pull/27565)

### Networking

+ Allow user to replace, and customize the ingress network [#31714](https://github.com/docker/docker/pull/31714)
- Fix UDP traffic in containers not working after the container is restarted [#32505](https://github.com/docker/docker/pull/32505)
- Fix files being written to `/var/lib/docker` if a different data-root is set [#32505](https://github.com/docker/docker/pull/32505)

### Runtime

- Ensure health probe is stopped when a container exits [#32274](https://github.com/docker/docker/pull/32274)

### Swarm Mode

+ Add update/rollback order for services (`--update-order` / `--rollback-order`) [#30261](https://github.com/docker/docker/pull/30261)
+ Add support for synchronous `service create` and `service update` [#31144](https://github.com/docker/docker/pull/31144)
+ Add support for "grace periods" on healthchecks through the `HEALTHCHECK --start-period` and `--health-start-period` flag to
  `docker service create`, `docker service update`, `docker create`, and `docker run` to support containers with an initial startup
  time [#28938](https://github.com/docker/docker/pull/28938)
* `docker service create` now omits fields that are not specified by the user, when possible. This will allow defaults to be applied inside the manager [#32284](https://github.com/docker/docker/pull/32284)
* `docker service inspect` now shows default values for fields that are not specified by the user [#32284](https://github.com/docker/docker/pull/32284)
* Move `docker service logs` out of experimental [#32462](https://github.com/docker/docker/pull/32462)
* Add support for Credential Spec and SELinux to services to the API [#32339](https://github.com/docker/docker/pull/32339)
* Add `--entrypoint` flag to `docker service create` and `docker service update` [#29228](https://github.com/docker/docker/pull/29228)
* Add `--network-add` and `--network-rm` to `docker service update` [#32062](https://github.com/docker/docker/pull/32062)
* Add `--credential-spec` flag to `docker service create` and `docker service update` [#32339](https://github.com/docker/docker/pull/32339)
* Add `--filter mode=<global|replicated>` to `docker service ls` [#31538](https://github.com/docker/docker/pull/31538)
* Resolve network IDs on the client side, instead of in the daemon when creating services [#32062](https://github.com/docker/docker/pull/32062)
* Add `--format` option to `docker node ls` [#30424](https://github.com/docker/docker/pull/30424)
* Add `--prune` option to `docker stack deploy` to remove services that are no longer defined in the docker-compose file [#31302](https://github.com/docker/docker/pull/31302)
* Add `PORTS` column for `docker service ls` when using `ingress` mode [#30813](https://github.com/docker/docker/pull/30813)
- Fix unnecessary re-deploying of tasks when environment-variables are used [#32364](https://github.com/docker/docker/pull/32364)
- Fix `docker stack deploy` not supporting `endpoint_mode` when deploying from a docker compose file [#32333](https://github.com/docker/docker/pull/32333)
- Proceed with startup if cluster component cannot be created to allow recovering from a broken swarm setup [#31631](https://github.com/docker/docker/pull/31631)

### Security

* Allow setting SELinux type or MCS labels when using `--ipc=container:` or `--ipc=host` [#30652](https://github.com/docker/docker/pull/30652)


### Deprecation

- Deprecate `--api-enable-cors` daemon flag. This flag was marked deprecated in Docker 1.6.0 but not listed in deprecated features [#32352](https://github.com/docker/docker/pull/32352)
- Remove Ubuntu 12.04 (Precise Pangolin) as supported platform. Ubuntu 12.04 is EOL, and no longer receives updates [#32520](https://github.com/docker/docker/pull/32520)


---

# Docker Engine 17.06 release notes

*Sección: Engine*

## 17.06.2-ce
2017-09-05

### Client

- Enable TCP keepalive in the client to prevent loss of connection [docker/cli#415](https://github.com/docker/cli/pull/415)

### Runtime

- Devmapper: ensure UdevWait is called after calls to setCookie [moby/moby#33732](https://github.com/moby/moby/pull/33732)
- Aufs: ensure diff layers are correctly removed to prevent leftover files from using up storage [moby/moby#34587](https://github.com/moby/moby/pull/34587)

### Swarm mode

- Ignore PullOptions for running tasks [docker/swarmkit#2351](https://github.com/docker/swarmkit/pull/2351)

## 17.06.1-ce
2017-08-15

### Builder

* Fix a regression, where `ADD` from remote URL's extracted archives [#89](https://github.com/docker/docker-ce/pull/89)
* Fix handling of remote "git@" notation [#100](https://github.com/docker/docker-ce/pull/100)
* Fix copy `--from` conflict with force pull [#86](https://github.com/docker/docker-ce/pull/86)

### Client

* Make pruning volumes optional when running `docker system prune`, and add a `--volumes` flag [#109](https://github.com/docker/docker-ce/pull/109)
* Show progress of replicated tasks before they are assigned [#97](https://github.com/docker/docker-ce/pull/97)
* Fix `docker wait` hanging if the container does not exist [#106](https://github.com/docker/docker-ce/pull/106)
* If `docker swarm ca` is called without the `--rotate` flag, warn if other flags are passed [#110](https://github.com/docker/docker-ce/pull/110)
* Fix API version negotiation not working if the daemon returns an error [#115](https://github.com/docker/docker-ce/pull/115)
* Print an error if "until" filter is combined with "--volumes" on system prune [#154](https://github.com/docker/docker-ce/pull/154)

### Logging

* Fix stderr logging for `journald` and `syslog` [#95](https://github.com/docker/docker-ce/pull/95)
* Fix log readers can block writes indefinitely [#98](https://github.com/docker/docker-ce/pull/98)
* Fix `awslogs` driver repeating last event [#151](https://github.com/docker/docker-ce/pull/151)

### Networking

* Fix issue with driver options not received by network drivers [#127](https://github.com/docker/docker-ce/pull/127)

### Plugins

* Make plugin removes more resilient to failure [#91](https://github.com/docker/docker-ce/pull/91)

### Runtime

* Prevent a `goroutine` leak when `healthcheck` gets stopped [#90](https://github.com/docker/docker-ce/pull/90)
* Do not error on relabel when relabel not supported [#92](https://github.com/docker/docker-ce/pull/92)
* Limit max backoff delay to 2 seconds for GRPC connection [#94](https://github.com/docker/docker-ce/pull/94)
* Fix issue preventing containers to run when memory cgroup was specified due to bug in certain kernels [#102](https://github.com/docker/docker-ce/pull/102)
* Fix container not responding to SIGKILL when paused [#102](https://github.com/docker/docker-ce/pull/102)
* Improve error message if an image for an incompatible OS is loaded [#108](https://github.com/docker/docker-ce/pull/108)
* Fix a handle leak in `go-winio` [#112](https://github.com/docker/docker-ce/pull/112)
* Fix issue upon upgrade, preventing docker from showing running containers when `--live-restore` is enabled [#117](https://github.com/docker/docker-ce/pull/117)
* Fix bug where services using secrets would fail to start on daemons using the `userns-remap` feature [#121](https://github.com/docker/docker-ce/pull/121)
* Fix error handling with `not-exist` errors on remove [#142](https://github.com/docker/docker-ce/pull/142)
* Fix REST API Swagger representation cannot be loaded with SwaggerUI [#156](https://github.com/docker/docker-ce/pull/156)

### Security

* Redact secret data on secret creation [#99](https://github.com/docker/docker-ce/pull/99)

### Swarm mode

* Do not add duplicate platform information to service spec [#107](https://github.com/docker/docker-ce/pull/107)
* Cluster update and memory issue fixes [#114](https://github.com/docker/docker-ce/pull/114)
* Changing get network request to return predefined network in swarm [#150](https://github.com/docker/docker-ce/pull/150)

## 17.06.0-ce
2017-06-28

> [!NOTE]: Docker 17.06.0 has an issue in the image builder causing a change in the behavior
> of the `ADD` instruction of Dockerfile when referencing a remote `.tar.gz` file. The issue will be
> fixed in Docker 17.06.1.

> [!NOTE]: Starting with Docker CE 17.06, Ubuntu packages are also available
> for IBM Z using the s390x architecture.

> [!NOTE]: Docker 17.06 by default disables communication with legacy (v1)
> registries. If you require interaction with registries that have not yet
> migrated to the v2 protocol, set the `--disable-legacy-registry=false` daemon
> option. Interaction with v1 registries will be removed in Docker 17.12.

### Builder

+ Add `--iidfile` option to docker build. It allows specifying a location where to save the resulting image ID
+ Allow specifying any remote ref in git checkout URLs [#32502](https://github.com/moby/moby/pull/32502)

### Client

+ Add `--format` option to `docker stack ls` [#31557](https://github.com/moby/moby/pull/31557)
+ Add support for labels in compose initiated builds [#32632](https://github.com/moby/moby/pull/32632) [#32972](https://github.com/moby/moby/pull/32972)
+ Add `--format` option to `docker history` [#30962](https://github.com/moby/moby/pull/30962)
+ Add `--format` option to `docker system df` [#31482](https://github.com/moby/moby/pull/31482)
+ Allow specifying Nameservers and Search Domains in stack files [#32059](https://github.com/moby/moby/pull/32059)
+ Add support for `read_only` service to `docker stack deploy` [#docker/cli/73](https://github.com/docker/cli/pull/73)
* Display Swarm cluster and node TLS information [#docker/cli/44](https://github.com/docker/cli/pull/44)
+ Add support for placement preference to `docker stack deploy` [#docker/cli/35](https://github.com/docker/cli/pull/35)
+ Add new `ca` subcommand to `docker swarm` to allow managing a swarm CA [#docker/cli/48](https://github.com/docker/cli/pull/48)
+ Add credential-spec to compose [#docker/cli/71](https://github.com/docker/cli/pull/71)
+ Add support for csv format options to `--network` and `--network-add` [#docker/cli/62](https://github.com/docker/cli/pull/62) [#33130](https://github.com/moby/moby/pull/33130)
- Fix stack compose bind-mount volumes on Windows [#docker/cli/136](https://github.com/docker/cli/pull/136)
- Correctly handle a Docker daemon without registry info [#docker/cli/126](https://github.com/docker/cli/pull/126)
+ Allow `--detach` and `--quiet` flags when using --rollback [#docker/cli/144](https://github.com/docker/cli/pull/144)
+ Remove deprecated `--email` flag from `docker login` [#docker/cli/143](https://github.com/docker/cli/pull/143)
* Adjusted `docker stats` memory output [#docker/cli/80](https://github.com/docker/cli/pull/80)

### Distribution

* Select digest over tag when both are provided during a pull [#33214](https://github.com/moby/moby/pull/33214)

### Logging

+ Add monitored resource type metadata for GCP logging driver [#32930](https://github.com/moby/moby/pull/32930)
+ Add multiline processing to the AWS CloudWatch logs driver [#30891](https://github.com/moby/moby/pull/30891)

### Networking

+ Add Support swarm-mode services with node-local networks such as macvlan, ipvlan, bridge, host [#32981](https://github.com/moby/moby/pull/32981)
+ Pass driver-options to network drivers on service creation [#32981](https://github.com/moby/moby/pull/33130)
+ Isolate Swarm Control-plane traffic from Application data traffic using --data-path-addr [#32717](https://github.com/moby/moby/pull/32717)
* Several improvements to Service Discovery [#docker/libnetwork/1796](https://github.com/docker/libnetwork/pull/1796)

### Packaging

+ Rely on `container-selinux` on Centos/Fedora/RHEL when available [#32437](https://github.com/moby/moby/pull/32437)

### Runtime

+ Add build & engine info prometheus metrics [#32792](https://github.com/moby/moby/pull/32792)
* Update containerd to d24f39e203aa6be4944f06dd0fe38a618a36c764 [#33007](https://github.com/moby/moby/pull/33007)
* Update runc to 992a5be178a62e026f4069f443c6164912adbf09 [#33007](https://github.com/moby/moby/pull/33007)
+ Add option to auto-configure blkdev for devmapper [#31104](https://github.com/moby/moby/pull/31104)
+ Add log driver list to `docker info` [#32540](https://github.com/moby/moby/pull/32540)
+ Add API endpoint to allow retrieving an image manifest [#32061](https://github.com/moby/moby/pull/32061)
* Do not remove container from memory on error with `forceremove` [#31012](https://github.com/moby/moby/pull/31012)
+ Add support for metric plugins [#32874](https://github.com/moby/moby/pull/32874)
* Return an error when an invalid filter is given to `prune` commands [#33023](https://github.com/moby/moby/pull/33023)
+ Add daemon option to allow pushing foreign layers [#33151](https://github.com/moby/moby/pull/33151)
- Fix an issue preventing containerd to be restarted after it died [#32986](https://github.com/moby/moby/pull/32986)
+ Add cluster events to Docker event stream. [#32421](https://github.com/moby/moby/pull/32421)
+ Add support for DNS search on windows [#33311](https://github.com/moby/moby/pull/33311)
* Upgrade to Go 1.8.3 [#33387](https://github.com/moby/moby/pull/33387)
- Prevent a containerd crash when journald is restarted [#containerd/930](https://github.com/containerd/containerd/pull/930)
- Fix healthcheck failures due to invalid environment variables [#33249](https://github.com/moby/moby/pull/33249)
- Prevent a directory to be created in lieu of the daemon socket when a container mounting it is to be restarted during a shutdown [#30348](https://github.com/moby/moby/pull/33330)
- Prevent a container to be restarted upon stop if its stop signal is set to `SIGKILL` [#33335](https://github.com/moby/moby/pull/33335)
- Ensure log drivers get passed the same filename to both StartLogging and StopLogging endpoints [#33583](https://github.com/moby/moby/pull/33583)
- Remove daemon data structure dump on `SIGUSR1` to avoid a panic [#33598](https://github.com/moby/moby/pull/33598)

### Security

+ Allow personality with UNAME26 bit set in default seccomp profile [#32965](https://github.com/moby/moby/pull/32965)

### Swarm Mode

+ Add an option to allow specifying a different interface for the data traffic (as opposed to control traffic) [#32717](https://github.com/moby/moby/pull/32717)
* Allow specifying a secret location within the container [#32571](https://github.com/moby/moby/pull/32571)
+ Add support for secrets on Windows [#32208](https://github.com/moby/moby/pull/32208)
+ Add TLS Info to swarm info and node info endpoint [#32875](https://github.com/moby/moby/pull/32875)
+ Add support for services to carry arbitrary config objects [#32336](https://github.com/moby/moby/pull/32336), [#docker/cli/45](https://github.com/docker/cli/pull/45),[#33169](https://github.com/moby/moby/pull/33169)
+ Add API to rotate swarm CA certificate [#32993](https://github.com/moby/moby/pull/32993)
* Service digest pining is now handled client side [#32388](https://github.com/moby/moby/pull/32388), [#33239](https://github.com/moby/moby/pull/33239)
+ Placement now also take platform in account [#33144](https://github.com/moby/moby/pull/33144)
- Fix possible hang when joining fails [#docker-ce/19](https://github.com/docker/docker-ce/pull/19)
- Fix an issue preventing external CA to be accepted [#33341](https://github.com/moby/moby/pull/33341)
- Fix possible orchestration panic in mixed version clusters [#swarmkit/2233](https://github.com/docker/swarmkit/pull/2233)
- Avoid assigning duplicate IPs during initialization [#swarmkit/2237](https://github.com/docker/swarmkit/pull/2237)

### Deprecation

* Disable legacy registry (v1) by default [#33629](https://github.com/moby/moby/pull/33629)


---

# Docker Engine 17.07 release notes

*Sección: Engine*

## 17.07.0-ce
2017-08-29

### API & Client

* Add support for proxy configuration in config.json [docker/cli#93](https://github.com/docker/cli/pull/93)
* Enable pprof/debug endpoints by default [moby/moby#32453](https://github.com/moby/moby/pull/32453)
* Passwords can now be passed using `STDIN` using the new  `--password-stdin` flag on `docker login` [docker/cli#271](https://github.com/docker/cli/pull/271)
+ Add `--detach` to docker scale [docker/cli#243](https://github.com/docker/cli/pull/243)
* Prevent `docker logs --no-stream` from hanging due to non-existing containers [moby/moby#34004](https://github.com/moby/moby/pull/34004)
- Fix `docker stack ps` printing error to `stdout` instead of `stderr` [docker/cli#298](https://github.com/docker/cli/pull/298)
* Fix progress bar being stuck on `docker service create` if an error occurs during deploy [docker/cli#259](https://github.com/docker/cli/pull/259)
* Improve presentation of progress bars in interactive mode [docker/cli#260](https://github.com/docker/cli/pull/260) [docker/cli#237](https://github.com/docker/cli/pull/237)
* Print a warning if `docker login --password` is used, and recommend `--password-stdin` [docker/cli#270](https://github.com/docker/cli/pull/270)
* Make API version negotiation more robust [moby/moby#33827](https://github.com/moby/moby/pull/33827)
* Hide `--detach` when connected to daemons older than Docker 17.05 [docker/cli#219](https://github.com/docker/cli/pull/219)
+ Add `scope` filter in `GET /networks/(id or name)` [moby/moby#33630](https://github.com/moby/moby/pull/33630)

### Builder

* Implement long running interactive session and sending build context incrementally [moby/moby#32677](https://github.com/moby/moby/pull/32677) [docker/cli#231](https://github.com/docker/cli/pull/231) [moby/moby#33859](https://github.com/moby/moby/pull/33859)
* Warn on empty continuation lines [moby/moby#33719](https://github.com/moby/moby/pull/33719)
- Fix `.dockerignore` entries with a leading `/` not matching anything [moby/moby#32088](https://github.com/moby/moby/pull/32088)

### Logging

- Fix wrong filemode for rotate log files [moby/moby#33926](https://github.com/moby/moby/pull/33926)
- Fix stderr logging for journald and syslog [moby/moby#33832](https://github.com/moby/moby/pull/33832)

### Runtime

* Allow stopping of paused container [moby/moby#34027](https://github.com/moby/moby/pull/34027)
+ Add quota support for the overlay2 storage driver [moby/moby#32977](https://github.com/moby/moby/pull/32977)
* Remove container locks on `docker ps` [moby/moby#31273](https://github.com/moby/moby/pull/31273)
* Store container names in memdb [moby/moby#33886](https://github.com/moby/moby/pull/33886)
* Fix race condition between `docker exec` and `docker pause` [moby/moby#32881](https://github.com/moby/moby/pull/32881)
* Devicemapper: Rework logging and add `--storage-opt dm.libdm_log_level` [moby/moby#33845](https://github.com/moby/moby/pull/33845)
* Devicemapper: Prevent "device in use" errors if deferred removal is enabled, but not deferred deletion [moby/moby#33877](https://github.com/moby/moby/pull/33877)
* Devicemapper: Use KeepAlive to prevent tasks being garbage-collected while still in use [moby/moby#33376](https://github.com/moby/moby/pull/33376)
* Report intermediate prune results if prune is cancelled [moby/moby#33979](https://github.com/moby/moby/pull/33979)
- Fix run `docker rename <container-id> new_name` concurrently resulting in the having multiple names [moby/moby#33940](https://github.com/moby/moby/pull/33940)
* Fix file-descriptor leak and error handling [moby/moby#33713](https://github.com/moby/moby/pull/33713)
- Fix SIGSEGV when running containers [docker/cli#303](https://github.com/docker/cli/pull/303)
* Prevent a goroutine leak when healthcheck gets stopped [moby/moby#33781](https://github.com/moby/moby/pull/33781)
* Image: Improve store locking [moby/moby#33755](https://github.com/moby/moby/pull/33755)
* Fix Btrfs quota groups not being removed when container is destroyed [moby/moby#29427](https://github.com/moby/moby/pull/29427)
* Libcontainerd: fix defunct containerd processes not being properly reaped [moby/moby#33419](https://github.com/moby/moby/pull/33419)
* Preparations for Linux Containers on Windows
  * LCOW: Dedicated scratch space for service VM utilities [moby/moby#33809](https://github.com/moby/moby/pull/33809)
  * LCOW: Support most operations excluding remote filesystem [moby/moby#33241](https://github.com/moby/moby/pull/33241) [moby/moby#33826](https://github.com/moby/moby/pull/33826)
  * LCOW: Change directory from lcow to "Linux Containers" [moby/moby#33835](https://github.com/moby/moby/pull/33835)
  * LCOW: pass command arguments without extra quoting [moby/moby#33815](https://github.com/moby/moby/pull/33815)
  * LCOW: Updates necessary due to platform schema change [moby/moby#33785](https://github.com/moby/moby/pull/33785)

### Swarm mode

* Initial support for pluggable secret backends [moby/moby#34157](https://github.com/moby/moby/pull/34157) [moby/moby#34123](https://github.com/moby/moby/pull/34123)
* Sort swarm stacks and nodes using natural sorting [docker/cli#315](https://github.com/docker/cli/pull/315)
* Make engine support cluster config event [moby/moby#34032](https://github.com/moby/moby/pull/34032)
* Only pass a join address when in the process of joining a cluster [moby/moby#33361](https://github.com/moby/moby/pull/33361)
* Fix error during service creation if a network with the same name exists both as "local" and "swarm" scoped network [docker/cli#184](https://github.com/docker/cli/pull/184)
* (experimental) Add support for plugins on swarm [moby/moby#33575](https://github.com/moby/moby/pull/33575)


---

# Docker Engine 17.09 release notes

*Sección: Engine*

## 17.09.1-ce
2017-12-07

### Builder

- Fix config leakage on shared parent stage [moby/moby#33753](https://github.com/moby/moby/issues/33753)
- Warn on empty continuation lines only, not on comment-only lines [moby/moby#35004](https://github.com/moby/moby/pull/35004)

### Client

- Set API version on Client even when Ping fails [docker/cli#546](https://github.com/docker/cli/pull/546)

### Networking

- Overlay fix for transient IP reuse [docker/libnetwork#2016](https://github.com/docker/libnetwork/pull/2016)
- Fix reapTime logic in NetworkDB and handle DNS cleanup for attachable container [docker/libnetwork#2017](https://github.com/docker/libnetwork/pull/2017)
- Disable hostname lookup on chain exists check [docker/libnetwork#2019](https://github.com/docker/libnetwork/pull/2019)
- Fix lint issues [docker/libnetwork#2020](https://github.com/docker/libnetwork/pull/2020)
- Restore error type in FindNetwork [moby/moby#35634](https://github.com/moby/moby/pull/35634)

### Runtime

- Protect `health monitor` Go channel [moby/moby#35482](https://github.com/moby/moby/pull/35482)
- Fix leaking container/exec state [moby/moby#35484](https://github.com/moby/moby/pull/35484)
- Add /proc/scsi to masked paths (patch to work around [CVE-2017-16539](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-16539) [moby/moby/#35399](https://github.com/moby/moby/pull/35399)
- Vendor tar-split: fix to prevent memory exhaustion issue that could crash Docker daemon [moby/moby/#35424](https://github.com/moby/moby/pull/35424) Fixes [CVE-2017-14992](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-14992)
- Fix P/Z HubPullSuite tests  [moby/moby#34837](https://github.com/moby/moby/pull/34837)
+ Windows: Add support for version filtering on pull [moby/moby#35090](https://github.com/moby/moby/pull/35090)
- Windows: Stop filtering Windows manifest lists by version [moby/moby#35117](https://github.com/moby/moby/pull/35117)
- Use rslave instead of rprivate in chroot archive [moby/moby/#35217](https://github.com/moby/moby/pull/35217)
- Remove container rootfs mountPath after unmount [moby/moby#34573](https://github.com/moby/moby/pull/34573)
- Fix honoring tmpfs size of user /dev/shm mount [moby/moby#35316](https://github.com/moby/moby/pull/35316)
- Don't abort when setting may_detach_mounts (log the error instead)  [moby/moby#35172](https://github.com/moby/moby/pull/35172)
- Fix version comparison when negotiating the API version [moby/moby#35008](https://github.com/moby/moby/pull/35008)

### Swarm mode

* Increase gRPC request timeout when sending snapshots [docker/swarmkit#2404](https://github.com/docker/swarmkit/pull/2404)
- Fix node filtering when there is no log driver [docker/swarmkit#2442](https://github.com/docker/swarmkit/pull/2442)
- Add an error on attempt to change cluster name [docker/swarmkit/#2454](https://github.com/docker/swarmkit/pull/2454)
- Delete node attachments when node is removed [docker/swarmkit/#2456](https://github.com/docker/swarmkit/pull/2456)
- Provide custom gRPC dialer to override default proxy dialer [docker/swarmkit/#2457](https://github.com/docker/swarmkit/pull/2457)
- Avoids recursive readlock on swarm info [moby/moby#35388](https://github.com/moby/moby/pull/35388)

## 17.09.0-ce
2017-09-26

### Builder

+ Add `--chown` flag to `ADD/COPY` commands in Dockerfile [moby/moby#34263](https://github.com/moby/moby/pull/34263)
* Fix cloning unneeded files while building from git repositories [moby/moby#33704](https://github.com/moby/moby/pull/33704)

### Client

* Allow extension fields in the v3.4 version of the compose format [docker/cli#452](https://github.com/docker/cli/pull/452)
* Make compose file allow to specify names for non-external volume [docker/cli#306](https://github.com/docker/cli/pull/306)
* Support `--compose-file -` as stdin [docker/cli#347](https://github.com/docker/cli/pull/347)
* Support `start_period` for healthcheck in Docker Compose [docker/cli#475](https://github.com/docker/cli/pull/475)
+ Add support for `stop-signal` in docker stack commands [docker/cli#388](https://github.com/docker/cli/pull/388)
+ Add support for update order in compose deployments [docker/cli#360](https://github.com/docker/cli/pull/360)
+ Add ulimits to unsupported compose fields [docker/cli#482](https://github.com/docker/cli/pull/482)
+ Add `--format` to `docker-search` [docker/cli#440](https://github.com/docker/cli/pull/440)
* Show images digests when `{{.Digest}}` is in format [docker/cli#439](https://github.com/docker/cli/pull/439)
* Print output of `docker stack rm` on `stdout` instead of `stderr` [docker/cli#491](https://github.com/docker/cli/pull/491)
- Fix `docker history --format {{json .}}` printing human-readable timestamps instead of ISO8601 when `--human=true` [docker/cli#438](https://github.com/docker/cli/pull/438)
- Fix idempotence of `docker stack deploy` when secrets or configs are used [docker/cli#509](https://github.com/docker/cli/pull/509)
- Fix presentation of random host ports [docker/cli#404](https://github.com/docker/cli/pull/404)
- Fix redundant service restarts when service created with multiple secrets [moby/moby#34746](https://github.com/moby/moby/issues/34746)

### Logging

- Fix Splunk logger not transmitting log data when tag is empty and raw-mode is used [moby/moby#34520](https://github.com/moby/moby/pull/34520)

### Networking

+ Add the control plane MTU option in the daemon config [moby/moby#34103](https://github.com/moby/moby/pull/34103)
+ Add service virtual IP to sandbox's loopback address [docker/libnetwork#1877](https://github.com/docker/libnetwork/pull/1877)

### Runtime

* Graphdriver: promote overlay2 over aufs [moby/moby#34430](https://github.com/moby/moby/pull/34430)
* LCOW: Additional flags for VHD boot [moby/moby#34451](https://github.com/moby/moby/pull/34451)
* LCOW: Don't block export [moby/moby#34448](https://github.com/moby/moby/pull/34448)
* LCOW: Dynamic sandbox management [moby/moby#34170](https://github.com/moby/moby/pull/34170)
* LCOW: Force Hyper-V Isolation [moby/moby#34468](https://github.com/moby/moby/pull/34468)
* LCOW: Move toolsScratchPath to /tmp [moby/moby#34396](https://github.com/moby/moby/pull/34396)
* LCOW: Remove hard-coding [moby/moby#34398](https://github.com/moby/moby/pull/34398)
* LCOW: WORKDIR correct handling [moby/moby#34405](https://github.com/moby/moby/pull/34405)
* Windows: named pipe mounts [moby/moby#33852](https://github.com/moby/moby/pull/33852)
- Fix "permission denied" errors when accessing volume with SELinux enforcing mode [moby/moby#34684](https://github.com/moby/moby/pull/34684)
- Fix layers size reported as `0` in `docker system df` [moby/moby#34826](https://github.com/moby/moby/pull/34826)
- Fix some "device or resource busy" errors when removing containers on RHEL 7.4 based kernels [moby/moby#34886](https://github.com/moby/moby/pull/34886)

### Swarm mode

* Include whether the managers in the swarm are autolocked as part of `docker info` [docker/cli#471](https://github.com/docker/cli/pull/471)
+ Add 'docker service rollback' subcommand [docker/cli#205](https://github.com/docker/cli/pull/205)
- Fix managers failing to join if the gRPC snapshot is larger than 4MB [docker/swarmkit#2375](https://github.com/docker/swarmkit/pull/2375)
- Fix "permission denied" errors for configuration file in SELinux-enabled containers [moby/moby#34732](https://github.com/moby/moby/pull/34732)
- Fix services failing to deploy on ARM nodes [moby/moby#34021](https://github.com/moby/moby/pull/34021)

### Packaging

+ Build scripts for ppc64el on Ubuntu [docker/docker-ce-packaging#43](https://github.com/docker/docker-ce-packaging/pull/43)

### Deprecation

+ Remove deprecated `--enable-api-cors` daemon flag [moby/moby#34821](https://github.com/moby/moby/pull/34821)


---

# Docker Engine 17.10 release notes

*Sección: Engine*

## 17.10.0-ce
2017-10-17

> [!IMPORTANT]: Starting with this release, `docker service create`, `docker service update`,
`docker service scale` and `docker service rollback` use non-detached mode as default,
use `--detach` to keep the old behaviour.

### Builder

* Reset uid/gid to 0 in uploaded build context to share build cache with other clients [docker/cli#513](https://github.com/docker/cli/pull/513)
+ Add support for `ADD` urls without any sub path [moby/moby#34217](https://github.com/moby/moby/pull/34217)

### Client

* Move output of `docker stack rm` to stdout [docker/cli#491](https://github.com/docker/cli/pull/491)
* Use natural sort for secrets and configs in cli [docker/cli#307](https://github.com/docker/cli/pull/307)
* Use non-detached mode as default for `docker service` commands [docker/cli#525](https://github.com/docker/cli/pull/525)
* Set APIVersion on the client, even when Ping fails [docker/cli#546](https://github.com/docker/cli/pull/546)
- Fix loader error with different build syntax in `docker stack deploy` [docker/cli#544](https://github.com/docker/cli/pull/544)
* Change the default output format for `docker container stats` to show `CONTAINER ID` and `NAME` [docker/cli#565](https://github.com/docker/cli/pull/565)
+ Add `--no-trunc` flag to `docker container stats` [docker/cli#565](https://github.com/docker/cli/pull/565)
+ Add experimental `docker trust`: `view`, `revoke`, `sign` subcommands [docker/cli#472](https://github.com/docker/cli/pull/472)
- Various doc and shell completion fixes [docker/cli#610](https://github.com/docker/cli/pull/610) [docker/cli#611](https://github.com/docker/cli/pull/611) [docker/cli#618](https://github.com/docker/cli/pull/618) [docker/cli#580](https://github.com/docker/cli/pull/580) [docker/cli#598](https://github.com/docker/cli/pull/598) [docker/cli#603](https://github.com/docker/cli/pull/603)

### Networking

* Enabling ILB/ELB on windows using per-node, per-network LB endpoint [moby/moby#34674](https://github.com/moby/moby/pull/34674)
* Overlay fix for transient IP reuse [docker/libnetwork#1935](https://github.com/docker/libnetwork/pull/1935)
* Serializing bitseq alloc [docker/libnetwork#1788](https://github.com/docker/libnetwork/pull/1788)
- Disable hostname lookup on chain exists check [docker/libnetwork#1974](https://github.com/docker/libnetwork/pull/1974)

### Runtime

* LCOW: Add UVM debuggability by grabbing logs before tear-down [moby/moby#34846](https://github.com/moby/moby/pull/34846)
* LCOW: Prepare work for bind mounts [moby/moby#34258](https://github.com/moby/moby/pull/34258)
* LCOW: Support for docker cp, ADD/COPY on build [moby/moby#34252](https://github.com/moby/moby/pull/34252)
* LCOW: VHDX boot to readonly [moby/moby#34754](https://github.com/moby/moby/pull/34754)
* Volume: evaluate symlinks before relabeling mount source [moby/moby#34792](https://github.com/moby/moby/pull/34792)
- Fixing ‘docker cp’ to allow new target file name in a host symlinked directory [moby/moby#31993](https://github.com/moby/moby/pull/31993)
+ Add support for Windows version filtering on pull [moby/moby#35090](https://github.com/moby/moby/pull/35090)

### Swarm mode

* Produce an error if `docker swarm init --force-new-cluster` is executed on worker nodes [moby/moby#34881](https://github.com/moby/moby/pull/34881)
+ Add support for `.Node.Hostname` templating in swarm services [moby/moby#34686](https://github.com/moby/moby/pull/34686)
* Increase gRPC request timeout to 20 seconds for sending snapshots [docker/swarmkit#2391](https://github.com/docker/swarmkit/pull/2391)
- Do not filter nodes if logdriver is set to `none` [docker/swarmkit#2396](https://github.com/docker/swarmkit/pull/2396)
+ Adding ipam options to ipam driver requests [docker/swarmkit#2324](https://github.com/docker/swarmkit/pull/2324)


---

# Docker Engine 17.11 release notes

*Sección: Engine*

## 17.11.0-ce
2017-11-20

> [!IMPORTANT]
> Docker CE 17.11 is the first Docker release based on
> [containerd 1.0 beta](https://github.com/containerd/containerd/releases/tag/v1.0.0-beta.2).
> Docker CE 17.11 and later don't recognize containers started with previous
> Docker versions. If you use Live Restore, you must stop all containers before
> upgrading to Docker CE 17.11. If you don't, any containers started by Docker
> versions that predate 17.11 aren't recognized by Docker after the upgrade and
> keep running, un-managed, on the system.

### Builder

* Test & Fix build with rm/force-rm matrix [moby/moby#35139](https://github.com/moby/moby/pull/35139)
- Fix build with `--stream` with a large context [moby/moby#35404](https://github.com/moby/moby/pull/35404)

### Client

* Hide help flag from help output [docker/cli#645](https://github.com/docker/cli/pull/645)
* Support parsing of named pipes for compose volumes [docker/cli#560](https://github.com/docker/cli/pull/560)
* [Compose] Cast values to expected type after interpolating values [docker/cli#601](https://github.com/docker/cli/pull/601)
+ Add output for "secrets" and "configs" on `docker stack deploy` [docker/cli#593](https://github.com/docker/cli/pull/593)
- Fix flag description for `--host-add` [docker/cli#648](https://github.com/docker/cli/pull/648)
* Do not truncate ID on docker service ps --quiet [docker/cli#579](https://github.com/docker/cli/pull/579)

### Deprecation

* Update bash completion and deprecation for synchronous service updates [docker/cli#610](https://github.com/docker/cli/pull/610)

### Logging

* copy to log driver's bufsize, fixes #34887 [moby/moby#34888](https://github.com/moby/moby/pull/34888)
+ Add TCP support for GELF log driver [moby/moby#34758](https://github.com/moby/moby/pull/34758)
+ Add credentials endpoint option for awslogs driver [moby/moby#35055](https://github.com/moby/moby/pull/35055)

### Networking

- Fix network name masking network ID on delete [moby/moby#34509](https://github.com/moby/moby/pull/34509)
- Fix returned error code for network creation from 500 to 409 [moby/moby#35030](https://github.com/moby/moby/pull/35030)
- Fix tasks fail with error "Unable to complete atomic operation, key modified" [docker/libnetwork#2004](https://github.com/docker/libnetwork/pull/2004)

### Runtime

* Switch to Containerd 1.0 client [moby/moby#34895](https://github.com/moby/moby/pull/34895)
* Increase container default shutdown timeout on Windows [moby/moby#35184](https://github.com/moby/moby/pull/35184)
* LCOW: API: Add `platform` to /images/create and /build [moby/moby#34642](https://github.com/moby/moby/pull/34642)
* Stop filtering Windows manifest lists by version [moby/moby#35117](https://github.com/moby/moby/pull/35117)
* Use windows console mode constants from Azure/go-ansiterm [moby/moby#35056](https://github.com/moby/moby/pull/35056)
* Windows Daemon should respect DOCKER_TMPDIR [moby/moby#35077](https://github.com/moby/moby/pull/35077)
* Windows: Fix startup logging [moby/moby#35253](https://github.com/moby/moby/pull/35253)
+ Add support for Windows version filtering on pull [moby/moby#35090](https://github.com/moby/moby/pull/35090)
- Fixes LCOW after containerd 1.0 introduced regressions [moby/moby#35320](https://github.com/moby/moby/pull/35320)
* ContainerWait on remove: don't stuck on rm fail [moby/moby#34999](https://github.com/moby/moby/pull/34999)
* oci: obey CL_UNPRIVILEGED for user namespaced daemon [moby/moby#35205](https://github.com/moby/moby/pull/35205)
* Don't abort when setting may_detach_mounts [moby/moby#35172](https://github.com/moby/moby/pull/35172)
- Fix panic on get container pid when live restore containers [moby/moby#35157](https://github.com/moby/moby/pull/35157)
- Mask `/proc/scsi` path for containers to prevent removal of devices (CVE-2017-16539) [moby/moby#35399](https://github.com/moby/moby/pull/35399)
* Update to github.com/vbatts/tar-split@v0.10.2 (CVE-2017-14992) [moby/moby#35424](https://github.com/moby/moby/pull/35424)

### Swarm Mode

* Modifying integration test due to new ipam options in swarmkit [moby/moby#35103](https://github.com/moby/moby/pull/35103)
- Fix deadlock on getting swarm info [moby/moby#35388](https://github.com/moby/moby/pull/35388)
+ Expand the scope of the `Err` field in `TaskStatus` to also cover non-terminal errors that block the task from progressing [docker/swarmkit#2287](https://github.com/docker/swarmkit/pull/2287)

### Packaging

+ Build packages for Debian 10 (Buster) [docker/docker-ce-packaging#50](https://github.com/docker/docker-ce-packaging/pull/50)
+ Build packages for Ubuntu 17.10 (Artful) [docker/docker-ce-packaging#55](https://github.com/docker/docker-ce-packaging/pull/55)


---

# Docker Engine 17.12 release notes

*Sección: Engine*

## 17.12.1-ce
2018-02-27

### Client
- Fix `node-generic-resource` typo [moby/moby#35970](https://github.com/moby/moby/pull/35970) and [moby/moby#36125](https://github.com/moby/moby/pull/36125)
* Return errors from daemon on stack deploy configs create/update [docker/cli#757](https://github.com/docker/cli/pull/757)

### Logging
- awslogs: fix batch size calculation for large logs [moby/moby#35726](https://github.com/moby/moby/pull/35726)
* Support a proxy in splunk log driver [moby/moby#36220](https://github.com/moby/moby/pull/36220)

### Networking
- Fix ingress network when upgrading from 17.09 to 17.12 [moby/moby#36003](https://github.com/moby/moby/pull/36003)
* Add verbose info to partial overlay ID [moby/moby#35989](https://github.com/moby/moby/pull/35989)
- Fix IPv6 networking being deconfigured if live-restore is being enabled [docker/libnetwork#2043](https://github.com/docker/libnetwork/pull/2043)
- Fix watchMiss thread context [docker/libnetwork#2051](https://github.com/docker/libnetwork/pull/2051)

### Packaging
- Set TasksMax in docker.service [docker/docker-ce-packaging#78](https://github.com/docker/docker-ce-packaging/pull/78)

### Runtime
* Bump Golang to 1.9.4
* Bump containerd to 1.0.1
- Fix dockerd not being able to reconnect to containerd when it is restarted [moby/moby#36173](https://github.com/moby/moby/pull/36173)
- Fix containerd events from being processed twice [moby/moby#35891](https://github.com/moby/moby/issues/35891)
- Fix vfs graph driver failure to initialize because of failure to setup fs quota [moby/moby#35827](https://github.com/moby/moby/pull/35827)
- Fix regression of health check not using container's working directory [moby/moby#35845](https://github.com/moby/moby/pull/35845)
- Honor `DOCKER_RAMDISK` with containerd 1.0 [moby/moby#35957](https://github.com/moby/moby/pull/35957)
- Update runc to fix hang during start and exec [moby/moby#36097](https://github.com/moby/moby/pull/36097)
- Windows: Vendor of Microsoft/hcsshim @v.0.6.8 partial fix for import layer failing [moby/moby#35924](https://github.com/moby/moby/pull/35924)
* Do not make graphdriver homes private mounts [moby/moby#36047](https://github.com/moby/moby/pull/36047)
* Use rslave propagation for mounts from daemon root [moby/moby#36055](https://github.com/moby/moby/pull/36055)
* Set daemon root to use shared mount propagation [moby/moby#36096](https://github.com/moby/moby/pull/36096)
* Validate that mounted paths exist when container is started, not just during creation  [moby/moby#35833](https://github.com/moby/moby/pull/35833)
* Add `REMOVE` and `ORPHANED` to TaskState [moby/moby#36146](https://github.com/moby/moby/pull/36146)
- Fix issue where network inspect does not show Created time for networks in swarm scope [moby/moby#36095](https://github.com/moby/moby/pull/36095)
* Nullify container read write layer upon release [moby/moby#36130](https://github.com/moby/moby/pull/36160) and [moby/moby#36343](https://github.com/moby/moby/pull/36242)

### Swarm
* Remove watchMiss from swarm mode [docker/libnetwork#2047](https://github.com/docker/libnetwork/pull/2047)

### Known Issues
* Health check no longer uses the container's working directory [moby/moby#35843](https://github.com/moby/moby/issues/35843)
* Errors not returned from client in stack deploy configs [moby/moby#757](https://github.com/docker/cli/pull/757)
* Docker cannot use memory limit when using systemd options [moby/moby#35123](https://github.com/moby/moby/issues/35123)

## 17.12.0-ce
2017-12-27

### Known Issues
* AWS logs batch size calculation [moby/moby#35726](https://github.com/moby/moby/pull/35726)
* Health check no longer uses the container's working directory [moby/moby#35843](https://github.com/moby/moby/issues/35843)
* Errors not returned from client in stack deploy configs [moby/moby#757](https://github.com/docker/cli/pull/757)
* Daemon aborts when project quota fails [moby/moby#35827](https://github.com/moby/moby/pull/35827)
* Docker cannot use memory limit when using systemd options [moby/moby#35123](https://github.com/moby/moby/issues/35123)

### Builder

- Fix build cache hash for broken symlink [moby/moby#34271](https://github.com/moby/moby/pull/34271)
- Fix long stream sync [moby/moby#35404](https://github.com/moby/moby/pull/35404)
- Fix dockerfile parser failing silently on long tokens [moby/moby#35429](https://github.com/moby/moby/pull/35429)

### Client

* Remove secret/config duplication in cli/compose [docker/cli#671](https://github.com/docker/cli/pull/671)
* Add `--local` flag to `docker trust sign` [docker/cli#575](https://github.com/docker/cli/pull/575)
* Add `docker trust inspect` [docker/cli#694](https://github.com/docker/cli/pull/694)
+ Add `name` field to secrets and configs to allow interpolation in Compose files [docker/cli#668](https://github.com/docker/cli/pull/668)
+ Add `--isolation` for setting swarm service isolation mode [docker/cli#426](https://github.com/docker/cli/pull/426)
* Remove deprecated "daemon" subcommand [docker/cli#689](https://github.com/docker/cli/pull/689)
- Fix behaviour of `rmi -f` with unexpected errors [docker/cli#654](https://github.com/docker/cli/pull/654)
* Integrated Generic resource in service create [docker/cli#429](https://github.com/docker/cli/pull/429)
- Fix external networks in stacks [docker/cli#743](https://github.com/docker/cli/pull/743)
* Remove support for referencing images by image shortid [docker/cli#753](https://github.com/docker/cli/pull/753) and [moby/moby#35790](https://github.com/moby/moby/pull/35790)
* Use commit-sha instead of tag for containerd [moby/moby#35770](https://github.com/moby/moby/pull/35770)

### Documentation

* Update API version history for 1.35 [moby/moby#35724](https://github.com/moby/moby/pull/35724)

### Logging

* Logentries driver line-only=true []byte output fix [moby/moby#35612](https://github.com/moby/moby/pull/35612)
* Logentries line-only logopt fix to maintain backwards compatibility [moby/moby#35628](https://github.com/moby/moby/pull/35628)
+ Add `--until` flag for docker logs [moby/moby#32914](https://github.com/moby/moby/pull/32914)
+ Add gelf log driver plugin to Windows build [moby/moby#35073](https://github.com/moby/moby/pull/35073)
* Set timeout on splunk batch send [moby/moby#35496](https://github.com/moby/moby/pull/35496)
* Update Graylog2/go-gelf [moby/moby#35765](https://github.com/moby/moby/pull/35765)

### Networking

* Move load balancer sandbox creation/deletion into libnetwork [moby/moby#35422](https://github.com/moby/moby/pull/35422)
* Only chown network files within container metadata [moby/moby#34224](https://github.com/moby/moby/pull/34224)
* Restore error type in FindNetwork [moby/moby#35634](https://github.com/moby/moby/pull/35634)
- Fix consumes MIME type for NetworkConnect [moby/moby#35542](https://github.com/moby/moby/pull/35542)
+ Added support for persisting Windows network driver specific options [moby/moby#35563](https://github.com/moby/moby/pull/35563)
- Fix timeout on netlink sockets and watchmiss leak [moby/moby#35677](https://github.com/moby/moby/pull/35677)
+ New daemon config for networking diagnosis [moby/moby#35677](https://github.com/moby/moby/pull/35677)
- Clean up node management logic [docker/libnetwork#2036](https://github.com/docker/libnetwork/pull/2036)
- Allocate VIPs when endpoints are restored [docker/swarmkit#2474](https://github.com/docker/swarmkit/pull/2474)

### Runtime

* Update to containerd v1.0.0 [moby/moby#35707](https://github.com/moby/moby/pull/35707)
* Have VFS graphdriver use accelerated in-kernel copy [moby/moby#35537](https://github.com/moby/moby/pull/35537)
* Introduce `workingdir` option for docker exec [moby/moby#35661](https://github.com/moby/moby/pull/35661)
* Bump Go to 1.9.2 [moby/moby#33892](https://github.com/moby/moby/pull/33892) [docker/cli#716](https://github.com/docker/cli/pull/716)
* `/dev` should not be readonly with `--readonly` flag [moby/moby#35344](https://github.com/moby/moby/pull/35344)
+ Add custom build-time Graphdrivers priority list [moby/moby#35522](https://github.com/moby/moby/pull/35522)
* LCOW: CLI changes to add platform flag - pull, run, create and build [docker/cli#474](https://github.com/docker/cli/pull/474)
* Fix width/height on Windows for `docker exec` [moby/moby#35631](https://github.com/moby/moby/pull/35631)
* Detect overlay2 support on pre-4.0 kernels [moby/moby#35527](https://github.com/moby/moby/pull/35527)
* Devicemapper: remove container rootfs mountPath after umount [moby/moby#34573](https://github.com/moby/moby/pull/34573)
* Disallow overlay/overlay2 on top of NFS [moby/moby#35483](https://github.com/moby/moby/pull/35483)
- Fix potential panic during plugin set. [moby/moby#35632](https://github.com/moby/moby/pull/35632)
- Fix some issues with locking on the container [moby/moby#35501](https://github.com/moby/moby/pull/35501)
- Fixup some issues with plugin refcounting [moby/moby#35265](https://github.com/moby/moby/pull/35265)
+ Add missing lock in ProcessEvent [moby/moby#35516](https://github.com/moby/moby/pull/35516)
+ Add vfs quota support [moby/moby#35231](https://github.com/moby/moby/pull/35231)
* Skip empty directories on prior graphdriver detection [moby/moby#35528](https://github.com/moby/moby/pull/35528)
* Skip xfs quota tests when running in user namespace [moby/moby#35526](https://github.com/moby/moby/pull/35526)
+ Added SubSecondPrecision to config option. [moby/moby#35529](https://github.com/moby/moby/pull/35529)
* Update fsnotify to fix deadlock in removing watch [moby/moby#35453](https://github.com/moby/moby/pull/35453)
- Fix "duplicate mount point" when `--tmpfs /dev/shm` is used [moby/moby#35467](https://github.com/moby/moby/pull/35467)
- Fix honoring tmpfs-size for user `/dev/shm` mount [moby/moby#35316](https://github.com/moby/moby/pull/35316)
- Fix EBUSY errors under overlayfs and v4.13+ kernels [moby/moby#34948](https://github.com/moby/moby/pull/34948)
* Container: protect health monitor channel [moby/moby#35482](https://github.com/moby/moby/pull/35482)
* Container: protect the health status with mutex [moby/moby#35517](https://github.com/moby/moby/pull/35517)
* Container: update real-time resources [moby/moby#33731](https://github.com/moby/moby/pull/33731)
* Create labels when volume exists only remotely [moby/moby#34896](https://github.com/moby/moby/pull/34896)
- Fix leaking container/exec state [moby/moby#35484](https://github.com/moby/moby/pull/35484)
* Disallow using legacy (v1) registries [moby/moby#35751](https://github.com/moby/moby/pull/35751) and [docker/cli#747](https://github.com/docker/cli/pull/747)
- Windows: Fix case insensitive filename matching against builder cache [moby/moby#35793](https://github.com/moby/moby/pull/35793)
- Fix race conditions around process handling and error checks [moby/moby#35809](https://github.com/moby/moby/pull/35809)
* Ensure containers are stopped on daemon startup [moby/moby#35805](https://github.com/moby/moby/pull/35805)
* Follow containerd namespace conventions [moby/moby#35812](https://github.com/moby/moby/pull/35812)

### Swarm Mode

+ Added support for swarm service isolation mode [moby/moby#34424](https://github.com/moby/moby/pull/34424)
- Fix task clean up for tasks that are complete [docker/swarmkit#2477](https://github.com/docker/swarmkit/pull/2477)

### Packaging

+ Add Packaging for Fedora 27 [docker/docker-ce-packaging#59](https://github.com/docker/docker-ce-packaging/pull/59)
* Change default versioning scheme to 0.0.0-dev unless specified for packaging [docker/docker-ce-packaging#67](https://github.com/docker/docker-ce-packaging/pull/67)
* Pass Version to engine static builds [docker/docker-ce-packaging#70](https://github.com/docker/docker-ce-packaging/pull/70)
+ Added support for aarch64 on Debian (stretch/jessie) and Ubuntu Zesty or newer [docker/docker-ce-packaging#35](https://github.com/docker/docker-ce-packaging/pull/35)


---

# Docker Engine 18.01 release notes

*Sección: Engine*

## 18.01.0-ce
2018-01-10

### Builder

* Fix files not being deleted if user-namespaces are enabled [moby/moby#35822](https://github.com/moby/moby/pull/35822)
- Add support for expanding environment-variables in `docker commit --change ...` [moby/moby#35582](https://github.com/moby/moby/pull/35582)

### Client

* Return errors from client in stack deploy configs [docker/cli#757](https://github.com/docker/cli/pull/757)
- Fix description of filter flag in prune commands [docker/cli#774](https://github.com/docker/cli/pull/774)
+ Add "pid" to unsupported options list [docker/cli#768](https://github.com/docker/cli/pull/768)
+ Add support for experimental Cli configuration [docker/cli#758](https://github.com/docker/cli/pull/758)
+ Add support for generic resources to bash completion [docker/cli#749](https://github.com/docker/cli/pull/749)
- Fix error in zsh completion script for docker exec [docker/cli#751](https://github.com/docker/cli/pull/751)
+ Add a debug message when client closes websocket attach connection [moby/moby#35720](https://github.com/moby/moby/pull/35720)
- Fix bash completion for `"docker swarm"` [docker/cli#772](https://github.com/docker/cli/pull/772)


### Documentation
* Correct references to `--publish` long syntax in docs [docker/cli#746](https://github.com/docker/cli/pull/746)
* Corrected descriptions for MAC_ADMIN and MAC_OVERRIDE [docker/cli#761](https://github.com/docker/cli/pull/761)
* Updated developer doc to explain external CLI [moby/moby#35681](https://github.com/moby/moby/pull/35681)
- Fix `"on-failure"` restart policy being documented as "failure" [docker/cli#754](https://github.com/docker/cli/pull/754)
- Fix anchors to "Storage driver options" [docker/cli#748](https://github.com/docker/cli/pull/748)

### Experimental

+ Add kubernetes support to `docker stack` command [docker/cli#721](https://github.com/docker/cli/pull/721)
* Don't append the container id to custom directory checkpoints. [moby/moby#35694](https://github.com/moby/moby/pull/35694)

### Logging

* Fix daemon crash when using the GELF log driver over TCP when the GELF server goes down [moby/moby#35765](https://github.com/moby/moby/pull/35765)
- Fix awslogs batch size calculation for large logs [moby/moby#35726](https://github.com/moby/moby/pull/35726)

### Networking

- Windows: Fix to allow docker service to start on Windows VM [docker/libnetwork#1916](https://github.com/docker/libnetwork/pull/1916)
- Fix for docker intercepting DNS requests on ICS network [docker/libnetwork#2014](https://github.com/docker/libnetwork/pull/2014)
+ Windows: Added a new network creation driver option [docker/libnetwork#2021](https://github.com/docker/libnetwork/pull/2021)


### Runtime

* Validate Mount-specs on container start to prevent missing host-path [moby/moby#35833](https://github.com/moby/moby/pull/35833)
- Fix overlay2 storage driver inside a user namespace [moby/moby#35794](https://github.com/moby/moby/pull/35794)
* Zfs: fix busy error on container stop [moby/moby#35674](https://github.com/moby/moby/pull/35674)
- Fix health checks not using the container's working directory [moby/moby#35845](https://github.com/moby/moby/pull/35845)
- Fix VFS graph driver failure to initialize because of failure to setup fs quota [moby/moby#35827](https://github.com/moby/moby/pull/35827)
- Fix containerd events being processed twice [moby/moby#35896](https://github.com/moby/moby/pull/35896)

### Swarm mode

- Fix published ports not being updated if a service has the same number of host-mode published ports with Published Port 0 [docker/swarmkit#2376](https://github.com/docker/swarmkit/pull/2376)
* Make the task termination order deterministic [docker/swarmkit#2265](https://github.com/docker/swarmkit/pull/2265)


---

# Docker Engine 18.02 release notes

*Sección: Engine*

## 18.02.0-ce
2018-02-07

### Builder

- Gitutils: fix checking out submodules [moby/moby#35737](https://github.com/moby/moby/pull/35737)

### Client

* Attach: Ensure attach exit code matches container's [docker/cli#696](https://github.com/docker/cli/pull/696)
+ Added support for tmpfs-mode in compose file [docker/cli#808](https://github.com/docker/cli/pull/808)
+ Adds a new compose file version 3.6 [docker/cli#808](https://github.com/docker/cli/pull/808)
- Fix issue of filter in `docker ps` where `health=starting` returns nothing [moby/moby#35940](https://github.com/moby/moby/pull/35940)
+ Improve presentation of published port ranges [docker/cli#581](https://github.com/docker/cli/pull/581)
* Bump Go to 1.9.3 [docker/cli#827](https://github.com/docker/cli/pull/827)
- Fix broken Kubernetes stack flags [docker/cli#831](https://github.com/docker/cli/pull/831)
* Annotate "stack" commands to be "swarm" and "kubernetes" [docker/cli#804](https://github.com/docker/cli/pull/804)

### Experimental

+ Add manifest command [docker/cli#138](https://github.com/docker/cli/pull/138)
* LCOW remotefs - return error in Read() implementation [moby/moby#36051](https://github.com/moby/moby/pull/36051)
+ LCOW: Coalesce daemon stores, allow dual LCOW and WCOW mode [moby/moby#34859](https://github.com/moby/moby/pull/34859)
- LCOW: Fix OpenFile parameters [moby/moby#36043](https://github.com/moby/moby/pull/36043)
* LCOW: Raise minimum requirement to Windows RS3 RTM build (16299) [moby/moby#36065](https://github.com/moby/moby/pull/36065)

### Logging

* Improve daemon config reload; log active configuration [moby/moby#36019](https://github.com/moby/moby/pull/36019)
- Fixed error detection using IsErrNotFound and IsErrNotImplemented for the ContainerLogs method [moby/moby#36000](https://github.com/moby/moby/pull/36000)
+ Add journald tag as SYSLOG_IDENTIFIER [moby/moby#35570](https://github.com/moby/moby/pull/35570)
* Splunk: limit the reader size on error responses [moby/moby#35509](https://github.com/moby/moby/pull/35509)

### Networking

* Disable service on release network results in zero-downtime deployments with rolling upgrades [moby/moby#35960](https://github.com/moby/moby/pull/35960)
- Fix services failing to start if multiple networks with the same name exist in different spaces [moby/moby#30897](https://github.com/moby/moby/pull/30897)
- Fix duplicate networks being added with `docker service update --network-add` [docker/cli#780](https://github.com/docker/cli/pull/780)
- Fixing ingress network when upgrading from 17.09 to 17.12. [moby/moby#36003](https://github.com/moby/moby/pull/36003)
- Fix ndots configuration [docker/libnetwork#1995](https://github.com/docker/libnetwork/pull/1995)
- Fix IPV6 networking being deconfigured if live-restore is enabled [docker/libnetwork#2043](https://github.com/docker/libnetwork/pull/2043)
+ Add support for MX type DNS queries in the embedded DNS server [docker/libnetwork#2041](https://github.com/docker/libnetwork/pull/2041)

### Packaging

+ Added packaging for Fedora 26, Fedora 27, and Centos 7 on aarch64 [docker/docker-ce-packaging#71](https://github.com/docker/docker-ce-packaging/pull/71)
- Removed support for Ubuntu Zesty [docker/docker-ce-packaging#73](https://github.com/docker/docker-ce-packaging/pull/73)
- Removed support for Fedora 25 [docker/docker-ce-packaging#72](https://github.com/docker/docker-ce-packaging/pull/72)

### Runtime

- Fixes unexpected Docker Daemon shutdown based on pipe error [moby/moby#35968](https://github.com/moby/moby/pull/35968)
- Fix some occurrences of hcsshim::ImportLayer failed in Win32: The system cannot find the path specified [moby/moby#35924](https://github.com/moby/moby/pull/35924)
* Windows: increase the maximum layer size during build to 127GB [moby/moby#35925](https://github.com/moby/moby/pull/35925)
- Fix Devicemapper: Error running DeleteDevice dm_task_run failed [moby/moby#35919](https://github.com/moby/moby/pull/35919)
+ Introduce « exec_die » event [moby/moby#35744](https://github.com/moby/moby/pull/35744)
* Update API to version 1.36 [moby/moby#35744](https://github.com/moby/moby/pull/35744)
- Fix `docker update` not updating cpu quota, and cpu-period of a running container [moby/moby#36030](https://github.com/moby/moby/pull/36030)
* Make container shm parent unbindable [moby/moby#35830](https://github.com/moby/moby/pull/35830)
+ Make image (layer) downloads faster by using pigz [moby/moby#35697](https://github.com/moby/moby/pull/35697)
+ Protect the daemon from volume plugins that are slow or deadlocked [moby/moby#35441](https://github.com/moby/moby/pull/35441)
- Fix `DOCKER_RAMDISK` environment variable not being honoured [moby/moby#35957](https://github.com/moby/moby/pull/35957)
* Bump containerd to 1.0.1 (9b55aab90508bd389d7654c4baf173a981477d55) [moby/moby#35986](https://github.com/moby/moby/pull/35986)
* Update runc to fix hang during start and exec [moby/moby#36097](https://github.com/moby/moby/pull/36097)
- Fix "--node-generic-resource" singular/plural [moby/moby#36125](https://github.com/moby/moby/pull/36125)


---

# Docker Engine 18.03 release notes

*Sección: Engine*

## 18.03.1-ce
2018-04-26

### Client

- Fix error with merge compose file with networks [docker/cli#983](https://github.com/docker/cli/pull/983)
* Fix docker stack deploy re-deploying services after the service was updated with `--force` [docker/cli#963](https://github.com/docker/cli/pull/963)
* Fix docker version output alignment [docker/cli#965](https://github.com/docker/cli/pull/965)

### Runtime

- Fix AppArmor profiles not being applied to `docker exec` processes [moby/moby#36466](https://github.com/moby/moby/pull/36466)
- Don't sort plugin mount slice [moby/moby#36711](https://github.com/moby/moby/pull/36711)
- Daemon/cluster: handle partial attachment entries during configure [moby/moby#36769](https://github.com/moby/moby/pull/36769)
* Bump Golang to 1.9.5 [moby/moby#36779](https://github.com/moby/moby/pull/36779) [docker/cli#986](https://github.com/docker/cli/pull/986)
- Daemon/stats: more resilient cpu sampling [moby/moby#36519](https://github.com/moby/moby/pull/36519)
* Containerd: update to 1.0.3 release [moby/moby#36749](https://github.com/moby/moby/pull/36749)
- Fix Windows layer leak when write fails [moby/moby#36728](https://github.com/moby/moby/pull/36728)
* Don't make container mount unbindable [moby/moby#36768](https://github.com/moby/moby/pull/36768)
- Fix Daemon panics on container export after a daemon restart [moby/moby/36586](https://github.com/moby/moby/pull/36586)
- Fix digest cache being removed on autherrors [moby/moby#36509](https://github.com/moby/moby/pull/36509)
- Make sure plugin container is removed on failure [moby/moby#36715](https://github.com/moby/moby/pull/36715)
- Copy: avoid using all system memory with authz plugins [moby/moby#36595](https://github.com/moby/moby/pull/36595)
- Relax some libcontainerd client locking [moby/moby#36848](https://github.com/moby/moby/pull/36848)
- Update `hcsshim` to v0.6.10 to address [CVE-2018-8115](https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/CVE-2018-8115)

### Swarm Mode

* Increase raft Election tick to 10 times Heartbeat tick [moby/moby#36672](https://github.com/moby/moby/pull/36672)

### Networking

* Gracefully remove LB endpoints from services [docker/libnetwork#2112](https://github.com/docker/libnetwork/pull/2112)
* Retry other external DNS servers on ServFail [docker/libnetwork#2121](https://github.com/docker/libnetwork/pull/2121)
* Improve scalability of bridge network isolation rules [docker/libnetwork#2117](https://github.com/docker/libnetwork/pull/2117)
* Allow for larger preset property values, do not override [docker/libnetwork#2124](https://github.com/docker/libnetwork/pull/2124)
* Prevent panics on concurrent reads/writes when calling `changeNodeState` [docker/libnetwork#2136](https://github.com/docker/libnetwork/pull/2136)

## 18.03.0-ce
2018-03-21

### Builder

* Switch to -buildmode=pie [moby/moby#34369](https://github.com/moby/moby/pull/34369)
* Allow Dockerfile to be outside of build-context [docker/cli#886](https://github.com/docker/cli/pull/886)
* Builder: fix wrong cache hits building from tars [moby/moby#36329](https://github.com/moby/moby/pull/36329)
- Fixes files leaking to other images in a multi-stage build [moby/moby#36338](https://github.com/moby/moby/pull/36338)

### Client

* Simplify the marshaling of compose types.Config [docker/cli#895](https://github.com/docker/cli/pull/895)
+ Add support for multiple composefile when deploying [docker/cli#569](https://github.com/docker/cli/pull/569)
- Fix broken Kubernetes stack flags [docker/cli#831](https://github.com/docker/cli/pull/831)
- Fix stack marshaling for Kubernetes [docker/cli#890](https://github.com/docker/cli/pull/890)
- Fix and simplify bash completion for service env, mounts and labels [docker/cli#682](https://github.com/docker/cli/pull/682)
- Fix `before` and `since` filter for `docker ps` [moby/moby#35938](https://github.com/moby/moby/pull/35938)
- Fix `--label-file` weird behavior [docker/cli#838](https://github.com/docker/cli/pull/838)
- Fix compilation of defaultCredentialStore() on unsupported platforms [docker/cli#872](https://github.com/docker/cli/pull/872)
* Improve and fix bash completion for images [docker/cli#717](https://github.com/docker/cli/pull/717)
+ Added check for empty source in bind mount [docker/cli#824](https://github.com/docker/cli/pull/824)
- Fix TLS from environment variables in client [moby/moby#36270](https://github.com/moby/moby/pull/36270)
* docker build now runs faster when registry-specific credential helper(s) are configured [docker/cli#840](https://github.com/docker/cli/pull/840)
* Update event filter zsh completion with `disable`, `enable`, `install` and `remove` [docker/cli#372](https://github.com/docker/cli/pull/372)
* Produce errors when empty ids are passed into inspect calls [moby/moby#36144](https://github.com/moby/moby/pull/36144)
* Marshall version for the k8s controller [docker/cli#891](https://github.com/docker/cli/pull/891)
* Set a non-zero timeout for HTTP client communication with plugin backend [docker/cli#883](https://github.com/docker/cli/pull/883)
+ Add DOCKER_TLS environment variable for --tls option [docker/cli#863](https://github.com/docker/cli/pull/863)
+ Add --template-driver option for secrets/configs [docker/cli#896](https://github.com/docker/cli/pull/896)
+ Move `docker trust` commands out of experimental [docker/cli#934](https://github.com/docker/cli/pull/934) [docker/cli#935](https://github.com/docker/cli/pull/935) [docker/cli#944](https://github.com/docker/cli/pull/944)

### Logging

* AWS logs - don't add new lines to maximum sized events [moby/moby#36078](https://github.com/moby/moby/pull/36078)
* Move log validator logic after plugins are loaded [moby/moby#36306](https://github.com/moby/moby/pull/36306)
* Support a proxy in Splunk log driver [moby/moby#36220](https://github.com/moby/moby/pull/36220)
- Fix log tail with empty logs [moby/moby#36305](https://github.com/moby/moby/pull/36305)

### Networking

* Libnetwork revendoring [moby/moby#36137](https://github.com/moby/moby/pull/36137)
- Fix for deadlock on exit with Memberlist revendor [docker/libnetwork#2040](https://github.com/docker/libnetwork/pull/2040)
* Fix user specified ndots option [docker/libnetwork#2065](https://github.com/docker/libnetwork/pull/2065)
- Fix to use ContainerID for Windows instead of SandboxID [docker/libnetwork#2010](https://github.com/docker/libnetwork/pull/2010)
* Verify NetworkingConfig to make sure EndpointSettings is not nil [moby/moby#36077](https://github.com/moby/moby/pull/36077)
- Fix `DockerNetworkInternalMode` issue [moby/moby#36298](https://github.com/moby/moby/pull/36298)
- Fix race in attachable network attachment [moby/moby#36191](https://github.com/moby/moby/pull/36191)
- Fix timeout issue of `InspectNetwork` on AArch64 [moby/moby#36257](https://github.com/moby/moby/pull/36257)
* Verbose info is missing for partial overlay ID [moby/moby#35989](https://github.com/moby/moby/pull/35989)
* Update `FindNetwork` to address network name duplications [moby/moby#30897](https://github.com/moby/moby/pull/30897)
* Disallow attaching ingress network [docker/swarmkit#2523](https://github.com/docker/swarmkit/pull/2523)
- Prevent implicit removal of the ingress network [moby/moby#36538](https://github.com/moby/moby/pull/36538)
- Fix stale HNS endpoints on Windows [moby/moby#36603](https://github.com/moby/moby/pull/36603)
- IPAM fixes for duplicate IP addresses [docker/libnetwork#2104](https://github.com/docker/libnetwork/pull/2104) [docker/libnetwork#2105](https://github.com/docker/libnetwork/pull/2105)

### Runtime

* Enable HotAdd for Windows [moby/moby#35414](https://github.com/moby/moby/pull/35414)
* LCOW: Graphdriver fix deadlock in hotRemoveVHDs [moby/moby#36114](https://github.com/moby/moby/pull/36114)
* LCOW: Regular mount if only one layer [moby/moby#36052](https://github.com/moby/moby/pull/36052)
* Remove interim env var LCOW_API_PLATFORM_IF_OMITTED [moby/moby#36269](https://github.com/moby/moby/pull/36269)
* Revendor Microsoft/opengcs @ v0.3.6 [moby/moby#36108](https://github.com/moby/moby/pull/36108)
- Fix issue of ExitCode and PID not show up in Task.Status.ContainerStatus [moby/moby#36150](https://github.com/moby/moby/pull/36150)
- Fix issue with plugin scanner going too deep [moby/moby#36119](https://github.com/moby/moby/pull/36119)
* Do not make graphdriver homes private mounts [moby/moby#36047](https://github.com/moby/moby/pull/36047)
* Do not recursive unmount on cleanup of zfs/btrfs [moby/moby#36237](https://github.com/moby/moby/pull/36237)
* Don't restore image if layer does not exist [moby/moby#36304](https://github.com/moby/moby/pull/36304)
* Adjust minimum API version for templated configs/secrets [moby/moby#36366](https://github.com/moby/moby/pull/36366)
* Bump containerd to 1.0.2 (cfd04396dc68220d1cecbe686a6cc3aa5ce3667c) [moby/moby#36308](https://github.com/moby/moby/pull/36308)
* Bump Golang to 1.9.4 [moby/moby#36243](https://github.com/moby/moby/pull/36243)
* Ensure daemon root is unmounted on shutdown [moby/moby#36107](https://github.com/moby/moby/pull/36107)
* Update runc to 6c55f98695e902427906eed2c799e566e3d3dfb5 [moby/moby#36222](https://github.com/moby/moby/pull/36222)
- Fix container cleanup on daemon restart [moby/moby#36249](https://github.com/moby/moby/pull/36249)
* Support SCTP port mapping (bump up API to v1.37) [moby/moby#33922](https://github.com/moby/moby/pull/33922)
* Support SCTP port mapping [docker/cli#278](https://github.com/docker/cli/pull/278)
- Fix Volumes property definition in ContainerConfig [moby/moby#35946](https://github.com/moby/moby/pull/35946)
* Bump moby and dependencies [docker/cli#829](https://github.com/docker/cli/pull/829)
* C.RWLayer: check for nil before use [moby/moby#36242](https://github.com/moby/moby/pull/36242)
+ Add `REMOVE` and `ORPHANED` to TaskState [moby/moby#36146](https://github.com/moby/moby/pull/36146)
- Fixed error detection using `IsErrNotFound` and `IsErrNotImplemented` for `ContainerStatPath`, `CopyFromContainer`, and `CopyToContainer` methods [moby/moby#35979](https://github.com/moby/moby/pull/35979)
+ Add an integration/internal/container helper package [moby/moby#36266](https://github.com/moby/moby/pull/36266)
+ Add canonical import path [moby/moby#36194](https://github.com/moby/moby/pull/36194)
+ Add/use container.Exec() to integration [moby/moby#36326](https://github.com/moby/moby/pull/36326)
- Fix "--node-generic-resource" singular/plural [moby/moby#36125](https://github.com/moby/moby/pull/36125)
* Daemon.cleanupContainer: nullify container RWLayer upon release [moby/moby#36160](https://github.com/moby/moby/pull/36160)
* Daemon: passdown the `--oom-kill-disable` option to containerd [moby/moby#36201](https://github.com/moby/moby/pull/36201)
* Display a warn message when there is binding ports and net mode is host [moby/moby#35510](https://github.com/moby/moby/pull/35510)
* Refresh containerd remotes on containerd restarted [moby/moby#36173](https://github.com/moby/moby/pull/36173)
* Set daemon root to use shared propagation [moby/moby#36096](https://github.com/moby/moby/pull/36096)
* Optimizations for recursive unmount [moby/moby#34379](https://github.com/moby/moby/pull/34379)
* Perform plugin mounts in the runtime [moby/moby#35829](https://github.com/moby/moby/pull/35829)
* Graphdriver: Fix RefCounter memory leak [moby/moby#36256](https://github.com/moby/moby/pull/36256)
* Use continuity fs package for volume copy [moby/moby#36290](https://github.com/moby/moby/pull/36290)
* Use proc/exe for reexec [moby/moby#36124](https://github.com/moby/moby/pull/36124)
+ Add API support for templated secrets and configs [moby/moby#33702](https://github.com/moby/moby/pull/33702) and [moby/moby#36366](https://github.com/moby/moby/pull/36366)
* Use rslave propagation for mounts from daemon root [moby/moby#36055](https://github.com/moby/moby/pull/36055)
+ Add /proc/keys to masked paths [moby/moby#36368](https://github.com/moby/moby/pull/36368)
* Bump Runc to 1.0.0-rc5 [moby/moby#36449](https://github.com/moby/moby/pull/36449)
- Fixes `runc exec` on big-endian architectures [moby/moby#36449](https://github.com/moby/moby/pull/36449)
* Use chroot when mount namespaces aren't provided [moby/moby#36449](https://github.com/moby/moby/pull/36449)
- Fix systemd slice expansion so that it could be consumed by cAdvisor [moby/moby#36449](https://github.com/moby/moby/pull/36449)
- Fix devices mounted with wrong uid/gid [moby/moby#36449](https://github.com/moby/moby/pull/36449)
- Fix read-only containers with IPC private mounts `/dev/shm` read-only [moby/moby#36526](https://github.com/moby/moby/pull/36526)

### Swarm Mode

* Replace EC Private Key with PKCS#8 PEMs [docker/swarmkit#2246](https://github.com/docker/swarmkit/pull/2246)
* Fix IP overlap with empty EndpointSpec [docker/swarmkit #2505](https://github.com/docker/swarmkit/pull/2505)
* Add support for Support SCTP port mapping [docker/swarmkit#2298](https://github.com/docker/swarmkit/pull/2298)
* Do not reschedule tasks if only placement constraints change and are satisfied by the assigned node [docker/swarmkit#2496](https://github.com/docker/swarmkit/pull/2496)
* Ensure task reaper stopChan is closed no more than once [docker/swarmkit #2491](https://github.com/docker/swarmkit/pull/2491)
* Synchronization fixes [docker/swarmkit#2495](https://github.com/docker/swarmkit/pull/2495)
* Add log message to indicate message send retry if streaming unimplemented [docker/swarmkit#2483](https://github.com/docker/swarmkit/pull/2483)
* Debug logs for session, node events on dispatcher, heartbeats [docker/swarmkit#2486](https://github.com/docker/swarmkit/pull/2486)
+ Add swarm types to bash completion event type filter [docker/cli#888](https://github.com/docker/cli/pull/888)
- Fix issue where network inspect does not show Created time for networks in swarm scope [moby/moby#36095](https://github.com/moby/moby/pull/36095)


---

# Docker Engine 18.04 release notes

*Sección: Engine*

## 18.04.0-ce
2018-04-10

### Builder

- Fix typos in builder and client. [moby/moby#36424](https://github.com/moby/moby/pull/36424)

### Client

* Print Stack API and Kubernetes versions in version command. [docker/cli#898](https://github.com/docker/cli/pull/898)
- Fix Kubernetes duplication in version command. [docker/cli#953](https://github.com/docker/cli/pull/953)
* Use HasAvailableFlags instead of HasFlags for Options in help. [docker/cli#959](https://github.com/docker/cli/pull/959)
+ Add support for mandatory variables to stack deploy. [docker/cli#893](https://github.com/docker/cli/pull/893)
- Fix docker stack services command Port output. [docker/cli#943](https://github.com/docker/cli/pull/943)
* Deprecate unencrypted storage. [docker/cli#561](https://github.com/docker/cli/pull/561)
* Don't set a default filename for ConfigFile. [docker/cli#917](https://github.com/docker/cli/pull/917)
- Fix compose network name. [docker/cli#941](https://github.com/docker/cli/pull/941)

### Logging

* Silent login: use credentials from cred store to login. [docker/cli#139](https://github.com/docker/cli/pull/139)
+ Add support for compressibility of log file. [moby/moby#29932](https://github.com/moby/moby/pull/29932)
- Fix empty LogPath with non-blocking logging mode. [moby/moby#36272](https://github.com/moby/moby/pull/36272)

### Networking

- Prevent explicit removal of ingress network. [moby/moby#36538](https://github.com/moby/moby/pull/36538)

### Runtime

* Devmapper cleanup improvements. [moby/moby#36307](https://github.com/moby/moby/pull/36307)
* Devmapper.Mounted: remove. [moby/moby#36437](https://github.com/moby/moby/pull/36437)
* Devmapper/Remove(): use Rmdir, ignore errors. [moby/moby#36438](https://github.com/moby/moby/pull/36438)
* LCOW - Change platform parser directive to FROM statement flag. [moby/moby#35089](https://github.com/moby/moby/pull/35089)
* Split daemon service code to windows file. [moby/moby#36653](https://github.com/moby/moby/pull/36653)
* Windows: Block pulling uplevel images. [moby/moby#36327](https://github.com/moby/moby/pull/36327)
* Windows: Hyper-V containers are broken after 36586 was merged. [moby/moby#36610](https://github.com/moby/moby/pull/36610)
* Windows: Move kernel_windows to use golang registry functions. [moby/moby#36617](https://github.com/moby/moby/pull/36617)
* Windows: Pass back system errors on container exit. [moby/moby#35967](https://github.com/moby/moby/pull/35967)
* Windows: Remove servicing mode. [moby/moby#36267](https://github.com/moby/moby/pull/36267)
* Windows: Report Version and UBR. [moby/moby#36451](https://github.com/moby/moby/pull/36451)
* Bump Runc to 1.0.0-rc5. [moby/moby#36449](https://github.com/moby/moby/pull/36449)
* Mount failure indicates the path that failed. [moby/moby#36407](https://github.com/moby/moby/pull/36407)
* Change return for errdefs.getImplementer(). [moby/moby#36489](https://github.com/moby/moby/pull/36489)
* Client: fix hijackedconn reading from buffer. [moby/moby#36663](https://github.com/moby/moby/pull/36663)
* Content encoding negotiation added to archive request. [moby/moby#36164](https://github.com/moby/moby/pull/36164)
* Daemon/stats: more resilient cpu sampling. [moby/moby#36519](https://github.com/moby/moby/pull/36519)
* Daemon/stats: remove obnoxious types file. [moby/moby#36494](https://github.com/moby/moby/pull/36494)
* Daemon: use context error rather than inventing new one. [moby/moby#36670](https://github.com/moby/moby/pull/36670)
* Enable CRIU on non-amd64 architectures (v2). [moby/moby#36676](https://github.com/moby/moby/pull/36676)
- Fixes intermittent client hang after closing stdin to attached container [moby/moby#36517](https://github.com/moby/moby/pull/36517)
- Fix daemon panic on container export after restart [moby/moby#36586](https://github.com/moby/moby/pull/36586)
- Follow-up fixes on multi-stage moby's Dockerfile. [moby/moby#36425](https://github.com/moby/moby/pull/36425)
* Freeze busybox and latest glibc in Docker image. [moby/moby#36375](https://github.com/moby/moby/pull/36375)
* If container will run as non root user, drop permitted, effective caps early. [moby/moby#36587](https://github.com/moby/moby/pull/36587)
* Layer: remove metadata store interface. [moby/moby#36504](https://github.com/moby/moby/pull/36504)
* Minor optimizations to dockerd. [moby/moby#36577](https://github.com/moby/moby/pull/36577)
* Whitelist statx syscall. [moby/moby#36417](https://github.com/moby/moby/pull/36417)
+ Add missing error return for plugin creation. [moby/moby#36646](https://github.com/moby/moby/pull/36646)
- Fix AppArmor not being applied to Exec processes. [moby/moby#36466](https://github.com/moby/moby/pull/36466)
* Daemon/logger/ring.go: log error not instance. [moby/moby#36475](https://github.com/moby/moby/pull/36475)
- Fix stats collector spinning CPU if no stats are collected. [moby/moby#36609](https://github.com/moby/moby/pull/36609)
- Fix(distribution): digest cache should not be moved if it was an auth. [moby/moby#36509](https://github.com/moby/moby/pull/36509)
- Make sure plugin container is removed on failure. [moby/moby#36715](https://github.com/moby/moby/pull/36715)
* Bump to containerd 1.0.3. [moby/moby#36749](https://github.com/moby/moby/pull/36749)
* Don't sort plugin mount slice. [moby/moby#36711](https://github.com/moby/moby/pull/36711)

### Swarm Mode

* Fixes for synchronizing the dispatcher shutdown with in-progress rpcs. [moby/moby#36371](https://github.com/moby/moby/pull/36371)
* Increase raft ElectionTick to 10xHeartbeatTick. [moby/moby#36672](https://github.com/moby/moby/pull/36672)
* Make Swarm manager Raft quorum parameters configurable in daemon config. [moby/moby#36726](https://github.com/moby/moby/pull/36726)
* Ingress network should not be attachable. [docker/swarmkit#2523](https://github.com/docker/swarmkit/pull/2523)
* [manager/state] Add fernet as an option for raft encryption. [docker/swarmkit#2535](https://github.com/docker/swarmkit/pull/2535)
* Log GRPC server errors.  [docker/swarmkit#2541](https://github.com/docker/swarmkit/pull/2541)
* Log leadership changes at the manager level. [docker/swarmkit#2542](https://github.com/docker/swarmkit/pull/2542)
* Remove the containerd executor. [docker/swarmkit#2568](https://github.com/docker/swarmkit/pull/2568)
* Agent: backoff session when no remotes are available. [docker/swarmkit#2570](https://github.com/docker/swarmkit/pull/2570)
* [ca/manager] Remove root CA key encryption support entirely. [docker/swarmkit#2573](https://github.com/docker/swarmkit/pull/2573)
- Fix agent logging race. [docker/swarmkit#2578](https://github.com/docker/swarmkit/pull/2578)
* Adding logic to restore networks in order. [docker/swarmkit#2571](https://github.com/docker/swarmkit/pull/2571)


---

# Docker Engine 18.05 release notes

*Sección: Engine*

## 18.05.0-ce
2018-05-09

### Builder

*  Adding `netbsd` compatibility to the package `pkg/term`. [moby/moby#36887](https://github.com/moby/moby/pull/36887)
*  Standardizes output path for artifacts of intermediate builds to `/build/`. [moby/moby#36858](https://github.com/moby/moby/pull/36858)

### Client

- Fix `docker stack deploy` reference flag. [docker/cli#981](https://github.com/docker/cli/pull/981)
- Fix docker stack deploy re-deploying services after the service was updated with `--force`. [docker/cli#963](https://github.com/docker/cli/pull/963)
+ Add bash completion for `secret|config create --template-driver`. [docker/cli#1004](https://github.com/docker/cli/pull/1004)
+ Add fish completions for docker trust subcommand. [docker/cli#984](https://github.com/docker/cli/pull/984)
- Fix --format example for docker history. [docker/cli#980](https://github.com/docker/cli/pull/980)
- Fix error with merge composefile with networks. [docker/cli#983](https://github.com/docker/cli/pull/983)

### Logging
* Standardized the properties of storage-driver log messages. [moby/moby#36492](https://github.com/moby/moby/pull/36492)
* Improve partial message support in logger. [moby/moby#35831](https://github.com/moby/moby/pull/35831)

### Networking

- Allow for larger preset property values, do not override. [docker/libnetwork#2124](https://github.com/docker/libnetwork/pull/2124)
- networkdb: User write lock in handleNodeEvent.  [docker/libnetwork#2136](https://github.com/docker/libnetwork/pull/2136)
* Import libnetwork fix for rolling updates. [moby/moby#36638](https://github.com/moby/moby/pull/36638)
* Update libnetwork to improve scalability of bridge network isolation rules. [moby/moby#36774](https://github.com/moby/moby/pull/36774)
- Fix a misused network object name. [moby/moby#36745](https://github.com/moby/moby/pull/36745)

### Runtime

* LCOW: Implement `docker save`. [moby/moby#36599](https://github.com/moby/moby/pull/36599)
* Pkg: devmapper: dynamically load dm_task_deferred_remove. [moby/moby#35518](https://github.com/moby/moby/pull/35518)
* Windows: Add GetLayerPath implementation in graphdriver. [moby/moby#36738](https://github.com/moby/moby/pull/36738)
- Fix Windows layer leak when write fails. [moby/moby#36728](https://github.com/moby/moby/pull/36728)
- Fix FIFO, sockets and device files when run in user NS. [moby/moby#36756](https://github.com/moby/moby/pull/36756)
- Fix docker version output alignment. [docker/cli#965](https://github.com/docker/cli/pull/965)
* Always make sysfs read-write with privileged. [moby/moby#36808](https://github.com/moby/moby/pull/36808)
* Bump Golang to 1.10.1. [moby/moby#35739](https://github.com/moby/moby/pull/35739)
* Bump containerd client. [moby/moby#36684](https://github.com/moby/moby/pull/36684)
* Bump golang.org/x/net to go1.10 release commit. [moby/moby#36894](https://github.com/moby/moby/pull/36894)
* Context.WithTimeout: do call the cancel func. [moby/moby#36920](https://github.com/moby/moby/pull/36920)
* Copy: avoid using all system memory with authz plugins. [moby/moby#36595](https://github.com/moby/moby/pull/36595)
* Daemon/cluster: handle partial attachment entries during configure. [moby/moby#36769](https://github.com/moby/moby/pull/36769)
* Don't make container mount unbindable. [moby/moby#36768](https://github.com/moby/moby/pull/36768)
* Extra check before unmounting on shutdown. [moby/moby#36879](https://github.com/moby/moby/pull/36879)
* Move mount parsing to separate package. [moby/moby#36896](https://github.com/moby/moby/pull/36896)
* No global volume driver store. [moby/moby#36637](https://github.com/moby/moby/pull/36637)
* Pkg/mount improvements. [moby/moby#36091](https://github.com/moby/moby/pull/36091)
* Relax some libcontainerd client locking. [moby/moby#36848](https://github.com/moby/moby/pull/36848)
* Remove daemon dependency on api packages. [moby/moby#36912](https://github.com/moby/moby/pull/36912)
* Remove the retries for service update. [moby/moby#36827](https://github.com/moby/moby/pull/36827)
* Revert unencryted storage warning prompt. [docker/cli#1008](https://github.com/docker/cli/pull/1008)
* Support cancellation in `directory.Size()`. [moby/moby#36734](https://github.com/moby/moby/pull/36734)
* Switch from x/net/context -> context. [moby/moby#36904](https://github.com/moby/moby/pull/36904)
* Fixed a function to check Content-type is `application/json` or not. [moby/moby#36778](https://github.com/moby/moby/pull/36778)
+ Add default pollSettings config functions. [moby/moby#36706](https://github.com/moby/moby/pull/36706)
+ Add if judgment before receiving operations on daemonWaitCh. [moby/moby#36651](https://github.com/moby/moby/pull/36651)
- Fix issues with running volume tests as non-root.. [moby/moby#36935](https://github.com/moby/moby/pull/36935)

### Swarm Mode

* RoleManager will remove detected nodes from the cluster membership [docker/swarmkit#2548](https://github.com/docker/swarmkit/pull/2548)
* Scheduler/TaskReaper: handle unassigned tasks marked for shutdown [docker/swarmkit#2574](https://github.com/docker/swarmkit/pull/2574)
* Avoid predefined error log. [docker/swarmkit#2561](https://github.com/docker/swarmkit/pull/2561)
* Task reaper should delete tasks with removed slots that were not yet assigned. [docker/swarmkit#2557](https://github.com/docker/swarmkit/pull/2557)
* Agent reports FIPS status. [docker/swarmkit#2587](https://github.com/docker/swarmkit/pull/2587)
- Fix: timeMutex critical operation outside of critical section. [docker/swarmkit#2603](https://github.com/docker/swarmkit/pull/2603)
* Expose swarmkit's Raft tuning parameters in engine config. [moby/moby#36726](https://github.com/moby/moby/pull/36726)
* Make internal/test/daemon.Daemon swarm aware. [moby/moby#36826](https://github.com/moby/moby/pull/36826)


---

# Docker Engine 18.06 release notes

*Sección: Engine*

## 18.06.3-ce

2019-02-19

### Security fixes for Docker Engine
* Change how the `runc` critical vulnerability patch is applied to include the fix in RPM packages. [docker/engine#156](https://github.com/docker/engine/pull/156)

## 18.06.2

2019-02-11

### Security fixes for Docker Engine
* Update `runc` to address a critical vulnerability that allows specially-crafted containers to gain administrative privileges on the host. [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736)
* Ubuntu 14.04 customers using a 3.13 kernel will need to upgrade to a supported Ubuntu 4.x kernel

## 18.06.1-ce
2018-08-21

### Builder

- Fix no error if build args are missing during docker build. [docker/engine#25](https://github.com/docker/engine/pull/25)
+ Set BuildKit's ExportedProduct variable to show useful errors. [docker/engine#21](https://github.com/docker/engine/pull/21)

### Client

+ Various shell completion script updates: [docker/cli#1229](https://github.com/docker/cli/pull/1229),
 [docker/cli#1268](https://github.com/docker/cli/pull/1268), and [docker/cli#1272](https://github.com/docker/cli/pull/1272)
- Fix `DOCKER_CONFIG` warning message and fallback search. [docker/cli#1241](https://github.com/docker/cli/pull/1241)
- Fix help message flags on `docker stack` commands and sub-commands. [docker/cli#1267](https://github.com/docker/cli/pull/1267)

### Runtime

* Disable CRI plugin listening on port 10010 by default. [docker/engine#29](https://github.com/docker/engine/pull/29)
* Update containerd to v1.1.2. [docker/engine#33](https://github.com/docker/engine/pull/33)
- Windows: Do not invoke HCS shutdown if terminate called. [docker/engine#31](https://github.com/docker/engine/pull/31)
* Windows: Select polling-based watcher for Windows log watcher. [docker/engine#34](https://github.com/docker/engine/pull/34)

### Swarm Mode

- Fix the condition used for skipping over running tasks. [docker/swarmkit#2677](https://github.com/docker/swarmkit/pull/2677)
- Fix task sorting. [docker/swarmkit#2712](https://github.com/docker/swarmkit/pull/2712)

## 18.06.0-ce
2018-07-18

### Important notes about this release

- Docker 18.06 CE will be the last release with a 4-month maintenance lifecycle. The planned Docker 18.09 CE release will be supported for 7 months with Docker 19.03 CE being the next release in line. More details about the release process can be found [here](/get-started/get-docker.md).

### Builder

* Builder: fix layer leak on multi-stage wildcard copy. [moby/moby#37178](https://github.com/moby/moby/pull/37178)
* Fix parsing of invalid environment variable substitution . [moby/moby#37134](https://github.com/moby/moby/pull/37134)
* Builder: use the arch info from base image. [moby/moby#36816](https://github.com/moby/moby/pull/36816) [moby/moby#37197](https://github.com/moby/moby/pull/37197)
+ New experimental builder backend based on [BuildKit](https://github.com/moby/buildkit). To enable, run daemon in experimental mode and set `DOCKER_BUILDKIT=1` environment variable on the docker CLI. [moby/moby#37151](https://github.com/moby/moby/pull/37151) [docker/cli#1111](https://github.com/docker/cli/pull/1111)
- Fix handling uppercase targets names in multi-stage builds. [moby/moby#36960](https://github.com/moby/moby/pull/36960)

### Client

* Bump spf13/cobra to v0.0.3, pflag to v1.0.1. [moby/moby#37106](https://github.com/moby/moby/pull/37106)
* Add support for the new Stack API for Kubernetes v1beta2. [docker/cli#899](https://github.com/docker/cli/pull/899)
* K8s: more robust stack error detection on deploy. [docker/cli#948](https://github.com/docker/cli/pull/948)
* Support for rollback config in compose 3.7. [docker/cli#409](https://github.com/docker/cli/pull/409)
* Update Cobra and pflag, and use built-in --version feature. [docker/cli#1069](https://github.com/docker/cli/pull/1069)
* Fix `docker stack deploy --prune` with empty name removing all services. [docker/cli#1088](https://github.com/docker/cli/pull/1088)
* [Kubernetes] stack services filters. [docker/cli#1023](https://github.com/docker/cli/pull/1023)
+ Only show orchestrator flag in root, stack and version commands in help. [docker/cli#1106](https://github.com/docker/cli/pull/1106)
+ Add an `Extras` field on the compose config types. [docker/cli#1126](https://github.com/docker/cli/pull/1126)
+ Add options to the compose loader. [docker/cli#1128](https://github.com/docker/cli/pull/1128)
- Fix always listing nodes in docker stack ps command on Kubernetes. [docker/cli#1093](https://github.com/docker/cli/pull/1093)
- Fix output being shown twice on stack rm error message. [docker/cli#1093](https://github.com/docker/cli/pull/1093)
* Extend client API with custom HTTP requests. [moby/moby#37071](https://github.com/moby/moby/pull/37071)
* Changed error message for unreadable files to clarify possibility of a .Dockerignore entry. [docker/cli#1053](https://github.com/docker/cli/pull/1053)
* Restrict kubernetes.allNamespaces value to 'enabled' or 'disabled' in configuration file. [docker/cli#1087](https://github.com/docker/cli/pull/1087)
* Check errors when initializing the docker client in the help command. [docker/cli#1119](https://github.com/docker/cli/pull/1119)
* Better namespace experience with Kubernetes. Fix using namespace defined in ~/.kube/config for stack commands. Add a NAMESPACE column for docker stack ls command. Add a --all-namespaces flag for docker stack ls command. [docker/cli#991](https://github.com/docker/cli/pull/991)
* Export Push and Save. [docker/cli#1123](https://github.com/docker/cli/pull/1123)
* Export pull as a public function. [docker/cli#1026](https://github.com/docker/cli/pull/1026)
* Remove Kubernetes commands from experimental. [docker/cli#1068](https://github.com/docker/cli/pull/1068)
* Adding configs/secrets to service inspect pretty. [docker/cli#1006](https://github.com/docker/cli/pull/1006)
- Fix service filtering by name on Kubernetes. [docker/cli#1101](https://github.com/docker/cli/pull/1101)
- Fix component information alignment in `docker version`. [docker/cli#1065](https://github.com/docker/cli/pull/1065)
- Fix cpu/memory limits and reservations being reset on service update. [docker/cli#1079](https://github.com/docker/cli/pull/1079)
* Manifest list: request specific permissions. [docker/cli#1024](https://github.com/docker/cli/pull/1024)
* Setting --orchestrator=all also sets --all-namespaces unless specific --namespace are set. [docker/cli#1059](https://github.com/docker/cli/pull/1059)
- Fix panics when --compress and --stream are used together. [docker/cli#1105](https://github.com/docker/cli/pull/1105)
* Switch from x/net/context to context. [docker/cli#1038](https://github.com/docker/cli/pull/1038)
+ Add --init option to `docker service create`. [docker/cli#479](https://github.com/docker/cli/pull/479)
+ Fixed bug displaying garbage output for build command when --stream and --quiet flags combined. [docker/cli#1090](https://github.com/docker/cli/pull/1090)
+ Add `init` support in 3.7 schema. [docker/cli#1129](https://github.com/docker/cli/pull/1129)
- Fix docker trust signer removal. [docker/cli#1112](https://github.com/docker/cli/pull/1112)
- Fix error message from docker inspect. [docker/cli#1071](https://github.com/docker/cli/pull/1071)
* Allow `x-*` extension on 3rd level objects. [docker/cli#1097](https://github.com/docker/cli/pull/1097)
* An invalid orchestrator now generates an error instead of being silently ignored. [docker/cli#1055](https://github.com/docker/cli/pull/1055)
* Added ORCHESTRATOR column to docker stack ls command. [docker/cli#973](https://github.com/docker/cli/pull/973)
* Warn when using host-ip for published ports for services. [docker/cli#1017](https://github.com/docker/cli/pull/1017)
+ Added the option to enable experimental cli features through the `DOCKER_CLI_EXPERIMENTAL` environment variable. [docker/cli#1138](https://github.com/docker/cli/pull/1138)
+ Add exec_die to the list of known container events. [docker/cli#1028](https://github.com/docker/cli/pull/1028)
* [K8s] Do env-variable expansion on the uninterpreted Config files. [docker/cli#974](https://github.com/docker/cli/pull/974)
+ Print warnings on stderr for each unsupported features while parsing a compose file for deployment on Kubernetes. [docker/cli#903](https://github.com/docker/cli/pull/903)
+ Added description about pids count. [docker/cli#1045](https://github.com/docker/cli/pull/1045)
- Warn user of filter when pruning. [docker/cli#1043](https://github.com/docker/cli/pull/1043)
- Fix `--rollback-*` options overwriting `--update-*` options. [docker/cli#1052](https://github.com/docker/cli/pull/1052)
* Update Attach, Build, Commit, Cp, Create subcommand fish completions. [docker/cli#1005](https://github.com/docker/cli/pull/1005)
+ Add bash completion for `dockerd --default-address-pool`. [docker/cli#1173](https://github.com/docker/cli/pull/1173)
+ Add bash completion for `exec_die` event. [docker/cli#1173](https://github.com/docker/cli/pull/1173)
* Update docker-credential-helper so `pass` is not called on every docker command. [docker/cli#1184](https://github.com/docker/cli/pull/1184)
* Fix for rotating swarm external CA. [docker/cli#1199](https://github.com/docker/cli/pull/1199)
* Improve version output alignment. [docker/cli#1207](https://github.com/docker/cli/pull/1207)
+ Add bash completion for `service create|update --init`. [docker/cli#1210](https://github.com/docker/cli/pull/1210)

### Deprecation

* Document reserved namespaces deprecation. [docker/cli#1040](https://github.com/docker/cli/pull/1040)

### Logging

* Allow awslogs to use non-blocking mode. [moby/moby#36522](https://github.com/moby/moby/pull/36522)
* Improve logging of long log lines on fluentd log driver.. [moby/moby#36159](https://github.com/moby/moby/pull/36159)
* Re-order CHANGELOG.md to pass `make validate` test. [moby/moby#37047](https://github.com/moby/moby/pull/37047)
* Update Events, Exec, Export, History, Images, Import, Inspect, Load, and Login subcommand fish completions. [docker/cli#1061](https://github.com/docker/cli/pull/1061)
* Update documentation for RingLogger's ring buffer. [moby/moby#37084](https://github.com/moby/moby/pull/37084)
+ Add metrics for log failures/partials. [moby/moby#37034](https://github.com/moby/moby/pull/37034)
- Fix logging plugin crash unrecoverable. [moby/moby#37028](https://github.com/moby/moby/pull/37028)
- Fix logging test type. [moby/moby#37070](https://github.com/moby/moby/pull/37070)
- Fix race conditions in logs API. [moby/moby#37062](https://github.com/moby/moby/pull/37062)
- Fix some issues in logfile reader and rotation. [moby/moby#37063](https://github.com/moby/moby/pull/37063)

### Networking

* Allow user to specify default address pools for docker networks. [moby/moby#36396](https://github.com/moby/moby/pull/36396) [docker/cli#818](https://github.com/docker/cli/pull/818)
* Adding logs for ipam state [docker/libnetwork#2417](https://github.com/docker/libnetwork/pull/2147)
* Fix race conditions in the overlay network driver [docker/libnetwork#2143](https://github.com/docker/libnetwork/pull/2143)
* Add wait time into xtables lock warning [docker/libnetwork#2142](https://github.com/docker/libnetwork/pull/2142)
* filter xtables lock warnings when firewalld is active [docker/libnetwork#2135](https://github.com/docker/libnetwork/pull/2135)
* Switch from x/net/context to context [docker/libnetwork#2140](https://github.com/docker/libnetwork/pull/2140)
* Adding a recovery mechanism for a split gossip cluster [docker/libnetwork#2134](https://github.com/docker/libnetwork/pull/2134)
* Running docker inspect on network attachment tasks now returns a full task object. [moby/moby#35246](https://github.com/moby/moby/pull/35246)
* Some container/network cleanups. [moby/moby#37033](https://github.com/moby/moby/pull/37033)
- Fix network inspect for overlay network. [moby/moby#37045](https://github.com/moby/moby/pull/37045)
* Improve Scalability of the Linux load balancing. [docker/engine#16](https://github.com/docker/engine/pull/16)
* Change log level from error to warning. [docker/engine#19](https://github.com/docker/engine/pull/19)

### Runtime

* Aufs: log why aufs is not supported. [moby/moby#36995](https://github.com/moby/moby/pull/36995)
* Hide experimental checkpoint features on Windows. [docker/cli#1094](https://github.com/docker/cli/pull/1094)
* Lcow: Allow the client to customize capabilities and device cgroup rules for LCOW containers. [moby/moby#37294](https://github.com/moby/moby/pull/37294)
* Changed path given for executable output in windows to actual location of executable output. [moby/moby#37295](https://github.com/moby/moby/pull/37295)
+ Add windows recycle bin test and update hcsshim to v0.6.11. [moby/moby#36994](https://github.com/moby/moby/pull/36994)
* Allow to add any args when doing a make run. [moby/moby#37190](https://github.com/moby/moby/pull/37190)
* Optimize ContainerTop() aka docker top. [moby/moby#37131](https://github.com/moby/moby/pull/37131)
- Fix compilation on 32bit machines. [moby/moby#37292](https://github.com/moby/moby/pull/37292)
* Update API version to v1 38. [moby/moby#37141](https://github.com/moby/moby/pull/37141)
- Fix `docker service update --host-add` does not update existing host entry. [docker/cli#1054](https://github.com/docker/cli/pull/1054)
- Fix swagger file type for ExecIds. [moby/moby#36962](https://github.com/moby/moby/pull/36962)
- Fix swagger volume type generation. [moby/moby#37060](https://github.com/moby/moby/pull/37060)
- Fix wrong assertion in volume/service package. [moby/moby#37211](https://github.com/moby/moby/pull/37211)
- Fix daemon panic on restart when a plugin is running. [moby/moby#37234](https://github.com/moby/moby/pull/37234)
* Construct and add 'LABEL' command from 'label' option to last stage. [moby/moby#37011](https://github.com/moby/moby/pull/37011)
- Fix race condition between exec start and resize.. [moby/moby#37172](https://github.com/moby/moby/pull/37172)
* Alternative failure mitigation of `TestExecInteractiveStdinClose`. [moby/moby#37143](https://github.com/moby/moby/pull/37143)
* RawAccess allows a set of paths to be not set as masked or readonly. [moby/moby#36644](https://github.com/moby/moby/pull/36644)
* Be explicit about github.com prefix being a legacy feature. [moby/moby#37174](https://github.com/moby/moby/pull/37174)
* Bump Golang to 1.10.3. [docker/cli#1122](https://github.com/docker/cli/pull/1122)
* Close ReadClosers to prevent xz zombies. [moby/moby#34218](https://github.com/moby/moby/pull/34218)
* Daemon.ContainerStop(): fix for a negative timeout. [moby/moby#36874](https://github.com/moby/moby/pull/36874)
* Daemon.setMounts(): copy slice in place. [moby/moby#36991](https://github.com/moby/moby/pull/36991)
* Describe IP field of swagger Port definition. [moby/moby#36971](https://github.com/moby/moby/pull/36971)
* Extract volume interaction to a volumes service. [moby/moby#36688](https://github.com/moby/moby/pull/36688)
* Fixed markdown formatting in docker image v1, v1.1, and v1.2 spec. [moby/moby#37051](https://github.com/moby/moby/pull/37051)
* Improve GetTimestamp parsing. [moby/moby#35402](https://github.com/moby/moby/pull/35402)
* Jsonmessage: pass message to aux callback. [moby/moby#37064](https://github.com/moby/moby/pull/37064)
* Overlay2: remove unused cdMountFrom() helper function. [moby/moby#37041](https://github.com/moby/moby/pull/37041)
- Overlay: Fix overlay storage-driver silently ignoring unknown storage-driver options. [moby/moby#37040](https://github.com/moby/moby/pull/37040)
* Remove some unused contrib items. [moby/moby#36977](https://github.com/moby/moby/pull/36977)
* Restartmanager: do not apply restart policy on created containers. [moby/moby#36924](https://github.com/moby/moby/pull/36924)
* Set item-type for ExecIDs. [moby/moby#37121](https://github.com/moby/moby/pull/37121)
* Use go-systemd const instead of magic string in Linux version of dockerd. [moby/moby#37136](https://github.com/moby/moby/pull/37136)
* Use stdlib TLS dialer. [moby/moby#36687](https://github.com/moby/moby/pull/36687)
* Warn when an engine label using a reserved namespace (com.docker.\*, io.docker.\*, or org.dockerproject.\*) is configured, as per [Docker object labels](../manage-resources/labels.md). [moby/moby#36921](https://github.com/moby/moby/pull/36921)
- Fix missing plugin name in message. [moby/moby#37052](https://github.com/moby/moby/pull/37052)
- Fix link anchors in CONTRIBUTING.md. [moby/moby#37276](https://github.com/moby/moby/pull/37276)
- Fix link to Docker Toolbox. [moby/moby#37240](https://github.com/moby/moby/pull/37240)
- Fix mis-used skip condition. [moby/moby#37179](https://github.com/moby/moby/pull/37179)
- Fix bind mounts not working in some cases. [moby/moby#37031](https://github.com/moby/moby/pull/37031)
- Fix fd leak on attach. [moby/moby#37184](https://github.com/moby/moby/pull/37184)
- Fix fluentd partial detection. [moby/moby#37029](https://github.com/moby/moby/pull/37029)
- Fix incorrect link in version-history.md. [moby/moby#37049](https://github.com/moby/moby/pull/37049)
* Allow vim to be case insensitive for D in dockerfile. [moby/moby#37235](https://github.com/moby/moby/pull/37235)
+ Add `t.Name()` to tests so that service names are unique. [moby/moby#37166](https://github.com/moby/moby/pull/37166)
+ Add additional message when backendfs is extfs without d_type support. [moby/moby#37022](https://github.com/moby/moby/pull/37022)
+ Add api version checking for tests from new feature. [moby/moby#37169](https://github.com/moby/moby/pull/37169)
+ Add image metrics for push and pull. [moby/moby#37233](https://github.com/moby/moby/pull/37233)
+ Add support for `init` on services. [moby/moby#37183](https://github.com/moby/moby/pull/37183)
+ Add verification of escapeKeys array length in pkg/term/proxy.go. [moby/moby#36918](https://github.com/moby/moby/pull/36918)
* When link id is empty for overlay2, do not remove this link.. [moby/moby#36161](https://github.com/moby/moby/pull/36161)
- Fix build on OpenBSD by defining Self(). [moby/moby#37301](https://github.com/moby/moby/pull/37301)
- Windows: Fix named pipe support for hyper-v isolated containers. [docker/engine#2](https://github.com/docker/engine/pull/2) [docker/cli#1165](https://github.com/docker/cli/pull/1165)
- Fix manifest lists to always use correct size. [docker/cli#1183](https://github.com/docker/cli/pull/1183)
* Register OCI media types. [docker/engine#4](https://github.com/docker/engine/pull/4)
* Update containerd to v1.1.1 [docker/engine#17](https://github.com/docker/engine/pull/17)
* LCOW: Prefer Windows over Linux in a manifest list. [docker/engine#3](https://github.com/docker/engine/pull/3)
* Add updated `MaskPaths` that are used in code paths directly using containerd to address [CVE-2018-10892](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-10892). [docker/engine#15](https://github.com/docker/engine/pull/15)
* Add `/proc/acpi` to masked paths to address [CVE-2018-10892](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2018-10892). [docker/engine#14](https://github.com/docker/engine/pull/14)
- Fix bindmount autocreate race. [docker/engine#11](https://github.com/docker/engine/pull/11)

### Swarm Mode

* List stacks for both Swarm and Kubernetes with --orchestrator=all in docker stack ls. Allow several occurrences of --namespace for Kubernetes with docker stack ls. [docker/cli#1031](https://github.com/docker/cli/pull/1031)
* Bump SwarmKit to remove deprecated grpc metadata wrappers. [moby/moby#36905](https://github.com/moby/moby/pull/36905)
* Issue an error for --orchestrator=all when working on mismatched Swarm and Kubernetes hosts. [docker/cli#1035](https://github.com/docker/cli/pull/1035)
- Fix broken swarm commands with Kubernetes defined as orchestrator. "--orchestrator" flag is no longer global but local to stack commands and subcommands [docker/cli#1137](https://github.com/docker/cli/pull/1137) [docker/cli#1139](https://github.com/docker/cli/pull/1139)
* Bump swarmkit to include task reaper fixes and more metrics. [docker/engine#13](https://github.com/docker/engine/pull/13)
- Avoid a leak when a service with unassigned tasks is deleted. [docker/engine#27](https://github.com/docker/engine/pull/27)
- Fix racy batching on the dispatcher. [docker/engine#27](https://github.com/docker/engine/pull/27)


---

# Docker Engine 18.09 release notes

*Sección: Engine*

> **Note:**
>
> With this release, the daemon, client and container runtime are now all shipped
> in separate packages. When updating, you need to update all packages at the same
> time to get the latest patch releases for each. For example, on Ubuntu:
> 
> ```console
> $ sudo apt-get install docker-ce docker-ce-cli containerd.io
> ```
> 
> See the [installation instructions](../install/index.md) for the corresponding
> Linux distribution for details.

## 18.09.9
2019-09-03

### Client

* Fix Windows absolute path detection on non-Windows. [docker/cli#1990](https://github.com/docker/cli/pull/1990)
* Fix Docker refusing to load key from delegation.key on Windows. [docker/cli#1968](https://github.com/docker/cli/pull/1968)
* Completion scripts updates for bash and zsh.

### Logging

* Fix for reading journald logs. [moby/moby#37819](https://github.com/moby/moby/pull/37819) [moby/moby#38859](https://github.com/moby/moby/pull/38859)

### Networking

* Prevent panic on network attached to a container with disabled networking. [moby/moby#39589](https://github.com/moby/moby/pull/39589)
* Fix service port for an application becomes unavailable randomly. [docker/libnetwork#2069](https://github.com/docker/libnetwork/pull/2069)
* Fix cleaning up `--config-only` networks `--config-from` networkshave ungracefully exited. [docker/libnetwork#2373](https://github.com/docker/libnetwork/pull/2373)

### Runtime

* Update to Go 1.11.13.
* Fix a potential engine panic when using XFS disk quota for containers. [moby/moby#39644](https://github.com/moby/moby/pull/39644)

### Swarm

* Fix "grpc: received message larger than max" errors. [moby/moby#39306](https://github.com/moby/moby/pull/39306)
* Fix an issue where nodes several tasks could not be removed. [docker/swarmkit#2867](https://github.com/docker/swarmkit/pull/2867)

## 18.09.8
2019-07-17

### Runtime

* Masked the secrets updated to the log files when running Docker Engine in debug mode. [CVE-2019-13509](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-13509): If a Docker engine is running in debug mode, and `docker stack deploy` is used to redeploy a stack which includes non-external secrets, the logs will contain the secret.


### Client

* Fixed rollback config type interpolation for `parallelism` and `max_failure_ratio` fields.

### Known Issue

* There are important changes to the upgrade process that, if not correctly followed, can have an impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or later.

## 18.09.7
2019-06-27

### Builder

* Fixed a panic error when building dockerfiles that contain only comments. [moby/moby#38487](https://github.com/moby/moby/pull/38487)
* Added a workaround for GCR authentication issue. [moby/moby#38246](https://github.com/moby/moby/pull/38246)
* Builder-next: Fixed a bug in the GCR token cache implementation workaround. [moby/moby#39183](https://github.com/moby/moby/pull/39183)

### Networking
*  Fixed an error where `--network-rm` would fail to remove a network. [moby/moby#39174](https://github.com/moby/moby/pull/39174)

### Runtime

* Added performance optimizations in aufs and layer store that helps in massively parallel container creation and removal. [moby/moby#39107](https://github.com/moby/moby/pull/39107), [moby/moby#39135](https://github.com/moby/moby/pull/39135)
* Updated containerd to version 1.2.6. [moby/moby#39016](https://github.com/moby/moby/pull/39016)
* Fixed [CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664) symlink-exchange attack with directory traversal. [moby/moby#39357](https://github.com/moby/moby/pull/39357)
* Windows: fixed support for `docker service create --limit-cpu`. [moby/moby#39190](https://github.com/moby/moby/pull/39190)
* daemon: fixed a mirrors validation issue.  [moby/moby#38991](https://github.com/moby/moby/pull/38991)
* Docker no longer supports sorting UID and GID ranges in ID maps. [moby/moby#39288](https://github.com/moby/moby/pull/39288)

### Logging

* Added a fix that now allows large log lines for logger plugins. [moby/moby#39038](https://github.com/moby/moby/pull/39038)

### Known Issue
* There are  important changes to the upgrade process that, if not correctly followed, can have an impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or later.

## 18.09.6
2019-05-06

### Builder
* Fixed `COPY` and `ADD` with multiple `<src>` to not invalidate cache if `DOCKER_BUILDKIT=1`.[moby/moby#38964](https://github.com/moby/moby/issues/38964)

### Networking
* Cleaned up the cluster provider when the agent is closed. [docker/libnetwork#2354](https://github.com/docker/libnetwork/pull/2354)
* Windows: Now selects a random host port if the user does not specify a host port. [docker/libnetwork#2369](https://github.com/docker/libnetwork/pull/2369)

### Known Issues
* There are  important changes to the upgrade process that, if not correctly followed, can have an impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or later.

## 18.09.5

2019-04-11

### Builder

* Fixed `DOCKER_BUILDKIT=1 docker build --squash ..` [docker/engine#176](https://github.com/docker/engine/pull/176)

### Client

* Fixed tty initial size error. [docker/cli#1775](https://github.com/docker/cli/pull/1775)
* Fixed dial-stdio goroutine leakage. [docker/cli#1795](https://github.com/docker/cli/pull/1795)
* Fixed the stack informer's selector used to track deployment. [docker/cli#1794](https://github.com/docker/cli/pull/1794)

### Networking

* Fixed `network=host` using wrong `resolv.conf` with `systemd-resolved`. [docker/engine#180](https://github.com/docker/engine/pull/180)
* Fixed Windows ARP entries getting corrupted randomly under load. [docker/engine#192](https://github.com/docker/engine/pull/192)

### Runtime
* Now showing stopped containers with restart policy as `Restarting`. [docker/engine#181](https://github.com/docker/engine/pull/181)
* Now using original process spec for execs. [docker/engine#178](https://github.com/docker/engine/pull/178)

### Swarm Mode

* Fixed leaking task resources when nodes are deleted. [docker/engine#185](https://github.com/docker/engine/pull/185)

### Known Issues

* There are  important changes to the upgrade process that, if not correctly followed, can have an impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or later.

## 18.09.4

 2019-03-28

### Builder

* Fixed [CVE-2019-13139](https://nvd.nist.gov/vuln/detail/CVE-2019-13139) by adding validation for `git ref` to avoid misinterpretation as a flag. [moby/moby#38944](https://github.com/moby/moby/pull/38944)

### Runtime

* Fixed `docker cp` error for filenames greater than 100 characters. [moby/moby#38634](https://github.com/moby/moby/pull/38634)
* Fixed `layer/layer_store` to ensure `NewInputTarStream` resources are released. [moby/moby#38413](https://github.com/moby/moby/pull/38413)
* Increased GRPC limit for `GetConfigs`. [moby/moby#38800](https://github.com/moby/moby/pull/38800)
* Updated `containerd` 1.2.5. [docker/engine#173](https://github.com/docker/engine/pull/173)

### Swarm Mode
* Fixed nil pointer exception when joining node to swarm. [moby/moby#38618](https://github.com/moby/moby/issues/38618)
* Fixed issue for swarm nodes not being able to join as masters if http proxy is set. [moby/moby#36951]

### Known Issues
* There are important changes to the upgrade process that, if not correctly followed, can have impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or later.

## 18.09.3

2019-02-28

### Networking fixes
* Windows: now avoids regeneration of network IDs to prevent broken references to networks. [docker/engine#149](https://github.com/docker/engine/pull/149)
* Windows: Fixed an issue to address `- restart always` flag on standalone containers not working when specifying a network. (docker/escalation#1037)
* Fixed an issue to address the IPAM state from networkdb if the manager is not attached to the overlay network. (docker/escalation#1049)

### Runtime fixes and updates

* Updated to Go version 1.10.8.
* Modified names in the container name generator. [docker/engine#159](https://github.com/docker/engine/pull/159)
* When copying an existing folder, xattr set errors when the target filesystem doesn't support xattr are now ignored. [docker/engine#135](https://github.com/docker/engine/pull/135)
* Graphdriver: fixed "device" mode not being detected if "character-device" bit is set. [docker/engine#160](https://github.com/docker/engine/pull/160)
* Fixed nil pointer dereference on failure to connect to containerd. [docker/engine#162](https://github.com/docker/engine/pull/162)
* Deleted stale containerd object on start failure. [docker/engine#154](https://github.com/docker/engine/pull/154)

### Known Issues
* There are important changes to the upgrade process that, if not correctly followed, can have impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or greater.

## 18.09.2

2019-02-11

### Security fixes
* Update `runc` to address a critical vulnerability that allows specially-crafted containers to gain administrative privileges on the host. [CVE-2019-5736](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-5736)
* Ubuntu 14.04 customers using a 3.13 kernel will need to upgrade to a supported Ubuntu 4.x kernel

For additional information, [refer to the Docker blog post](https://blog.docker.com/2019/02/docker-security-update-cve-2018-5736-and-container-security-best-practices/).

### Known Issues
* There are important changes to the upgrade process that, if not correctly followed, can have impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or greater.

## 18.09.1

2019-01-09

#### Important notes about this release

In Docker versions prior to 18.09, containerd was managed by the Docker engine daemon. In Docker Engine 18.09, containerd is managed by systemd. Since containerd is managed by systemd, any custom configuration to the `docker.service` systemd configuration which changes mount settings (for example, `MountFlags=slave`) breaks interactions between the Docker Engine daemon and containerd, and you will not be able to start containers.

Run the following command to get the current value of the `MountFlags` property for the `docker.service`:

```console
$ sudo systemctl show --property=MountFlags docker.service
MountFlags=
```

Update your configuration if this command prints a non-empty value for `MountFlags`, and restart the docker service.

### Security fixes
* Upgraded Go language to 1.10.6 to resolve [CVE-2018-16873](https://nvd.nist.gov/vuln/detail/CVE-2018-16873), [CVE-2018-16874](https://nvd.nist.gov/vuln/detail/CVE-2018-16874), and [CVE-2018-16875](https://nvd.nist.gov/vuln/detail/CVE-2018-16875).
* Fixed authz plugin for 0-length content and path validation.
* Added `/proc/asound` to masked paths [docker/engine#126](https://github.com/docker/engine/pull/126)

### Improvements
* Updated to BuildKit 0.3.3 [docker/engine#122](https://github.com/docker/engine/pull/122)
* Updated to containerd 1.2.2 [docker/engine#144](https://github.com/docker/engine/pull/144)
* Provided additional warnings for use of deprecated legacy overlay and devicemapper storage drivers [docker/engine#85](https://github.com/docker/engine/pull/85)
* prune: perform image pruning before build cache pruning [docker/cli#1532](https://github.com/docker/cli/pull/1532)
* Added bash completion for experimental CLI commands (manifest) [docker/cli#1542](https://github.com/docker/cli/pull/1542)
* Windows: allow process isolation on Windows 10 [docker/engine#81](https://github.com/docker/engine/pull/81)

### Fixes
* Disable kmem accounting in runc on RHEL/CentOS (docker/escalation#614, docker/escalation#692) [docker/engine#121](https://github.com/docker/engine/pull/121)
* Fixed inefficient networking configuration [docker/engine#123](https://github.com/docker/engine/pull/123)
* Fixed docker system prune doesn't accept until filter [docker/engine#122](https://github.com/docker/engine/pull/122)
* Avoid unset credentials in `containerd` [docker/engine#122](https://github.com/docker/engine/pull/122)
* Fixed iptables compatibility on Debian [docker/engine#107](https://github.com/docker/engine/pull/107)
* Fixed setting default schema to tcp for docker host [docker/cli#1454](https://github.com/docker/cli/pull/1454)
* Fixed bash completion for `service update --force`  [docker/cli#1526](https://github.com/docker/cli/pull/1526)
* Windows: DetachVhd attempt in cleanup [docker/engine#113](https://github.com/docker/engine/pull/113)
* API: properly handle invalid JSON to return a 400 status [docker/engine#110](https://github.com/docker/engine/pull/110)
* API: ignore default address-pools on API < 1.39 [docker/engine#118](https://github.com/docker/engine/pull/118)
* API: add missing default address pool fields to swagger [docker/engine#119](https://github.com/docker/engine/pull/119)
* awslogs: account for UTF-8 normalization in limits [docker/engine#112](https://github.com/docker/engine/pull/112)
* Prohibit reading more than 1MB in HTTP error responses [docker/engine#114](https://github.com/docker/engine/pull/114)
* apparmor: allow receiving of signals from `docker kill` [docker/engine#116](https://github.com/docker/engine/pull/116)
* overlay2: use index=off if possible (fix EBUSY on mount) [docker/engine#84](https://github.com/docker/engine/pull/84)

### Packaging
* Add docker.socket requirement for docker.service. [docker/docker-ce-packaging#276](https://github.com/docker/docker-ce-packaging/pull/276)
* Add socket activation for RHEL-based distributions. [docker/docker-ce-packaging#274](https://github.com/docker/docker-ce-packaging/pull/274)
* Add libseccomp requirement for RPM packages. [docker/docker-ce-packaging#266](https://github.com/docker/docker-ce-packaging/pull/266)

### Known Issues
* When upgrading from 18.09.0 to 18.09.1, `containerd` is not upgraded to the correct version on Ubuntu.
* There are important changes to the upgrade process that, if not correctly followed, can have impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or greater.

## 18.09.0

2018-11-08

### Important notes about this release

In Docker versions prior to 18.09, containerd was managed by the Docker engine daemon. In Docker Engine 18.09, containerd is managed by systemd. Since containerd is managed by systemd, any custom configuration to the `docker.service` systemd
configuration which changes mount settings (for example, `MountFlags=slave`) breaks interactions between the Docker Engine daemon and containerd, and you will not be able to start containers.

Run the following command to get the current value of the `MountFlags` property for the `docker.service`:

```console
$ sudo systemctl show --property=MountFlags docker.service
MountFlags=
```

Update your configuration if this command prints a non-empty value for `MountFlags`, and restart the docker service.


### New features

* Updated API version to 1.39 [moby/moby#37640](https://github.com/moby/moby/pull/37640)
* Added support for remote connections using SSH [docker/cli#1014](https://github.com/docker/cli/pull/1014)
* Builder: added prune options to the API [moby/moby#37651](https://github.com/moby/moby/pull/37651)
* Added "Warnings" to `/info` endpoint, and move detection to the daemon [moby/moby#37502](https://github.com/moby/moby/pull/37502)
* Allows BuildKit builds to run without experimental mode enabled. Buildkit can now be configured with an option in daemon.json [moby/moby#37593](https://github.com/moby/moby/pull/37593) [moby/moby#37686](https://github.com/moby/moby/pull/37686) [moby/moby#37692](https://github.com/moby/moby/pull/37692) [docker/cli#1303](https://github.com/docker/cli/pull/1303)  [docker/cli#1275](https://github.com/docker/cli/pull/1275)
* Added support for build-time secrets using a `--secret` flag when using BuildKit [docker/cli#1288](https://github.com/docker/cli/pull/1288)
* Added SSH agent socket forwarder (`docker build --ssh $SSHMOUNTID=$SSH_AUTH_SOCK`) when using BuildKit [docker/cli#1438](https://github.com/docker/cli/pull/1438) / [docker/cli#1419](https://github.com/docker/cli/pull/1419)
* Added `--chown` flag support for `ADD` and `COPY` commands on Windows [moby/moby#35521](https://github.com/moby/moby/pull/35521)
* Added `builder prune` subcommand to prune BuildKit build cache [docker/cli#1295](https://github.com/docker/cli/pull/1295) [docker/cli#1334](https://github.com/docker/cli/pull/1334)
* BuildKit: Adds configurable garbage collection policy for the BuildKit build cache [docker/engine#59](https://github.com/docker/engine/pull/59) / [moby/moby#37846](https://github.com/moby/moby/pull/37846)
* BuildKit: Adds support for `docker build --pull ...` when using BuildKit [moby/moby#37613](https://github.com/moby/moby/pull/37613)
* BuildKit: Adds support or "registry-mirrors" and "insecure-registries" when using BuildKit [docker/engine#59](https://github.com/docker/engine/pull/59) / [moby/moby#37852](https://github.com/moby/moby/pull/37852)
* BuildKit: Enables net modes and bridge. [moby/moby#37620](https://github.com/moby/moby/pull/37620)
* Added `docker engine` subcommand to manage the lifecycle of a Docker Engine running as a privileged container on top of containerd, and to allow upgrades to Docker Engine Enterprise [docker/cli#1260](https://github.com/docker/cli/pull/1260)
* Exposed product license in `docker info` output [docker/cli#1313](https://github.com/docker/cli/pull/1313)
* Showed warnings produced by daemon in `docker info` output [docker/cli#1225](https://github.com/docker/cli/pull/1225)
* Added "local" log driver [moby/moby#37092](https://github.com/moby/moby/pull/37092)
* Amazon CloudWatch: adds `awslogs-endpoint` logging option [moby/moby#37374](https://github.com/moby/moby/pull/37374)
* Added support for global default address pools [moby/moby#37558](https://github.com/moby/moby/pull/37558) [docker/cli#1233](https://github.com/docker/cli/pull/1233)
* Configured containerd log-level to be the same as dockerd [moby/moby#37419](https://github.com/moby/moby/pull/37419)
* Added configuration option for cri-containerd [moby/moby#37519](https://github.com/moby/moby/pull/37519)
* Updates containerd client to v1.2.0-rc.1 [moby/moby#37664](https://github.com/moby/moby/pull/37664), [docker/engine#75](https://github.com/docker/engine/pull/75) / [moby/moby#37710](https://github.com/moby/moby/pull/37710)
* Added support for global default address pools [moby/moby#37558](https://github.com/moby/moby/pull/37558) [docker/cli#1233](https://github.com/docker/cli/pull/1233)
* Moved the `POST /session` endpoint out of experimental. [moby/moby#40028](https://github.com/moby/moby/pull/40028)


### Improvements

* Does not return "`<unknown>`" in /info response [moby/moby#37472](https://github.com/moby/moby/pull/37472)
* BuildKit: Changes `--console=[auto,false,true]` to `--progress=[auto,plain,tty]` [docker/cli#1276](https://github.com/docker/cli/pull/1276)
* BuildKit: Sets BuildKit's ExportedProduct variable to show useful errors in the future. [moby/moby#37439](https://github.com/moby/moby/pull/37439)
* Hides `--data-path-addr` flags when connected to a daemon that doesn't support this option [docker/docker/cli#1240](https://github.com/docker/cli/pull/1240)
* Only shows buildkit-specific flags if BuildKit is enabled [docker/cli#1438](https://github.com/docker/cli/pull/1438) / [docker/cli#1427](https://github.com/docker/cli/pull/1427)
* Improves version output alignment [docker/cli#1204](https://github.com/docker/cli/pull/1204)
* Sorts plugin names and networks in a natural order [docker/cli#1166](https://github.com/docker/cli/pull/1166), [docker/cli#1266](https://github.com/docker/cli/pull/1266)
* Updates bash and zsh [completion scripts](https://github.com/docker/cli/issues?q=label%3Aarea%2Fcompletion+milestone%3A18.09.0+is%3Aclosed)
* Passes log-level to containerd. [moby/moby#37419](https://github.com/moby/moby/pull/37419)
* Uses direct server return (DSR) in east-west overlay load balancing [docker/engine#93](https://github.com/docker/engine/pull/93) / [docker/libnetwork#2270](https://github.com/docker/libnetwork/pull/2270)
* Builder: temporarily disables bridge networking when using buildkit. [moby/moby#37691](https://github.com/moby/moby/pull/37691)
* Blocks task starting until node attachments are ready [moby/moby#37604](https://github.com/moby/moby/pull/37604)
* Propagates the provided external CA certificate to the external CA object in swarm. [docker/cli#1178](https://github.com/docker/cli/pull/1178)
* Removes Ubuntu 14.04 "Trusty Tahr" as a supported platform [docker-ce-packaging#255](https://github.com/docker/docker-ce-packaging/pull/255) / [docker-ce-packaging#254](https://github.com/docker/docker-ce-packaging/pull/254)
* Removes Debian 8 "Jessie" as a supported platform [docker-ce-packaging#255](https://github.com/docker/docker-ce-packaging/pull/255) / [docker-ce-packaging#254](https://github.com/docker/docker-ce-packaging/pull/254)
* Removes 'docker-' prefix for containerd and runc binaries [docker/engine#61](https://github.com/docker/engine/pull/61) / [moby/moby#37907](https://github.com/moby/moby/pull/37907), [docker-ce-packaging#241](https://github.com/docker/docker-ce-packaging/pull/241)
* Splits "engine", "cli", and "containerd" to separate packages, and run containerd as a separate systemd service [docker-ce-packaging#131](https://github.com/docker/docker-ce-packaging/pull/131), [docker-ce-packaging#158](https://github.com/docker/docker-ce-packaging/pull/158)
* Builds binaries with Go 1.10.4 [docker-ce-packaging#181](https://github.com/docker/docker-ce-packaging/pull/181)
* Removes `-ce` suffix from version string [docker-ce-packaging#206](https://github.com/docker/docker-ce-packaging/pull/206)

### Fixes

* BuildKit: Do not cancel buildkit status request. [moby/moby#37597](https://github.com/moby/moby/pull/37597)
* Fixes no error is shown if build args are missing during docker build [moby/moby#37396](https://github.com/moby/moby/pull/37396)
* Fixes error "unexpected EOF" when adding an 8GB file [moby/moby#37771](https://github.com/moby/moby/pull/37771)
* LCOW: Ensures platform is populated on `COPY`/`ADD`. [moby/moby#37563](https://github.com/moby/moby/pull/37563)
* Fixes mapping a range of host ports to a single container port [docker/cli#1102](https://github.com/docker/cli/pull/1102)
* Fixes `trust inspect` typo: "`AdminstrativeKeys`" [docker/cli#1300](https://github.com/docker/cli/pull/1300)
* Fixes environment file parsing for imports of absent variables and those with no name. [docker/cli#1019](https://github.com/docker/cli/pull/1019)
* Fixes a potential "out of memory exception" when running `docker image prune` with a large list of dangling images [docker/cli#1432](https://github.com/docker/cli/pull/1432) / [docker/cli#1423](https://github.com/docker/cli/pull/1423)
* Fixes pipe handling in ConEmu and ConsoleZ on Windows [moby/moby#37600](https://github.com/moby/moby/pull/37600)
* Fixes long startup on windows, with non-hns governed Hyper-V networks [docker/engine#67](https://github.com/docker/engine/pull/67) / [moby/moby#37774](https://github.com/moby/moby/pull/37774)
* Fixes daemon won't start when "runtimes" option is defined both in config file and cli [docker/engine#57](https://github.com/docker/engine/pull/57) / [moby/moby#37871](https://github.com/moby/moby/pull/37871)
* Loosens permissions on `/etc/docker` directory to prevent "permission denied" errors when using `docker manifest inspect` [docker/engine#56](https://github.com/docker/engine/pull/56) / [moby/moby#37847](https://github.com/moby/moby/pull/37847)
* Fixes denial of service with large numbers in `cpuset-cpus` and `cpuset-mems` [docker/engine#70](https://github.com/docker/engine/pull/70) / [moby/moby#37967](https://github.com/moby/moby/pull/37967)
* LCOW: Add `--platform` to `docker import` [docker/cli#1375](https://github.com/docker/cli/pull/1375) / [docker/cli#1371](https://github.com/docker/cli/pull/1371)
* LCOW: Add LinuxMetadata support by default on Windows [moby/moby#37514](https://github.com/moby/moby/pull/37514)
* LCOW: Mount to short container paths to avoid command-line length limit [moby/moby#37659](https://github.com/moby/moby/pull/37659)
* LCOW: Fix builder using wrong cache layer [moby/moby#37356](https://github.com/moby/moby/pull/37356)
* Fixes json-log file descriptors leaking when using `--follow` [docker/engine#48](https://github.com/docker/engine/pull/48) [moby/moby#37576](https://github.com/moby/moby/pull/37576) [moby/moby#37734](https://github.com/moby/moby/pull/37734)
* Fixes a possible deadlock on closing the watcher on kqueue [moby/moby#37392](https://github.com/moby/moby/pull/37392)
* Uses poller based watcher to work around the file caching issue in Windows [moby/moby#37412](https://github.com/moby/moby/pull/37412)
* Handles systemd-resolved case by providing appropriate resolv.conf to networking layer [moby/moby#37485](https://github.com/moby/moby/pull/37485)
* Removes support for TLS < 1.2 [moby/moby#37660](https://github.com/moby/moby/pull/37660)
* Seccomp: Whitelist syscalls linked to `CAP_SYS_NICE` in default seccomp profile [moby/moby#37242](https://github.com/moby/moby/pull/37242)
* Seccomp: move the syslog syscall to be gated by `CAP_SYS_ADMIN` or `CAP_SYSLOG` [docker/engine#64](https://github.com/docker/engine/pull/64) / [moby/moby#37929](https://github.com/moby/moby/pull/37929)
* SELinux: Fix relabeling of local volumes specified via Mounts API on selinux-enabled systems [moby/moby#37739](https://github.com/moby/moby/pull/37739)
* Adds warning if REST API is accessible through an insecure connection [moby/moby#37684](https://github.com/moby/moby/pull/37684)
* Masks proxy credentials from URL when displayed in system info [docker/engine#72](https://github.com/docker/engine/pull/72) / [moby/moby#37934](https://github.com/moby/moby/pull/37934)
* Fixes mount propagation for btrfs [docker/engine#86](https://github.com/docker/engine/pull/86) / [moby/moby#38026](https://github.com/moby/moby/pull/38026)
* Fixes nil pointer dereference in node allocation [docker/engine#94](https://github.com/docker/engine/pull/94) / [docker/swarmkit#2764](https://github.com/docker/swarmkit/pull/2764)

### Known Issues

* There are important changes to the upgrade process that, if not correctly followed, can have impact on the availability of applications running on the Swarm during upgrades. These constraints impact any upgrades coming from any version before 18.09 to version 18.09 or greater.
* With https://github.com/boot2docker/boot2docker/releases/download/v18.09.0/boot2docker.iso, connection is being refused from a node on the virtual machine. Any publishing of swarm ports in virtualbox-created docker-machine VM's will not respond. This is occurring on macOS and Windows 10, using docker-machine version 0.15 and 0.16.

   The following `docker run` command works, allowing access from host browser:

   `docker run -d -p 4000:80 nginx`

   However, the following `docker service` command fails, resulting in curl/chrome unable to connect (connection refused):

   `docker service create -p 5000:80 nginx`

   This issue is not apparent when provisioning 18.09.0 cloud VM's using docker-machine.

   Workarounds:
   * Use cloud VM's that don't rely on boot2docker.
   * `docker run` is unaffected.
   * For Swarm, set VIRTUALBOX_BOOT2DOCKER_URL=https://github.com/boot2docker/boot2docker/releases/download/v18.06.1-ce/boot2docker.iso.

   This issue is resolved in 18.09.1.

### Deprecation Notices

- Docker has deprecated support for Device Mapper as a storage driver. It will continue to be
supported at this time, but support will be removed in a future release.

  The [Overlay2 storage driver](../storage/drivers/overlayfs-driver.md) is now the default for Docker Engine implementations.

For more information on the list of deprecated flags and APIs, have a look at the [deprecation information](/engine/deprecated/) where you can find the target removal dates.

### End of Life Notification

In this release, Docker has also removed support for TLS < 1.2 [moby/moby#37660](https://github.com/moby/moby/pull/37660),
Ubuntu 14.04 "Trusty Tahr" [docker-ce-packaging#255](https://github.com/docker/docker-ce-packaging/pull/255) / [docker-ce-packaging#254](https://github.com/docker/docker-ce-packaging/pull/254), and Debian 8 "Jessie" [docker-ce-packaging#255](https://github.com/docker/docker-ce-packaging/pull/255) / [docker-ce-packaging#254](https://github.com/docker/docker-ce-packaging/pull/254).


---

# Docker Engine 19.03 release notes

*Sección: Engine*

## 19.03.15
2021-02-01

### Security

* [CVE-2021-21285](https://github.com/moby/moby/security/advisories/GHSA-6fj5-m822-rqx8) Prevent an invalid image from crashing docker daemon
* [CVE-2021-21284](https://github.com/moby/moby/security/advisories/GHSA-7452-xqpj-6rpc) Lock down file permissions to prevent remapped root from accessing docker state
* Ensure AppArmor and SELinux profiles are applied when building with BuildKit

### Client

* Check contexts before importing them to reduce risk of extracted files escaping context store

## 19.03.14
2020-12-01

### Security

- [CVE-2020-15257](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15257):
  Update bundled static binaries of containerd to v1.3.9 [moby/moby#41731](https://github.com/moby/moby/pull/41731).
  Package managers should update the containerd.io package.

### Builder

- Beta versions of apparmor are now parsed correctly preventing build failures [moby/moby#41542](https://github.com/moby/moby/pull/41542)

### Networking

- Fix panic when swarmkit service keeps failing to start [moby/moby#41635](https://github.com/moby/moby/pull/41635)

### Runtime

- Return correct errors instead of spurious -EINVAL [moby/moby#41293](https://github.com/moby/moby/pull/41293)

### Rootless

- Lock state dir for preventing automatic clean-up by systemd-tmpfiles [moby/moby#41635](https://github.com/moby/moby/pull/41635)
- dockerd-rootless.sh: support new containerd shim socket path convention [moby/moby#41557](https://github.com/moby/moby/pull/41557)

### Logging

- gcplogs: Fix memory/connection leak [moby/moby#41522](https://github.com/moby/moby/pull/41522)
- awslogs: Support for AWS imdsv2 [moby/moby#41494](https://github.com/moby/moby/pull/41494)

## 19.03.13
2020-09-16

### Builder

- buildkit: Fix nil dereference in cache logic [moby/moby#41279](https://github.com/moby/moby/pull/41279)
- buildkit: Treat Unix sockets as regular files during COPY/ADD [moby/moby#41269](https://github.com/moby/moby/pull/41269)
- buildkit: Ignore system and security xattrs in calculation to ensure consistent COPY caching regardless of SELinux environment [moby/moby#41222](https://github.com/moby/moby/pull/41222)
- buildkit: Make `--cache-from` behavior more reliable [moby/moby#41222](https://github.com/moby/moby/pull/41222)
- buildkit: Fix infinite loop burning CPU when exporting cache [moby/moby#41185](https://github.com/moby/moby/pull/41185)

### Client

- Bump Golang 1.13.15 [docker/cli#2674](https://github.com/docker/cli/pull/2674)
- Fix config file permission issues (~/.docker/config.json) [docker/cli#2631](https://github.com/docker/cli/pull/2631)
- build: Fix panic on terminals with zero height [docker/cli#2719](https://github.com/docker/cli/pull/2719)
- windows: Fix potential issue with newline character in console [docker/cli#2623](https://github.com/docker/cli/pull/2623)

### Networking

- Clean up network sandbox on failure [moby/moby#41081](https://github.com/moby/moby/pull/41081)
- Fix shallow error messages by forwarding deadline-related errors to user [moby/moby#41312](https://github.com/moby/moby/pull/41312)
- Fix leaking of netns file descriptors [moby/moby#41287](https://github.com/moby/moby/41287)

### Rootless

- Fix port forwarder resource leak [moby/moby#41277](https://github.com/moby/moby/pull/41277)

### Runtime

- Bump Golang 1.13.15 [moby/moby#41334](https://github.com/moby/moby/pull/41334)
- Update to containerd 1.3.7 [moby/moby#40408](https://github.com/moby/moby/pull/40408)

### Windows

- Fix slow Windows container start time when using servercore image [moby/moby#41192](https://github.com/moby/moby/pull/41192)

## 19.03.12
2020-06-18

### Client

- Fix bug preventing logout from registry when using multiple config files (e.g. Windows vs WSL2 when using Docker Desktop) [docker/cli#2592](https://github.com/docker/cli/pull/2592)
- Fix regression preventing context metadata to be read [docker/cli#2586](https://github.com/docker/cli/pull/2586)
- Bump Golang 1.13.12 [docker/cli#2575](https://github.com/docker/cli/pull/2575)

### Networking

- Fix regression preventing daemon start up in a systemd-nspawn environment [moby/moby#41124](https://github.com/moby/moby/pull/41124) [moby/libnetwork#2567](https://github.com/moby/libnetwork/pull/2567)
- Fix the retry logic for creating overlay networks in swarm [moby/moby#41124](https://github.com/moby/moby/pull/41124) [moby/libnetwork#2565](https://github.com/moby/libnetwork/pull/2565)

### Runtime

- Bump Golang 1.13.12 [moby/moby#41082](https://github.com/moby/moby/pull/41082)


## 19.03.11
2020-06-01

### Network

Disable IPv6 Router Advertisements to prevent address spoofing. [CVE-2020-13401](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-13401)

**Description**

In the Docker default configuration, the container network interface is a virtual ethernet link going to the host (veth interface).
In this configuration, an attacker able to run a process as root in a container can send and receive arbitrary packets to the host using the `CAP_NET_RAW` capability (present in the default configuration).

If IPv6 is not totally disabled on the host (via `ipv6.disable=1` on the kernel cmdline), it will be either unconfigured or configured on some interfaces, but it’s pretty likely that ipv6 forwarding is disabled, that is, `/proc/sys/net/ipv6/conf//forwarding == 0`. Also by default, `/proc/sys/net/ipv6/conf//accept_ra == 1`. The combination of these 2 sysctls means that the host accepts router advertisements and configures the IPv6 stack using them.

By sending “rogue” router advertisements from a container, an attacker can reconfigure the host to redirect part or all of the IPv6 traffic of the host to the attacker-controlled container.

Even if there was no IPv6 traffic before, if the DNS returns A (IPv4) and AAAA (IPv6) records, many HTTP libraries will try to connect via IPv6 first then fallback to IPv4, giving an opportunity to the attacker to respond.
If by chance the host has a vulnerability like last year’s RCE in apt (CVE-2019-3462), the attacker can now escalate to the host.

As `CAP_NET_ADMIN` is not present by default for Docker containers, the attacker can’t configure the IPs they want to MitM, they can’t use iptables to NAT or REDIRECT the traffic, and they can’t use `IP_TRANSPARENT`.
The attacker can however still use `CAP_NET_RAW` and implement a tcp/ip stack in user space.

See [kubernetes/kubernetes#91507](https://github.com/kubernetes/kubernetes/issues/91507) for related issues.

## 19.03.10
2020-05-29

### Client
- Fix version negotiation with older engine. [docker/cli#2538](https://github.com/docker/cli/pull/2538)
- Avoid setting SSH flags through hostname. [docker/cli#2560](https://github.com/docker/cli/pull/2560)
- Fix panic when DOCKER_CLI_EXPERIMENTAL is invalid. [docker/cli#2558](https://github.com/docker/cli/pull/2558)
- Avoid potential panic on s390x by upgrading Go to 1.13.11. [docker/cli#2532](https://github.com/docker/cli/pull/2532)

### Networking
- Fix DNS fallback regression. [moby/moby#41009](https://github.com/moby/moby/pull/41009)

### Runtime
- Avoid potential panic on s390x by upgrading Go to 1.13.11. [moby/moby#40978](https://github.com/moby/moby/pull/40978)

### Packaging
- Fix ARM builds on ARM64. [moby/moby#41027](https://github.com/moby/moby/pull/41027)

## 19.03.9
2020-05-14

### Builder
- buildkit: Fix concurrent map write panic when building multiple images in parallel. [moby/moby#40780](https://github.com/moby/moby/pull/40780)
- buildkit: Fix issue preventing chowning of non-root-owned files between stages with userns. [moby/moby#40955](https://github.com/moby/moby/pull/40955)
- Avoid creation of irrelevant temporary files on Windows. [moby/moby#40877](https://github.com/moby/moby/pull/40877)

### Client
- Fix panic on single-character volumes. [docker/cli#2471](https://github.com/docker/cli/pull/2471)
- Lazy daemon feature detection to avoid long timeouts on simple commands. [docker/cli#2442](https://github.com/docker/cli/pull/2442)
- docker context inspect on Windows is now faster. [docker/cli#2516](https://github.com/docker/cli/pull/2516)
- Bump Golang 1.13.10. [docker/cli#2431](https://github.com/docker/cli/pull/2431)
- Bump gopkg.in/yaml.v2 to v2.2.8. [docker/cli#2470](https://github.com/docker/cli/pull/2470)

### Logging
- Avoid situation preventing container logs to rotate due to closing a closed log file. [moby/moby#40921](https://github.com/moby/moby/pull/40921)

### Networking
- Fix potential panic upon restart. [moby/moby#40809](https://github.com/moby/moby/pull/40809)
- Assign the correct network value to the default bridge Subnet field. [moby/moby#40565](https://github.com/moby/moby/pull/40565)

### Runtime
- Fix docker crash when creating namespaces with UID in /etc/subuid and /etc/subgid. [moby/moby#40562](https://github.com/moby/moby/pull/40562)
- Improve ARM platform matching. [moby/moby#40758](https://github.com/moby/moby/pull/40758)
- overlay2: show backing filesystem. [moby/moby#40652](https://github.com/moby/moby/pull/40652)
- Update CRIU to v3.13 "Silicon Willet". [moby/moby#40850](https://github.com/moby/moby/pull/40850)
- Only show registry v2 schema1 deprecation warning upon successful fallback, as opposed to any registry error. [moby/moby#40681](https://github.com/moby/moby/pull/40681)
- Use FILE_SHARE_DELETE for log files on Windows. [moby/moby#40563](https://github.com/moby/moby/pull/40563)
- Bump Golang 1.13.10. [moby/moby#40803](https://github.com/moby/moby/pull/40803)

### Rootless
- Now rootlesskit-docker-proxy returns detailed error message on exposing privileged ports. [moby/moby#40863](https://github.com/moby/moby/pull/40863)
- Supports numeric ID in /etc/subuid and /etc/subgid. [moby/moby#40951](https://github.com/moby/moby/pull/40951)

### Security
- apparmor: add missing rules for userns. [moby/moby#40564](https://github.com/moby/moby/pull/40564)
- SElinux: fix ENOTSUP errors not being detected when relabeling. [moby/moby#40946](https://github.com/moby/moby/pull/40946)

### Swarm
- Increase refill rate for logger to avoid hanging on service logs. [moby/moby#40628](https://github.com/moby/moby/pull/40628)
- Fix issue where single swarm manager is stuck in Down state after reboot. [moby/moby#40831](https://github.com/moby/moby/pull/40831)
- tasks.db no longer grows indefinitely. [moby/moby#40831](https://github.com/moby/moby/pull/40831)

## 19.03.8
2020-03-10

### Runtime

- Improve mitigation for [CVE-2019-14271](https://nvd.nist.gov/vuln/detail/CVE-2019-14271) for some nscd configuration.

## 19.03.7
2020-03-03

### Builder

- builder-next: Fix deadlock issues in corner cases. [moby/moby#40557](https://github.com/moby/moby/pull/40557)

### Runtime

* overlay: remove modprobe execs. [moby/moby#40462](https://github.com/moby/moby/pull/40462)
* selinux: display better error messages when setting file labels. [moby/moby#40547](https://github.com/moby/moby/pull/40547)
* Speed up initial stats collection. [moby/moby#40549](https://github.com/moby/moby/pull/40549)
- rootless: use certs.d from XDG_CONFIG_HOME. [moby/moby#40461](https://github.com/moby/moby/pull/40461)
- Bump Golang 1.12.17. [moby/moby#40533](https://github.com/moby/moby/pull/40533) 
- Bump google.golang.org/grpc to v1.23.1. [moby/moby#40566](https://github.com/moby/moby/pull/40566)
- Update containerd binary to v1.2.13. [moby/moby#40540](https://github.com/moby/moby/pull/40540)
- Prevent showing stopped containers as running in an edge case. [moby/moby#40555](https://github.com/moby/moby/pull/40555)
- Prevent potential lock. [moby/moby#40604](https://github.com/moby/moby/pull/40604)

### Client

- Bump Golang 1.12.17. [docker/cli#2342](https://github.com/docker/cli/pull/2342)
- Bump google.golang.org/grpc to v1.23.1. [docker/cli#1884](https://github.com/docker/cli/pull/1884) [docker/cli#2373](https://github.com/docker/cli/pull/2373)

## 19.03.6
2020-02-12

### Builder

- builder-next: Allow modern sign hashes for ssh forwarding. [docker/engine#453](https://github.com/docker/engine/pull/453)
- builder-next: Clear onbuild rules after triggering. [docker/engine#453](https://github.com/docker/engine/pull/453)
- builder-next: Fix issue with directory permissions when usernamespaces is enabled. [moby/moby#40440](https://github.com/moby/moby/pull/40440)
- Bump hcsshim to fix docker build failing on Windows 1903. [docker/engine#429](https://github.com/docker/engine/pull/429)

### Networking

- Shorten controller ID in exec-root to not hit UNIX_PATH_MAX. [docker/engine#424](https://github.com/docker/engine/pull/424)
- Fix panic in drivers/overlay/encryption.go. [docker/engine#424](https://github.com/docker/engine/pull/424)
- Fix hwaddr set race between us and udev. [docker/engine#439](https://github.com/docker/engine/pull/439)

### Runtime

* Bump Golang 1.12.16. [moby/moby#40433](https://github.com/moby/moby/pull/40433)
* Update containerd binary to v1.2.12. [moby/moby#40433](https://github.com/moby/moby/pull/40453)
* Update to runc v1.0.0-rc10. [moby/moby#40433](https://github.com/moby/moby/pull/40453)
- Fix possible runtime panic in Lgetxattr. [docker/engine#454](https://github.com/docker/engine/pull/454)
- rootless: fix proxying UDP packets. [docker/engine#434](https://github.com/docker/engine/pull/434)

## 19.03.5
2019-11-14

### Builder

* builder-next: Added `entitlements` in builder config. [docker/engine#412](https://github.com/docker/engine/pull/412)
* Fix builder-next: permission errors on using build secrets or ssh forwarding with userns-remap. [docker/engine#420](https://github.com/docker/engine/pull/420)
* Fix builder-next: copying a symlink inside an already copied directory. [docker/engine#420](https://github.com/docker/engine/pull/420)

### Packaging

* Support RHEL 8 packages

### Runtime

* Bump Golang to 1.12.12. [docker/engine#418](https://github.com/docker/engine/pull/418)
* Update to RootlessKit to v0.7.0 to harden slirp4netns with mount namespace and seccomp. [docker/engine#397](https://github.com/docker/engine/pull/397)
* Fix to propagate GetContainer error from event processor. [docker/engine#407](https://github.com/docker/engine/pull/407)
* Fix push of OCI image. [docker/engine#405](https://github.com/docker/engine/pull/405)

## 19.03.4
2019-10-17

### Networking

* Rollback libnetwork changes to fix `DOCKER-USER` iptables chain issue. [docker/engine#404](https://github.com/docker/engine/pull/404)

### Known Issues

#### Existing

* In some circumstances with large clusters, Docker information might, as part of the Swarm section,
  include the error `code = ResourceExhausted desc = grpc: received message larger than
  max (5351376 vs. 4194304)`. This does not indicate any failure or misconfiguration by the user,
  and requires no response.
* Orchestrator port conflict can occur when redeploying all services as new. Due to many Swarm manager
  requests in a short amount of time, some services are not able to receive traffic and are causing a `404`
  error after being deployed.
     - **Workaround:** restart all tasks via `docker service update --force`.
* [CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664) symlink-exchange attack with directory traversal. Workaround until proper fix is available in upcoming patch release: `docker pause` container before doing file operations. [moby/moby#39252](https://github.com/moby/moby/pull/39252)
* `docker cp` regression due to CVE mitigation. An error is produced when the source of `docker cp` is set to `/`.

## 19.03.3
2019-10-08

### Security

* Patched `runc` in containerd. [CVE-2017-18367](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-18367)

### Builder

* Fix builder-next: resolve digest for third party registries. [docker/engine#339](https://github.com/docker/engine/pull/339)

* Fix builder-next: user namespace builds when daemon started with socket activation. [docker/engine#373](https://github.com/docker/engine/pull/373)

* Fix builder-next; session: release forwarded ssh socket connection per connection. [docker/engine#373](https://github.com/docker/engine/pull/373)

* Fix build-next: llbsolver: error on multiple cache importers. [docker/engine#373](https://github.com/docker/engine/pull/373)

### Client

* Added support for Docker Template 0.1.6.

* Mitigate against YAML files that have excessive aliasing. [docker/cli#2119](https://github.com/docker/cli/pull/2119)

### Runtime

* Bump Golang to 1.12.10. [docker/engine#387](https://github.com/docker/engine/pull/387)

* Bump containerd to 1.2.10. [docker/engine#385](https://github.com/docker/engine/pull/385)

* Distribution: modify warning logic when pulling v2 schema1 manifests. [docker/engine#368](https://github.com/docker/engine/pull/368)

* Fix `POST /images/create` returning a 500 status code when providing an incorrect platform option. [docker/engine#365](https://github.com/docker/engine/pull/365)

* Fix `POST /build` returning a 500 status code when providing an incorrect platform option. [docker/engine#365](https://github.com/docker/engine/pull/365)

* Fix panic on 32-bit ARMv7 caused by misaligned struct member. [docker/engine#363](https://github.com/docker/engine/pull/363)

* Fix to return "invalid parameter" when linking to non-existing container. [docker/engine#352](https://github.com/docker/engine/pull/352)

* Fix overlay2: busy error on mount when using kernel >= 5.2. [docker/engine#332](https://github.com/docker/engine/pull/332)

* Fix `docker rmi` stuck in certain misconfigured systems, e.g. dead NFS share. [docker/engine#335](https://github.com/docker/engine/pull/335)

* Fix handling of blocked I/O of exec'd processes. [docker/engine#296](https://github.com/docker/engine/pull/296)

* Fix jsonfile logger: follow logs stuck when `max-size` is set and `max-file=1`. [docker/engine#378](https://github.com/docker/engine/pull/378)

### Known Issues

#### New

* `DOCKER-USER` iptables chain is missing: [docker/for-linux#810](https://github.com/docker/for-linux/issues/810).
  Users cannot perform additional container network traffic filtering on top of
  this iptables chain. You are not affected by this issue if you are not
  customizing iptable chains on top of `DOCKER-USER`.
     - **Workaround:** Insert the iptables chain after the docker daemon starts.
       For example:
       ```
       iptables -N DOCKER-USER
       iptables -I FORWARD -j DOCKER-USER
       iptables -A DOCKER-USER -j RETURN
       ```

#### Existing

* In some circumstances with large clusters, docker information might, as part of the Swarm section,
  include the error `code = ResourceExhausted desc = grpc: received message larger than
  max (5351376 vs. 4194304)`. This does not indicate any failure or misconfiguration by the user,
  and requires no response.
* Orchestrator port conflict can occur when redeploying all services as new. Due to many swarm manager
  requests in a short amount of time, some services are not able to receive traffic and are causing a `404`
  error after being deployed.
     - **Workaround:** restart all tasks via `docker service update --force`.
* [CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664) symlink-exchange attack with directory traversal. Workaround until proper fix is available in upcoming patch release: `docker pause` container before doing file operations. [moby/moby#39252](https://github.com/moby/moby/pull/39252)
* `docker cp` regression due to CVE mitigation. An error is produced when the source of `docker cp` is set to `/`.

## 19.03.2
2019-09-03

### Builder

* Fix `COPY --from` to non-existing directory on Windows. [moby/moby#39695](https://github.com/moby/moby/pull/39695)

* Fix builder-next: metadata commands not having created time in history. [moby/moby#39456](https://github.com/moby/moby/issues/39456)

* Fix builder-next: close progress on layer export error. [moby/moby#39782](https://github.com/moby/moby/pull/39782)

* Update buildkit to 588c73e1e4. [moby/moby#39781](https://github.com/moby/moby/pull/39781)

### Client

* Fix Windows absolute path detection on non-Windows [docker/cli#1990](https://github.com/docker/cli/pull/1990)

* Fix to zsh completion script for `docker login --username`.

* Fix context: produce consistent output on `context create`. [docker/cli#1985](https://github.com/docker/cli/pull/1874)

* Fix support for HTTP proxy env variable. [docker/cli#2059](https://github.com/docker/cli/pull/2059)

### Logging

* Fix for reading journald logs. [moby/moby#37819](https://github.com/moby/moby/pull/37819) [moby/moby#38859](https://github.com/moby/moby/pull/38859)

### Networking

* Prevent panic on network attached to a container with disabled networking. [moby/moby#39589](https://github.com/moby/moby/pull/39589)

### Runtime

* Bump Golang to 1.12.8.

* Fix a potential engine panic when using XFS disk quota for containers. [moby/moby#39644](https://github.com/moby/moby/pull/39644)

### Swarm

* Fix an issue where nodes with several tasks could not be removed. [docker/swarmkit#2867](https://github.com/docker/swarmkit/pull/2867)

### Known issues

* In some circumstances with large clusters, docker information might, as part of the Swarm section,
  include the error `code = ResourceExhausted desc = grpc: received message larger than
  max (5351376 vs. 4194304)`. This does not indicate any failure or misconfiguration by the user,
  and requires no response.
* Orchestrator port conflict can occur when redeploying all services as new. Due to many swarm manager
  requests in a short amount of time, some services are not able to receive traffic and are causing a `404`
  error after being deployed.
     - Workaround: restart all tasks via `docker service update --force`.

* Traffic cannot egress the HOST because of missing Iptables rules in the FORWARD chain
  The missing rules are :
     ```
     /sbin/iptables --wait -C FORWARD -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
     /sbin/iptables --wait -C FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
     ```
     - Workaround: Add these rules back using a script and cron definitions. The script
     must contain '-C' commands to check for the presence of a rule and '-A' commands to add
     rules back. Run the script on a cron in regular intervals, for example, every <x> minutes.
     - Affected versions: 18.09.1, 19.03.0
* [CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664) symlink-exchange attack with directory traversal. Workaround until proper fix is available in upcoming patch release: `docker pause` container before doing file operations. [moby/moby#39252](https://github.com/moby/moby/pull/39252)
* `docker cp` regression due to CVE mitigation. An error is produced when the source of `docker cp` is set to `/`.

## 19.03.1
2019-07-25

### Security

 * Fixed loading of nsswitch based config inside chroot under Glibc. [CVE-2019-14271](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-14271)

### Known issues

 * In some circumstances, in large clusters, docker information might, as part of the Swarm section,
 include the error `code = ResourceExhausted desc = grpc: received message larger than
 max (5351376 vs. 4194304)`. This does not indicate any failure or misconfiguration by the user,
 and requires no response.
 * Orchestrator port conflict can occur when redeploying all services as new. Due to many swarm manager
 requests in a short amount of time, some services are not able to receive traffic and are causing a `404`
 error after being deployed.
    - Workaround: restart all tasks via `docker service update --force`.

 * Traffic cannot egress the HOST because of missing Iptables rules in the FORWARD chain
 The missing rules are :
     ```
     /sbin/iptables --wait -C FORWARD -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
     /sbin/iptables --wait -C FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
     ```
     - Workaround: Add these rules back using a script and cron definitions. The script
     must contain '-C' commands to check for the presence of a rule and '-A' commands to add
     rules back. Run the script on a cron in regular intervals, for example, every <x> minutes.
     - Affected versions: 18.09.1, 19.03.0
 * [CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664) symlink-exchange attack with directory traversal. Workaround until proper fix is available in upcoming patch release: `docker pause` container before doing file operations. [moby/moby#39252](https://github.com/moby/moby/pull/39252)
 * `docker cp` regression due to CVE mitigation. An error is produced when the source of `docker cp` is set to `/`.

## 19.03.0
2019-07-22

### Builder

* Fixed `COPY --from` to preserve ownership. [moby/moby#38599](https://github.com/moby/moby/pull/38599)
* builder-next:

    - Added inline cache support `--cache-from`. [docker/engine#215](https://github.com/docker/engine/pull/215)
    - Outputs configuration allowed. [moby/moby#38898](https://github.com/moby/moby/pull/38898)
    - Fixed gcr workaround token cache. [docker/engine#212](https://github.com/docker/engine/pull/212)
    - `stopprogress` called on download error. [docker/engine#215](https://github.com/docker/engine/pull/215)
    - Buildkit now uses systemd's `resolv.conf`. [docker/engine#260](https://github.com/docker/engine/pull/260).
    - Setting buildkit outputs now allowed. [docker/cli#1766](https://github.com/docker/cli/pull/1766)
    - Look for Dockerfile specific dockerignore file (for example, Dockerfile.dockerignore) for
        ignored paths. [docker/engine#215](https://github.com/docker/engine/pull/215)
    - Automatically detect if process execution is possible for x86, arm, and arm64 binaries.
        [docker/engine#215](https://github.com/docker/engine/pull/215)
    - Updated buildkit to 1f89ec1. [docker/engine#260](https://github.com/docker/engine/pull/260)
    - Use Dockerfile frontend version `docker/dockerfile:1.1` by default.
        [docker/engine#215](https://github.com/docker/engine/pull/215)
    - No longer rely on an external image for COPY/ADD operations.
        [docker/engine#215](https://github.com/docker/engine/pull/215)

### Client

* Added `--pids-limit` flag to `docker update`. [docker/cli#1765](https://github.com/docker/cli/pull/1765)
* Added systctl support for services. [docker/cli#1754](https://github.com/docker/cli/pull/1754)
* Added support for `template_driver` in compose files. [docker/cli#1746](https://github.com/docker/cli/pull/1746)
* Added `--device` support for Windows. [docker/cli#1606](https://github.com/docker/cli/pull/1606)
* Added support for Data Path Port configuration. [docker/cli#1509](https://github.com/docker/cli/pull/1509)
* Added fast context switch: commands. [docker/cli#1501](https://github.com/docker/cli/pull/1501)
* Support added for `--mount type=bind,bind-nonrecursive,...` [docker/cli#1430](https://github.com/docker/cli/pull/1430)
* Added maximum replicas per node. [docker/cli#1612](https://github.com/docker/cli/pull/1612)
* Added option to pull images quietly. [docker/cli#882](https://github.com/docker/cli/pull/882)
* Added a separate `--domainname` flag. [docker/cli#1130](https://github.com/docker/cli/pull/1130)
* Added support for secret drivers in `docker stack deploy`. [docker/cli#1783](https://github.com/docker/cli/pull/1783)
* Added ability to use swarm `Configs` as `CredentialSpecs` on services.
[docker/cli#1781](https://github.com/docker/cli/pull/1781)
* Added `--security-opt systempaths=unconfined` support. [docker/cli#1808](https://github.com/docker/cli/pull/1808)
* Added basic framework for writing and running CLI plugins. [docker/cli#1564](https://github.com/docker/cli/pull/1564)
  [docker/cli#1898](https://github.com/docker/cli/pull/1898)
* Bumped Docker App to v0.8.0. [docker/docker-ce-packaging#341](https://github.com/docker/docker-ce-packaging/pull/341)
* Added support for Docker buildx. [docker/docker-ce-packaging#336](https://github.com/docker/docker-ce-packaging/pull/336)
* Added support for Docker Assemble v0.36.0.
* Added support for Docker Cluster v1.0.0-rc2.
* Added support for Docker Template v0.1.4.
* Added support for Docker Registry v0.1.0-rc1.
* Bumped google.golang.org/grpc to v1.20.1. [docker/cli#1884](https://github.com/docker/cli/pull/1884)
* CLI changed to pass driver specific options to `docker run`. [docker/cli#1767](https://github.com/docker/cli/pull/1767)
* Bumped Golang 1.12.5. [docker/cli#1875](https://github.com/docker/cli/pull/1875)
* `docker system info` output now segregates information relevant to the client and daemon.
[docker/cli#1638](https://github.com/docker/cli/pull/1638)
* (Experimental) When targeting Kubernetes, added support for `x-pull-secret: some-pull-secret` in
compose-files service configs. [docker/cli#1617](https://github.com/docker/cli/pull/1617)
* (Experimental) When targeting Kubernetes, added support for `x-pull-policy: <Never|Always|IfNotPresent>`
in compose-files service configs. [docker/cli#1617](https://github.com/docker/cli/pull/1617)
* cp, save, export: Now preventing overwriting irregular files. [docker/cli#1515](https://github.com/docker/cli/pull/1515)
* npipe volume type on stack file now allowed. [docker/cli#1195](https://github.com/docker/cli/pull/1195)
* Fixed tty initial size error. [docker/cli#1529](https://github.com/docker/cli/pull/1529)
* Fixed problem with labels copying value from environment variables.
[docker/cli#1671](https://github.com/docker/cli/pull/1671)

### API

* Updated API version to v1.40. [moby/moby#38089](https://github.com/moby/moby/pull/38089)
* Added warnings to `/info` endpoint, and moved detection to the daemon.
[moby/moby#37502](https://github.com/moby/moby/pull/37502)
* Added HEAD support for `/_ping` endpoint. [moby/moby#38570](https://github.com/moby/moby/pull/38570)
* Added `Cache-Control` headers to disable caching `/_ping` endpoint.
[moby/moby#38569](https://github.com/moby/moby/pull/38569)
* Added `containerd`, `runc`, and `docker-init` versions to `/version`.
[moby/moby#37974](https://github.com/moby/moby/pull/37974)
* Added undocumented `/grpc` endpoint and registered BuildKit's controller.
[moby/moby#38990](https://github.com/moby/moby/pull/38990)

### Experimental
* Enabled checkpoint/restore of containers with TTY. [moby/moby#38405](https://github.com/moby/moby/pull/38405)
* LCOW: Added support for memory and CPU limits. [moby/moby#37296](https://github.com/moby/moby/pull/37296)
* Windows: Added ContainerD runtime. [moby/moby#38541](https://github.com/moby/moby/pull/38541)
* Windows: LCOW now requires Windows RS5+. [moby/moby#39108](https://github.com/moby/moby/pull/39108)

### Security

* mount: added BindOptions.NonRecursive (API v1.40). [moby/moby#38003](https://github.com/moby/moby/pull/38003)
* seccomp: whitelisted `io_pgetevents()`. [moby/moby#38895](https://github.com/moby/moby/pull/38895)
* seccomp: `ptrace(2)` for 4.8+ kernels now allowed. [moby/moby#38137](https://github.com/moby/moby/pull/38137)

### Runtime

* Running `dockerd` as a non-root user (Rootless mode) is now allowed.
[moby/moby#380050](https://github.com/moby/moby/pull/38050)
* Rootless: optional support provided for `lxc-user-nic` SUID binary.
[docker/engine#208](https://github.com/docker/engine/pull/208)
* Added DeviceRequests to HostConfig to support NVIDIA GPUs. [moby/moby#38828](https://github.com/moby/moby/pull/38828)
* Added `--device` support for Windows. [moby/moby#37638](https://github.com/moby/moby/pull/37638)
* Added `memory.kernelTCP` support for linux. [moby/moby#37043](https://github.com/moby/moby/pull/37043)
* Windows credential specs can now be passed directly to the engine.
[moby/moby#38777](https://github.com/moby/moby/pull/38777)
* Added pids-limit support in docker update. [moby/moby#32519](https://github.com/moby/moby/pull/32519)
* Added support for exact list of capabilities. [moby/moby#38380](https://github.com/moby/moby/pull/38380)
* daemon: Now use 'private' ipc mode by default. [moby/moby#35621](https://github.com/moby/moby/pull/35621)
* daemon: switched to semaphore-gated WaitGroup for startup tasks. [moby/moby#38301](https://github.com/moby/moby/pull/38301)
* Now use `idtools.LookupGroup` instead of parsing `/etc/group` file for docker.sock ownership to
fix: `api.go doesn't respect nsswitch.conf`. [moby/moby#38126](https://github.com/moby/moby/pull/38126)
* cli: fixed images filter when using multi reference filter. [moby/moby#38171](https://github.com/moby/moby/pull/38171)
* Bumped Golang to 1.12.5. [docker/engine#209](https://github.com/docker/engine/pull/209)
* Bumped `containerd` to 1.2.6. [moby/moby#39016](https://github.com/moby/moby/pull/39016)
* Bumped `runc` to 1.0.0-rc8, opencontainers/selinux v1.2.2. [docker/engine#210](https://github.com/docker/engine/pull/210)
* Bumped `google.golang.org/grpc` to v1.20.1. [docker/engine#215](https://github.com/docker/engine/pull/215)
* Performance optimized in aufs and layer store for massively parallel container creation/removal.
[moby/moby#39135](https://github.com/moby/moby/pull/39135) [moby/moby#39209](https://github.com/moby/moby/pull/39209)
* Root is now passed to chroot for chroot Tar/Untar (CVE-2018-15664)
[moby/moby#39292](https://github.com/moby/moby/pull/39292)
* Fixed `docker --init` with /dev bind mount. [moby/moby#37665](https://github.com/moby/moby/pull/37665)
* The right device number is now fetched when greater than 255 and using the `--device-read-bps` option.
[moby/moby#39212](https://github.com/moby/moby/pull/39212)
* Fixed `Path does not exist` error when path definitely exists. [moby/moby#39251](https://github.com/moby/moby/pull/39251)

### Networking

* Moved IPVLAN driver out of experimental.
[moby/moby#38983](https://github.com/moby/moby/pull/38983)
* Added support for 'dangling' filter. [moby/moby#31551](https://github.com/moby/moby/pull/31551)
[docker/libnetwork#2230](https://github.com/docker/libnetwork/pull/2230)
* Load balancer sandbox is now deleted when a service is updated with `--network-rm`.
[docker/engine#213](https://github.com/docker/engine/pull/213)
* Windows: Now forcing a nil IP specified in `PortBindings` to IPv4zero (0.0.0.0).
[docker/libnetwork#2376](https://github.com/docker/libnetwork/pull/2376)

### Swarm

* Added support for maximum replicas per node. [moby/moby#37940](https://github.com/moby/moby/pull/37940)
* Added support for GMSA CredentialSpecs from Swarmkit configs. [moby/moby#38632](https://github.com/moby/moby/pull/38632)
* Added support for sysctl options in services. [moby/moby#37701](https://github.com/moby/moby/pull/37701)
* Added support for filtering on node labels. [moby/moby#37650](https://github.com/moby/moby/pull/37650)
* Windows: Support added for named pipe mounts in docker service create + stack yml.
[moby/moby#37400](https://github.com/moby/moby/pull/37400)
* VXLAN UDP Port configuration now supported. [moby/moby#38102](https://github.com/moby/moby/pull/38102)
* Now using Service Placement Constraints in Enforcer. [docker/swarmkit#2857](https://github.com/docker/swarmkit/pull/2857)
* Increased max recv gRPC message size for nodes and secrets.
[docker/engine#256](https://github.com/docker/engine/pull/256)

### Logging

* Enabled gcplogs driver on Windows. [moby/moby#37717](https://github.com/moby/moby/pull/37717)
* Added zero padding for RFC5424 syslog format. [moby/moby#38335](https://github.com/moby/moby/pull/38335)
* Added `IMAGE_NAME` attribute to `journald` log events. [moby/moby#38032](https://github.com/moby/moby/pull/38032)

### Deprecation

* Deprecate image manifest v2 schema1 in favor of v2 schema2. Future version of Docker will remove
support for v2 schema1 althogether. [moby/moby#39365](https://github.com/moby/moby/pull/39365)
* Removed v1.10 migrator. [moby/moby#38265](https://github.com/moby/moby/pull/38265)
* Now skipping deprecated storage-drivers in auto-selection. [moby/moby#38019](https://github.com/moby/moby/pull/38019)
* Deprecated `aufs` storage driver and added warning. [moby/moby#38090](https://github.com/moby/moby/pull/38090)
* Removed support for 17.09.

For more information on deprecated flags and APIs, refer to
[deprecation information](/engine/deprecated/) for target removal dates.

### Known issues

* In some circumstances with large clusters, docker information might, as part of the Swarm section,
include the error `code = ResourceExhausted desc = grpc: received message larger than
max (5351376 vs. 4194304)`. This does not indicate any failure or misconfiguration by the user,
and requires no response.
* Orchestrator port conflict can occur when redeploying all services as new. Due to many swarm manager
requests in a short amount of time, some services are not able to receive traffic and are causing a `404`
error after being deployed.
   - Workaround: restart all tasks via `docker service update --force`.

* Traffic cannot egress the HOST because of missing Iptables rules in the FORWARD chain
The missing rules are :
    ```
    /sbin/iptables --wait -C FORWARD -o docker_gwbridge -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    /sbin/iptables --wait -C FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    ```
    - Workaround: Add these rules back using a script and cron definitions. The script
    must contain '-C' commands to check for the presence of a rule and '-A' commands to add
    rules back. Run the script on a cron in regular intervals, for example, every <x> minutes.
    - Affected versions: 18.09.1, 19.03.0
* [CVE-2018-15664](https://nvd.nist.gov/vuln/detail/CVE-2018-15664) symlink-exchange attack with directory traversal. Workaround until proper fix is available in upcoming patch release: `docker pause` container before doing file operations. [moby/moby#39252](https://github.com/moby/moby/pull/39252)
* `docker cp` regression due to CVE mitigation. An error is produced when the source of `docker cp` is set to `/`.


---

# Docker Engine 20.10 release notes

*Sección: Engine*

This document describes the latest changes, additions, known issues, and fixes
for Docker Engine version 20.10.

## 20.10.24
{{< release-date date="2023-04-04" >}}

### Updates

- Update Go runtime to [1.19.7](https://go.dev/doc/devel/release#go1.19.minor).
- Update Docker Buildx to [v0.10.4](https://github.com/docker/buildx/releases/tag/v0.10.4).
- Update containerd to [v1.6.20](https://github.com/containerd/containerd/releases/tag/v1.6.20).
- Update runc to [v1.1.5](https://github.com/opencontainers/runc/releases/tag/v1.1.5).

### Bug fixes and enhancements

- Fixed a number of issues that can cause Swarm encrypted overlay networks
  to fail to uphold their guarantees, addressing [CVE-2023-28841](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28841),
  [CVE-2023-28840](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28840), and
  [CVE-2023-28842](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28842).
  - A lack of kernel support for encrypted overlay networks now reports
    as an error.
  - Encrypted overlay networks are eagerly set up, rather than waiting for
    multiple nodes to attach.
  - Encrypted overlay networks are now usable on Red Hat Enterprise Linux 9
    through the use of the `xt_bpf` kernel module.
  - Users of Swarm overlay networks should review [GHSA-vwm3-crmr-xfxw](https://github.com/moby/moby/security/advisories/GHSA-vwm3-crmr-xfxw)
    to ensure that unintentional exposure has not occurred.
- Upgrade github.com/containerd/fifo to v1.1.0 to fix a potential panic [moby/moby#45216](https://github.com/moby/moby/pull/45242).
- Fix missing Bash completion for installed cli-plugins [docker/cli#4091](https://github.com/docker/cli/pull/4091).


## 20.10.23
{{< release-date date="2023-01-19" >}}

This release of Docker Engine contains updated versions of Docker Compose,
Docker Buildx, containerd, and some minor bug fixes and enhancements.

### Updates

- Update Docker Compose to [v2.15.1](https://github.com/docker/compose/releases/tag/v2.15.1).
- Update Docker Buildx to [v0.10.0](https://github.com/docker/buildx/releases/tag/v0.10.0).
- Update containerd (`containerd.io` package) to [v1.6.15](https://github.com/containerd/containerd/releases/tag/v1.6.15).
- Update the package versioning format for `docker-compose-cli` to allow distribution version updates [docker/docker-ce-packaging#822](https://github.com/docker/docker-ce-packaging/pull/822).
- Update Go runtime to [1.18.10](https://go.dev/doc/devel/release#go1.18.minor),

### Bug fixes and enhancements

- Fix an issue where `docker build` would fail when using `--add-host=host.docker.internal:host-gateway`
  with BuildKit enabled [moby/moby#44650](https://github.com/moby/moby/pull/44650).
- Revert seccomp: block socket calls to `AF_VSOCK` in default profile [moby/moby#44712](https://github.com/moby/moby/pull/44712).

  This change, while favorable from a security standpoint, caused a change
  in behavior for some use-cases. As such, we are reverting it to ensure
  stability and compatibility for the affected users.

  However, users of `AF_VSOCK` in containers should recognize that this
  (special) address family is not currently namespaced in any version of
  the Linux kernel, and may result in unexpected behavior, like containers
  communicating directly with host hypervisors.

  Future releases, will filter `AF_VSOCK`. Users who need to allow containers
  to communicate over the unnamespaced `AF_VSOCK` will need to turn off seccomp
  confinement or set a custom seccomp profile.

## 20.10.22
{{< release-date date="2022-12-16" >}}

This release of Docker Engine contains updated versions of Docker Compose,
Docker Scan, containerd, and some minor bug fixes and enhancements.

### Updates

- Update Docker Compose to [v2.14.1](https://github.com/docker/compose/releases/tag/v2.14.1).
- Update Docker Scan to [v0.23.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.23.0).
- Update containerd (`containerd.io` package) to [v1.6.13](https://github.com/containerd/containerd/releases/tag/v1.6.13),
  to include a fix for [CVE-2022-23471](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23471).
- Update Go runtime to [1.18.9](https://go.dev/doc/devel/release#go1.18.minor),
  to include fixes for
  [CVE-2022-41716](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41716),
  [CVE-2022-41717](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41717), and
  [CVE-2022-41720](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41720).

### Bug fixes and enhancements

- Improve error message when attempting to pull an unsupported image format or OCI artifact
  [moby/moby#44413](https://github.com/moby/moby/pull/44413),
  [moby/moby#44569](https://github.com/moby/moby/pull/44569). 
- Fix an issue where the host's ephemeral port-range was ignored when selecting random ports for containers [moby/moby#44476](https://github.com/moby/moby/pull/44476).
- Fix `ssh: parse error in message type 27` errors during `docker build` on hosts using OpenSSH 8.9 or above [moby/moby#3862](https://github.com/moby/moby/pull/3862).
- seccomp: block socket calls to `AF_VSOCK` in default profile [moby/moby#44564](https://github.com/moby/moby/pull/44564).


## 20.10.21
{{< release-date date="2022-10-25" >}}

This release of Docker Engine contains updated versions of Docker Compose,
Docker Scan, containerd, added packages for Ubuntu 22.10, and some minor bug
fixes and enhancements.

### New
- Provide packages for Ubuntu 22.10 (Kinetic Kudu).
- Add support for `allow-nondistributable-artifacts` towards Docker Hub [moby/moby#44313](https://github.com/moby/moby/pull/44313).

### Updates

- Update Docker Compose to [v2.12.2](https://github.com/docker/compose/releases/tag/v2.12.2).
- Update Docker Scan to [v0.21.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.21.0).
- Update containerd (`containerd.io` package) to [v1.6.9](https://github.com/containerd/containerd/releases/tag/v1.6.9).
- Update bundled BuildKit version to fix `output clipped, log limit 1MiB reached` errors [moby/moby#44339](https://github.com/moby/moby/pull/44339).

### Bug fixes and enhancements
- Remove experimental gate for `--platform` in bash completion [docker/cli#3824](https://github.com/docker/cli/pull/3824).
- Fix an `Invalid standard handle identifier` panic when  registering the Docker Engine as a service from a legacy CLI on Windows [moby/moby#44326](https://github.com/moby/moby/pull/44326).
- Fix running Git commands in Cygwin on Windows [moby/moby#44332](https://github.com/moby/moby/pull/44332).

## 20.10.20
{{< release-date date="2022-10-18" >}}

This release of Docker Engine contains partial mitigations for a Git vulnerability
([CVE-2022-39253](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253)),
and has updated handling of `image:tag@digest` image references.

The Git vulnerability allows a maliciously crafted Git repository, when used as a
build context, to copy arbitrary filesystem paths into resulting containers/images;
this can occur in both the daemon, and in API clients, depending on the versions and
tools in use.

The mitigations available in this release and in other consumers of the daemon API
are partial and only protect users who build a Git URL context (e.g. `git+protocol://`).
As the vulnerability could still be exploited by manually run Git commands that interact
with and check out submodules, users should immediately upgrade to a patched version of
Git to protect against this vulnerability. Further details are available from the GitHub
blog (["Git security vulnerabilities announced"](https://github.blog/2022-10-18-git-security-vulnerabilities-announced/)).

### Updates

- Update Docker Compose to [v2.12.0](https://github.com/docker/compose/releases/tag/v2.12.0).
- Updated handling of `image:tag@digest` references. When pulling an image using
  the `image:tag@digest` ("pull by digest"), image resolution happens through
  the content-addressable digest and the `image` and `tag` are not used. While
  this is expected, this could lead to confusing behavior, and could potentially
  be exploited through social engineering to run an image that is already present
  in the local image store. Docker now checks if the digest matches the repository
  name used to pull the image, and otherwise will produce an error.
- Updated handling of `image:tag@digest` references. Refer to the "Daemon" section
  above for details.

### Bug fixes and enhancements

- Added a mitigation for [CVE-2022-39253](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253),
  when using the classic Builder with a Git URL as the build context.
- Added a mitigation to the classic Builder and updated BuildKit to [v0.8.3-31-gc0149372](https://github.com/moby/buildkit/commit/c014937225cba29cfb1d5161fd134316c0e9bdaa),
  for [CVE-2022-39253](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-39253).

## 20.10.19
{{< release-date date="2022-10-14" >}}

This release of Docker Engine comes with some bug-fixes, and an updated version
of Docker Compose.

### Updates

- Update Docker Compose to [v2.11.2](https://github.com/docker/compose/releases/tag/v2.11.2).
- Update Go runtime to [1.18.7](https://go.dev/doc/devel/release#go1.18.minor),
  which contains fixes for [CVE-2022-2879](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-2879),
  [CVE-2022-2880](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-2880),
  and [CVE-2022-41715](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-41715).

### Bug fixes and enhancements

- Fix an issue that could result in a panic during `docker builder prune` or
  `docker system prune` [moby/moby#44122](https://github.com/moby/moby/pull/44122).
- Fix a bug where using `docker volume prune` would remove volumes that were
  still in use if the daemon was running with "live restore" and was restarted
  [moby/moby#44238](https://github.com/moby/moby/pull/44238).

## 20.10.18
{{< release-date date="2022-09-09" >}}

This release of Docker Engine comes with a fix for a low-severity security issue,
some minor bug fixes, and updated versions of Docker Compose, Docker Buildx,
`containerd`, and `runc`.

### Updates

- Update Docker Buildx to [v0.9.1](https://github.com/docker/buildx/releases/tag/v0.9.1).
- Update Docker Compose to [v2.10.2](https://github.com/docker/compose/releases/tag/v2.10.2).
- Update containerd (`containerd.io` package) to [v1.6.8](https://github.com/containerd/containerd/releases/tag/v1.6.8).
- Update runc version to [v1.1.4](https://github.com/opencontainers/runc/releases/tag/v1.1.4).
- Update Go runtime to [1.18.6](https://go.dev/doc/devel/release#go1.18.minor),
  which contains fixes for [CVE-2022-27664](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-27664) and
  [CVE-2022-32190](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-32190).

### Bug fixes and enhancements

- Add Bash completion for Docker Compose [docker/cli#3752](https://github.com/docker/cli/pull/3752).
- Fix an issue where file-capabilities were not preserved during build
  [moby/moby#43876](https://github.com/moby/moby/pull/43876).
- Fix an issue that could result in a panic caused by a concurrent map read and
  map write [moby/moby#44067](https://github.com/moby/moby/pull/44067).
- Fix a security vulnerability relating to supplementary group permissions, which
  could allow a container process to bypass primary group restrictions within the
  container [CVE-2022-36109](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-36109),
  [GHSA-rc4r-wh2q-q6c4](https://github.com/moby/moby/security/advisories/GHSA-rc4r-wh2q-q6c4).
- seccomp: add support for Landlock syscalls in default policy [moby/moby#43991](https://github.com/moby/moby/pull/43991).
- seccomp: update default policy to support new syscalls introduced in kernel 5.12 - 5.16 [moby/moby#43991](https://github.com/moby/moby/pull/43991).
- Fix an issue where cache lookup for image manifests would fail, resulting
  in a redundant round-trip to the image registry [moby/moby#44109](https://github.com/moby/moby/pull/44109).
- Fix an issue where `exec` processes and healthchecks were not terminated
  when they timed out [moby/moby#44018](https://github.com/moby/moby/pull/44018).

## 20.10.17
{{< release-date date="2022-06-06" >}}

This release of Docker Engine comes with updated versions of Docker Compose and the
`containerd`, and `runc` components, as well as some minor bug fixes.

### Updates

- Update Docker Compose to [v2.6.0](https://github.com/docker/compose/releases/tag/v2.6.0).
- Update containerd (`containerd.io` package) to [v1.6.6](https://github.com/containerd/containerd/releases/tag/v1.6.6),
  which contains a fix for [CVE-2022-31030](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-31030)
- Update runc version to [v1.1.2](https://github.com/opencontainers/runc/releases/tag/v1.1.2), which contains a fix for
  [CVE-2022-29162](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29162).
- Update Go runtime to [1.17.11](https://go.dev/doc/devel/release#go1.17.minor),
  which contains fixes for [CVE-2022-30634](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30634),
  [CVE-2022-30629](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30629),
  [CVE-2022-30580](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-30580) and
  [CVE-2022-29804](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29804)

### Bug fixes and enhancements

- Remove asterisk from docker commands in zsh completion script [docker/cli#3648](https://github.com/docker/cli/pull/3648).
- Fix Windows port conflict with published ports in host mode for overlay [moby/moby#43644](https://github.com/moby/moby/pull/43644).
- Ensure performance tuning is always applied to libnetwork sandboxes [moby/moby#43683](https://github.com/moby/moby/pull/43683).

## 20.10.16
{{< release-date date="2022-05-12" >}}

This release of Docker Engine fixes a regression in the Docker CLI builds for
macOS, fixes an issue with `docker stats` when using containerd 1.5 and up,
and updates the Go runtime to include a fix for [CVE-2022-29526](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29526).

### Updates
- Update golang.org/x/sys dependency which contains a fix for
  [CVE-2022-29526](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29526).
- Updated the `golang.org/x/sys` build-time dependency which contains a fix for [CVE-2022-29526](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29526).
- Updated Go runtime to [1.17.10](https://go.dev/doc/devel/release#go1.17.minor),
  which contains a fix for [CVE-2022-29526](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29526).

### Bug fixes and enhancements
- Fixed a regression in binaries for macOS introduced in [20.10.15](#201015), which
  resulted in a panic [docker/cli#43426](https://github.com/docker/cli/pull/3592).
- Fixed an issue where `docker stats` was showing empty stats when running with
  containerd 1.5.0 or up [moby/moby#43567](https://github.com/moby/moby/pull/43567).
- Used "weak" dependencies for the `docker scan` CLI plugin, to prevent a
  "conflicting requests" error when users performed an off-line installation from
  downloaded RPM packages [docker/docker-ce-packaging#659](https://github.com/docker/docker-ce-packaging/pull/659).

## 20.10.15
{{< release-date date="2022-05-05" >}}

This release of Docker Engine comes with updated versions of the `compose`,
`buildx`, `containerd`, and `runc` components, as well as some minor bug fixes.

### Updates
- Update Docker Compose to [v2.5.0](https://github.com/docker/compose/releases/tag/v2.5.0).
- Update Docker Buildx to [v0.8.2](https://github.com/docker/buildx/releases/tag/v0.8.2).
- Update Go runtime to [1.17.9](https://go.dev/doc/devel/release#go1.17.minor).
- Update containerd (`containerd.io` package) to [v1.6.4](https://github.com/containerd/containerd/releases/tag/v1.6.4).
- Update runc version to [v1.1.1](https://github.com/opencontainers/runc/releases/tag/v1.1.1).

### Bug fixes and enhancements
- Use a RWMutex for stateCounter to prevent potential locking congestion [moby/moby#43426](https://github.com/moby/moby/pull/43426).
- Prevent an issue where the daemon was unable to find an available IP-range in
  some conditions [moby/moby#43360](https://github.com/moby/moby/pull/43360) 
- Add packages for CentOS 9 stream and Fedora 36.

### Known issues
- We've identified an issue with the [macOS CLI binaries](https://download.docker.com/mac/static/stable/)
in the 20.10.15 release. This issue has been resolved in the [20.10.16](#201016) release.

## 20.10.14
{{< release-date date="2022-03-23" >}}

This release of Docker Engine updates the default inheritable capabilities for
containers to address [CVE-2022-24769](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24769),
a new version of the `containerd.io` runtime is also included to address the same
issue.

### Updates
- Update the default inheritable capabilities.
- Update the default inheritable capabilities for containers used during build.
- Update containerd (`containerd.io` package) to [v1.5.11](https://github.com/containerd/containerd/releases/tag/v1.5.11).
- Update `docker buildx` to [v0.8.1](https://github.com/docker/buildx/releases/tag/v0.8.1).

## 20.10.13
{{< release-date date="2022-03-10" >}} 

This release of Docker Engine contains some bug-fixes and packaging changes,
updates to the `docker scan` and `docker buildx` commands, an updated version of
the Go runtime, and new versions of the `containerd.io` runtime.
Together with this release, we now also provide `.deb` and `.rpm` packages of
Docker Compose V2, which can be installed using the (optional) `docker-compose-plugin`
package.

### New
- Provide `.deb` and `.rpm` packages for Docker Compose V2. [Docker Compose v2.3.3](https://github.com/docker/compose/releases/tag/v2.3.3)
  can now be installed on Linux using the `docker-compose-plugin` packages, which
  provides the `docker compose` subcommand on the Docker CLI. The Docker Compose
  plugin can also be installed and run standalone to be used as a drop-in replacement
  for `docker-compose` (Docker Compose V1) [docker/docker-ce-packaging#638](https://github.com/docker/docker-ce-packaging/pull/638).
  The `compose-cli-plugin` package can also be used on older version of the Docker
  CLI with support for CLI plugins (Docker CLI 18.09 and up).
- Provide packages for the upcoming Ubuntu 22.04 "Jammy Jellyfish" LTS release [docker/docker-ce-packaging#645](https://github.com/docker/docker-ce-packaging/pull/645), [docker/containerd-packaging#271](https://github.com/docker/containerd-packaging/pull/271).

### Updates
- Updated the bundled version of buildx to [v0.8.0](https://github.com/docker/buildx/releases/tag/v0.8.0).
- Update `docker buildx` to [v0.8.0](https://github.com/docker/buildx/releases/tag/v0.8.0).
- Update `docker scan` (`docker-scan-plugin`) to [v0.17.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.17.0).
- Update containerd (`containerd.io` package) to [v1.5.10](https://github.com/containerd/containerd/releases/tag/v1.5.10).
- Update the bundled runc version to [v1.0.3](https://github.com/opencontainers/runc/releases/tag/v1.0.3).
- Update Golang runtime to Go 1.16.15.
- Updates the fluentd log driver to prevent a potential daemon crash, and prevent
  containers from hanging when using the `fluentd-async-connect=true` and the
  remote server is unreachable [moby/moby#43147](https://github.com/moby/moby/pull/43147).

### Bug fixes and enhancements
- Fix a race condition when updating the container's state [moby/moby#43166](https://github.com/moby/moby/pull/43166).
- Update the etcd dependency to prevent the daemon from incorrectly holding file locks [moby/moby#43259](https://github.com/moby/moby/pull/43259)
- Fix detection of user-namespaces when configuring the default `net.ipv4.ping_group_range` sysctl [moby/moby#43084](https://github.com/moby/moby/pull/43084).
- Retry downloading image-manifests if a connection failure happens during image
  pull [moby/moby#43333](https://github.com/moby/moby/pull/43333).
- Various fixes in command-line reference and API documentation.
- Prevent an OOM when using the "local" logging driver with containers that produce
  a large amount of log messages [moby/moby#43165](https://github.com/moby/moby/pull/43165).

## 20.10.12
2021-12-13

This release of Docker Engine contains changes in packaging only, and provides
updates to the `docker scan` and `docker buildx` commands. Versions of `docker scan`
before v0.11.0 are not able to detect the [Log4j 2 CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228).
We are shipping an updated version of `docker scan` in this release to help you
scan your images for this vulnerability.

> [!NOTE]
>
> The `docker scan` command on Linux is currently only supported on x86 platforms.
> We do not yet provide a package for other hardware architectures on Linux.

The `docker scan` feature is provided as a separate package and, depending on your
upgrade or installation method, 'docker scan' may not be updated automatically to
the latest version. Use the instructions below to update `docker scan` to the latest
version. You can also use these instructions to install, or upgrade the `docker scan`
package without upgrading the Docker Engine:

On `.deb` based distributions, such as Ubuntu and Debian:

```console
$ apt-get update && apt-get install docker-scan-plugin
```

On rpm-based distributions, such as CentOS or Fedora:

```console
$ yum install docker-scan-plugin
```

After upgrading, verify you have the latest version of `docker scan` installed:

```console
$ docker scan --accept-license --version
Version:    v0.12.0
Git commit: 1074dd0
Provider:   Snyk (1.790.0 (standalone))
```

[Read our blog post on CVE-2021-44228](https://www.docker.com/blog/apache-log4j-2-cve-2021-44228/)
to learn how to use the `docker scan` command to check if images are vulnerable.

### Packaging

- Update `docker scan` to [v0.12.0](https://github.com/docker/scan-cli-plugin/releases/tag/v0.12.0).
- Update `docker buildx` to [v0.7.1](https://github.com/docker/buildx/releases/tag/v0.7.1).
- Update Golang runtime to Go 1.16.12.


## 20.10.11
2021-11-17

> [!IMPORTANT]
>
> Due to [net/http changes](https://github.com/golang/go/issues/40909) in [Go 1.16](https://golang.org/doc/go1.16#net/http), HTTP proxies configured through the `$HTTP_PROXY` environment variable are no longer used for TLS (`https://`) connections. Make sure you also set an `$HTTPS_PROXY` environment variable for handling requests to `https://` URLs. Refer to [Configure the daemon to use a proxy](../daemon/proxy.md) to learn how to configure the Docker Daemon to use a proxy server.


### Distribution

- Handle ambiguous OCI manifest parsing to mitigate [CVE-2021-41190](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41190) / [GHSA-mc8v-mgrf-8f4m](https://github.com/opencontainers/distribution-spec/security/advisories/GHSA-mc8v-mgrf-8f4m).
  See [GHSA-xmmx-7jpf-fx42](https://github.com/moby/moby/security/advisories/GHSA-xmmx-7jpf-fx42) for details.

### Windows

- Fix panic.log file having read-only attribute set [moby/moby#42987](https://github.com/moby/moby/pull/42987).

### Packaging

- Update containerd to [v1.4.12](https://github.com/containerd/containerd/releases/tag/v1.4.12) to mitigate [CVE-2021-41190](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41190).
- Update Golang runtime to Go 1.16.10.


## 20.10.10
2021-10-25

> [!IMPORTANT]
>
> Due to [net/http changes](https://github.com/golang/go/issues/40909) in [Go 1.16](https://golang.org/doc/go1.16#net/http), HTTP proxies configured through the `$HTTP_PROXY` environment variable are no longer used for TLS (`https://`) connections. Make sure you also set an `$HTTPS_PROXY` environment variable for handling requests to `https://` URLs. Refer to the [HTTP/HTTPS proxy section](../daemon/proxy.md) to learn how to configure the Docker Daemon to use a proxy server.


### Builder

- Fix platform-matching logic to fix `docker build` using not finding images in
  the local image cache on Arm machines when using BuildKit [moby/moby#42954](https://github.com/moby/moby/pull/42954)

### Runtime

- Add support for `clone3` syscall in the default seccomp policy to support running
  containers based on recent versions of Fedora and Ubuntu. [moby/moby/#42836](https://github.com/moby/moby/pull/42836).
- Windows: update hcsshim library to fix a bug in sparse file handling in container
  layers, which was exposed by recent changes in Windows [moby/moby#42944](https://github.com/moby/moby/pull/42944).
- Fix some situations where `docker stop` could hang forever [moby/moby#42956](https://github.com/moby/moby/pull/42956).

### Swarm

- Fix an issue where updating a service did not roll back on failure [moby/moby#42875](https://github.com/moby/moby/pull/42875).

### Packaging

- Add packages for Ubuntu 21.10 "Impish Indri" and Fedora 35.
- Update `docker scan` to v0.9.0
- Update Golang runtime to Go 1.16.9.

## 20.10.9
2021-10-04

This release is a security release with security fixes in the CLI, runtime, as
well as updated versions of the containerd.io package.

> [!IMPORTANT]
>
> Due to [net/http changes](https://github.com/golang/go/issues/40909) in [Go 1.16](https://golang.org/doc/go1.16#net/http), HTTP proxies configured through the `$HTTP_PROXY` environment variable are no longer used for TLS (`https://`) connections. Make sure you also set an `$HTTPS_PROXY` environment variable for handling requests to `https://` URLs. Refer to the [HTTP/HTTPS proxy section](../daemon/proxy.md) to learn how to configure the Docker Daemon to use a proxy server.

### Client

- [CVE-2021-41092](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41092)
  Ensure default auth config has address field set, to prevent credentials being
  sent to the default registry.

### Runtime

- [CVE-2021-41089](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41089)
  Create parent directories inside a chroot during `docker cp` to prevent a specially
  crafted container from changing permissions of existing files in the host’s filesystem.
- [CVE-2021-41091](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41091)
  Lock down file permissions to prevent unprivileged users from discovering and
  executing programs in `/var/lib/docker`.

### Packaging

> **Known issue**
>
> The `ctr` binary shipping with the static packages of this release is not
> statically linked, and will not run in Docker images using alpine as a base
> image. Users can install the `libc6-compat` package, or download a previous
> version of the `ctr` binary as a workaround. Refer to the containerd ticket
> related to this issue for more details: [containerd/containerd#5824](https://github.com/containerd/containerd/issues/5824).

- Update Golang runtime to Go 1.16.8, which contains fixes for [CVE-2021-36221](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-36221)
  and [CVE-2021-39293](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-39293)
- Update static binaries and containerd.io rpm and deb packages to containerd
  v1.4.11 and runc v1.0.2 to address [CVE-2021-41103](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-41103).
- Update the bundled buildx version to v0.6.3 for rpm and deb packages.

## 20.10.8
2021-08-03

> [!IMPORTANT]
>
> Due to [net/http changes](https://github.com/golang/go/issues/40909) in [Go 1.16](https://golang.org/doc/go1.16#net/http), HTTP proxies configured through the `$HTTP_PROXY` environment variable are no longer used for TLS (`https://`) connections. Make sure you also set an `$HTTPS_PROXY` environment variable for handling requests to `https://` URLs. Refer to the [HTTP/HTTPS proxy section](../daemon/proxy.md) to learn how to configure the Docker Daemon to use a proxy server.

### Deprecation

- Deprecate support for encrypted TLS private keys. Legacy PEM encryption as
  specified in RFC 1423 is insecure by design. Because it does not authenticate
  the ciphertext, it is vulnerable to padding oracle attacks that can let an
  attacker recover the plaintext. Support for encrypted TLS private keys is now
  marked as deprecated, and will be removed in an upcoming release. [docker/cli#3219](https://github.com/docker/cli/pull/3219)
- Deprecate Kubernetes stack support. Following the deprecation of [Compose on Kubernetes](https://github.com/docker/compose-on-kubernetes),
  support for Kubernetes in the `stack` and `context` commands in the Docker CLI
  is now marked as deprecated, and will be removed in an upcoming release [docker/cli#3174](https://github.com/docker/cli/pull/3174).

### Client

- Fix `Invalid standard handle identifier` errors on Windows [docker/cli#3132](https://github.com/docker/cli/pull/3132).

### Rootless

- Avoid `can't open lock file /run/xtables.lock: Permission denied` error on
  SELinux hosts [moby/moby#42462](https://github.com/moby/moby/pull/42462).
- Disable overlay2 when running with SELinux to prevent permission denied errors [moby/moby#42462](https://github.com/moby/moby/pull/42462).
- Fix `x509: certificate signed by unknown authority` error on openSUSE Tumbleweed [moby/moby#42462](https://github.com/moby/moby/pull/42462).

### Runtime

- Print a warning when using the `--platform` option to pull a single-arch image
  that does not match the specified architecture [moby/moby#42633](https://github.com/moby/moby/pull/42633).
- Fix incorrect `Your kernel does not support swap memory limit` warning when
  running with cgroups v2 [moby/moby#42479](https://github.com/moby/moby/pull/42479).
- Windows: Fix a situation where containers were not stopped if `HcsShutdownComputeSystem`
  returned an `ERROR_PROC_NOT_FOUND` error [moby/moby#42613](https://github.com/moby/moby/pull/42613) 

### Swarm

- Fix a possibility where overlapping IP addresses could exist as a result of the
  node failing to clean up its old loadbalancer IPs [moby/moby#42538](https://github.com/moby/moby/pull/42538)
- Fix a deadlock in log broker ("dispatcher is stopped") [moby/moby#42537](https://github.com/moby/moby/pull/42537)

### Packaging

> **Known issue**
>
> The `ctr` binary shipping with the static packages of this release is not
> statically linked, and will not run in Docker images using alpine as a base
> image. Users can install the `libc6-compat` package, or download a previous
> version of the `ctr` binary as a workaround. Refer to the containerd ticket
> related to this issue for more details: [containerd/containerd#5824](https://github.com/containerd/containerd/issues/5824).

- Remove packaging for Ubuntu 16.04 "Xenial" and Fedora 32, as they reached EOL [docker/docker-ce-packaging#560](https://github.com/docker/docker-ce-packaging/pull/560)
- Update Golang runtime to Go 1.16.6
- Update the bundled buildx version to v0.6.1 for rpm and deb packages [docker/docker-ce-packaging#562](https://github.com/docker/docker-ce-packaging/pull/562)
- Update static binaries and containerd.io rpm and deb packages to containerd v1.4.9 and runc v1.0.1: [docker/containerd-packaging#241](https://github.com/docker/containerd-packaging/pull/241), [docker/containerd-packaging#245](https://github.com/docker/containerd-packaging/pull/245), [docker/containerd-packaging#247](https://github.com/docker/containerd-packaging/pull/247).

## 20.10.7
2021-06-02

### Client

* Suppress warnings for deprecated cgroups [docker/cli#3099](https://github.com/docker/cli/pull/3099).
* Prevent sending `SIGURG` signals to container on Linux and macOS. The Go runtime
  (starting with Go 1.14) uses `SIGURG` signals internally as an interrupt to
  support preemptable syscalls. In situations where the Docker CLI was attached
  to a container, these interrupts were forwarded to the container. This fix
  changes the Docker CLI to ignore `SIGURG` signals [docker/cli#3107](https://github.com/docker/cli/pull/3107),
  [moby/moby#42421](https://github.com/moby/moby/pull/42421).

### Builder

* Update BuildKit to version v0.8.3-3-g244e8cde [moby/moby#42448](https://github.com/moby/moby/pull/42448):
    * Transform relative mountpoints for exec mounts in the executor to work around
      a breaking change in runc v1.0.0-rc94 and up. [moby/buildkit#2137](https://github.com/moby/buildkit/pull/2137).
    * Add retry on image push 5xx errors. [moby/buildkit#2043](https://github.com/moby/buildkit/pull/2043).
    * Fix build-cache not being invalidated when renaming a file that is copied using
      a `COPY` command with a wildcard. Note that this change invalidates
      existing build caches for copy commands that use a wildcard. [moby/buildkit#2018](https://github.com/moby/buildkit/pull/2018).
    * Fix build-cache not being invalidated when using mounts [moby/buildkit#2076](https://github.com/moby/buildkit/pull/2076).
* Fix build failures when `FROM` image is not cached when using legacy schema 1 images [moby/moby#42382](https://github.com/moby/moby/pull/42382).

### Logging

* Update the hcsshim SDK to make daemon logs on Windows less verbose [moby/moby#42292](https://github.com/moby/moby/pull/42292).

### Rootless

* Fix capabilities not being honored when an image was built on a daemon with
  user-namespaces enabled [moby/moby#42352](https://github.com/moby/moby/pull/42352).

### Networking

* Update libnetwork to fix publishing ports on environments with kernel boot
  parameter `ipv6.disable=1`, and to fix a deadlock causing internal DNS lookups
  to fail [moby/moby#42413](https://github.com/moby/moby/pull/42413).

### Contrib

* Update rootlesskit to v0.14.2 to fix a timeout when starting the userland proxy
  with the `slirp4netns` port driver [moby/moby#42294](https://github.com/moby/moby/pull/42294).
* Fix "Device or resource busy" errors when running docker-in-docker on a rootless
  daemon [moby/moby#42342](https://github.com/moby/moby/pull/42342).

### Packaging

* Update containerd to v1.4.6, runc v1.0.0-rc95 to address [CVE-2021-30465](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30465)
  [moby/moby#42398](https://github.com/moby/moby/pull/42398), [moby/moby#42395](https://github.com/moby/moby/pull/42395),
  [docker/containerd-packaging#234](https://github.com/docker/containerd-packaging/pull/234)
* Update containerd to v1.4.5, runc v1.0.0-rc94 [moby/moby#42372](https://github.com/moby/moby/pull/42372),
  [moby/moby#42388](https://github.com/moby/moby/pull/42388), [docker/containerd-packaging#232](https://github.com/docker/containerd-packaging/pull/232).
* Update Docker Scan plugin packages (`docker-scan-plugin`) to v0.8 [docker/docker-ce-packaging#545](https://github.com/docker/docker-ce-packaging/pull/545).


## 20.10.6
2021-04-12

### Client

* Apple Silicon (darwin/arm64) support for Docker CLI [docker/cli#3042](https://github.com/docker/cli/pull/3042)
* config: print deprecation warning when falling back to pre-v1.7.0 config file `~/.dockercfg`. Support for this file will be removed in a future release [docker/cli#3000](https://github.com/docker/cli/pull/3000)

### Builder

* Fix classic builder silently ignoring unsupported Dockerfile options and prompt to enable BuildKit instead [moby/moby#42197](https://github.com/moby/moby/pull/42197)

### Logging

* json-file: fix sporadic unexpected EOF errors [moby/moby#42174](https://github.com/moby/moby/pull/42174)

### Networking

* Fix a regression in docker 20.10, causing  IPv6 addresses no longer to be bound by default when mapping ports [moby/moby#42205](https://github.com/moby/moby/pull/42205)
* Fix implicit IPv6 port-mappings not included in API response. Before docker 20.10, published ports were accessible through both IPv4 and IPv6 by default, but the API only included information about the IPv4 (0.0.0.0) mapping [moby/moby#42205](https://github.com/moby/moby/pull/42205)
* Fix a regression in docker 20.10, causing the docker-proxy  to not be terminated in all cases [moby/moby#42205](https://github.com/moby/moby/pull/42205)
* Fix iptables forwarding rules not being cleaned up upon container removal [moby/moby#42205](https://github.com/moby/moby/pull/42205)

### Packaging

* Update containerd to [v1.4.4](https://github.com/containerd/containerd/releases/tag/v1.4.4) for static binaries. The containerd.io package on apt/yum repos already had this update out of band. Includes a fix for [CVE-2021-21334](https://github.com/containerd/containerd/security/advisories/GHSA-6g2q-w5j3-fwh4). [moby/moby#42124](https://github.com/moby/moby/pull/42124)
* Packages for Debian/Raspbian 11 Bullseye, Ubuntu 21.04 Hirsute Hippo and Fedora 34 [docker/docker-ce-packaging#521](https://github.com/docker/docker-ce-packaging/pull/521) [docker/docker-ce-packaging#522](https://github.com/docker/docker-ce-packaging/pull/522) [docker/docker-ce-packaging#533](https://github.com/docker/docker-ce-packaging/pull/533)
* Provide the [Docker Scan CLI](https://github.com/docker/scan-cli-plugin) plugin on Linux amd64 via a `docker-scan-plugin` package as a recommended dependency for the `docker-ce-cli` package [docker/docker-ce-packaging#537](https://github.com/docker/docker-ce-packaging/pull/537)
* Include VPNKit binary for arm64 [moby/moby#42141](https://github.com/moby/moby/pull/42141)

### Plugins

* Fix docker plugin create making plugins that were incompatible with older versions of Docker [moby/moby#42256](https://github.com/moby/moby/pull/42256)

### Rootless

* Update RootlessKit to [v0.14.1](https://github.com/rootless-containers/rootlesskit/releases/tag/v0.14.1) (see also [v0.14.0](https://github.com/rootless-containers/rootlesskit/releases/tag/v0.14.0) [v0.13.2](https://github.com/rootless-containers/rootlesskit/releases/tag/v0.13.2)) [moby/moby#42186](https://github.com/moby/moby/pull/42186) [moby/moby#42232](https://github.com/moby/moby/pull/42232)
* dockerd-rootless-setuptool.sh: create CLI context "rootless" [moby/moby#42109](https://github.com/moby/moby/pull/42109)
* dockerd-rootless.sh: prohibit running as root [moby/moby#42072](https://github.com/moby/moby/pull/42072)
* Fix "operation not permitted" when bind mounting existing mounts [moby/moby#42233](https://github.com/moby/moby/pull/42233)
* overlay2: fix "createDirWithOverlayOpaque(...) ... input/output error" [moby/moby#42235](https://github.com/moby/moby/pull/42235)
* overlay2: support "userxattr" option (kernel 5.11) [moby/moby#42168](https://github.com/moby/moby/pull/42168)
* btrfs: allow unprivileged user to delete subvolumes (kernel >= 4.18) [moby/moby#42253](https://github.com/moby/moby/pull/42253)
* cgroup2: Move cgroup v2 out of experimental [moby/moby#42263](https://github.com/moby/moby/pull/42263)


## 20.10.5
2021-03-02

### Client

* Revert [docker/cli#2960](https://github.com/docker/cli/pull/2960) to fix hanging in `docker start --attach` and remove spurious `Unsupported signal: <nil>. Discarding` messages. [docker/cli#2987](https://github.com/docker/cli/pull/2987).

## 20.10.4
2021-02-26

### Builder

* Fix incorrect cache match for inline cache import with empty layers [moby/moby#42061](https://github.com/moby/moby/pull/42061)
* Update BuildKit to v0.8.2 [moby/moby#42061](https://github.com/moby/moby/pull/42061)
  * resolver: avoid error caching on token fetch
  * fileop: fix checksum to contain indexes of inputs preventing certain cache misses
  * Fix reference count issues on typed errors with mount references (fixing `invalid mutable ref` errors)
  * git: set token only for main remote access allowing cloning submodules with different credentials
* Ensure blobs get deleted in /var/lib/docker/buildkit/content/blobs/sha256 after pull. To clean up old state run `builder prune` [moby/moby#42065](https://github.com/moby/moby/pull/42065)
* Fix parallel pull synchronization regression [moby/moby#42049](https://github.com/moby/moby/pull/42049)
* Ensure libnetwork state files do not leak [moby/moby#41972](https://github.com/moby/moby/pull/41972)

### Client

* Fix a panic on `docker login` if no config file is present [docker/cli#2959](https://github.com/docker/cli/pull/2959)
* Fix `WARNING: Error loading config file: .dockercfg: $HOME is not defined` [docker/cli#2958](https://github.com/docker/cli/pull/2958)

### Runtime

* docker info: silence unhandleable warnings [moby/moby#41958](https://github.com/moby/moby/pull/41958)
* Avoid creating parent directories for XGlobalHeader [moby/moby#42017](https://github.com/moby/moby/pull/42017)
* Use 0755 permissions when creating missing directories [moby/moby#42017](https://github.com/moby/moby/pull/42017)
* Fallback to manifest list when no platform matches in image config [moby/moby#42045](https://github.com/moby/moby/pull/42045) [moby/moby#41873](https://github.com/moby/moby/pull/41873)
* Fix a daemon panic on setups with a custom default runtime configured [moby/moby#41974](https://github.com/moby/moby/pull/41974)
* Fix a panic when daemon configuration is empty [moby/moby#41976](https://github.com/moby/moby/pull/41976)
* Fix daemon panic when starting container with invalid device cgroup rule [moby/moby#42001](https://github.com/moby/moby/pull/42001)
* Fix userns-remap option when username & UID match [moby/moby#42013](https://github.com/moby/moby/pull/42013)
* static: update runc binary to v1.0.0-rc93 [moby/moby#42014](https://github.com/moby/moby/pull/42014)

### Logger

* Honor `labels-regex` config even if `labels` is not set [moby/moby#42046](https://github.com/moby/moby/pull/42046)
* Handle long log messages correctly preventing awslogs in non-blocking mode to split events bigger than 16kB [mobymoby#41975](https://github.com/moby/moby/pull/41975)

### Rootless

* Prevent the service hanging when stopping by setting systemd KillMode to mixed [moby/moby#41956](https://github.com/moby/moby/pull/41956)
* dockerd-rootless.sh: add typo guard [moby/moby#42070](https://github.com/moby/moby/pull/42070)
* Update rootlesskit to v0.13.1 to fix handling of IPv6 addresses [moby/moby#42025](https://github.com/moby/moby/pull/42025)
* allow mknodding FIFO inside userns [moby/moby#41957](https://github.com/moby/moby/pull/41957)

### Security

* profiles: seccomp: update to Linux 5.11 syscall list [moby/moby#41971](https://github.com/moby/moby/pull/41971)

### Swarm

* Fix issue with heartbeat not persisting upon restart [moby/moby#42060](https://github.com/moby/moby/pull/42060)
* Fix potential stalled tasks [moby/moby#42060](https://github.com/moby/moby/pull/42060)
* Fix `--update-order` and `--rollback-order` flags when only `--update-order` or `--rollback-order` is provided [docker/cli#2963](https://github.com/docker/cli/pull/2963)
* Fix `docker service rollback` returning a non-zero exit code in some situations [docker/cli#2964](https://github.com/docker/cli/pull/2964)
* Fix inconsistent progress-bar direction on `docker service rollback` [docker/cli#2964](https://github.com/docker/cli/pull/2964)


## 20.10.3
2021-02-01

### Security

* [CVE-2021-21285](https://github.com/moby/moby/security/advisories/GHSA-6fj5-m822-rqx8) Prevent an invalid image from crashing docker daemon
* [CVE-2021-21284](https://github.com/moby/moby/security/advisories/GHSA-7452-xqpj-6rpc) Lock down file permissions to prevent remapped root from accessing docker state
* Ensure AppArmor and SELinux profiles are applied when building with BuildKit

### Client

* Check contexts before importing them to reduce risk of extracted files escaping context store
* Windows: prevent executing certain binaries from current directory [docker/cli#2950](https://github.com/docker/cli/pull/2950)

## 20.10.2
2021-01-04

### Runtime

- Fix a daemon start up hang when restoring containers with restart policies but that keep failing to start [moby/moby#41729](https://github.com/moby/moby/pull/41729)
- overlay2: fix an off-by-one error preventing to build or run containers when data-root is 24-bytes long [moby/moby#41830](https://github.com/moby/moby/pull/41830)
- systemd: send `sd_notify STOPPING=1` when shutting down [moby/moby#41832](https://github.com/moby/moby/pull/41832)

### Networking

- Fix IPv6 port forwarding [moby/moby#41805](https://github.com/moby/moby/pull/41805) [moby/libnetwork#2604](https://github.com/moby/libnetwork/pull/2604)

### Swarm

- Fix filtering for `replicated-job` and `global-job` service modes [moby/moby#41806](https://github.com/moby/moby/pull/41806)

### Packaging

- buildx updated to [v0.5.1](https://github.com/docker/buildx/releases/tag/v0.5.1) [docker/docker-ce-packaging#516](https://github.com/docker/docker-ce-packaging/pull/516)

## 20.10.1
2020-12-14

### Builder

- buildkit: updated to [v0.8.1](https://github.com/moby/buildkit/releases/tag/v0.8.1) with various bugfixes [moby/moby#41793](https://github.com/moby/moby/pull/41793)

### Packaging

- Revert a change in the systemd unit that could prevent docker from starting due to a startup order conflict [docker/docker-ce-packaging#514](https://github.com/docker/docker-ce-packaging/pull/514)
- buildx updated to [v0.5.0](https://github.com/docker/buildx/releases/tag/v0.5.0) [docker/docker-ce-packaging#515](https://github.com/docker/docker-ce-packaging/pull/515)

## 20.10.0
2020-12-08

### Deprecation / Removal

For an overview of all deprecated features, refer to the [Deprecated Engine Features](/engine/deprecated/) page.

- Warnings and deprecation notice when `docker pull`-ing from non-compliant registries not supporting pull-by-digest [docker/cli#2872](https://github.com/docker/cli/pull/2872)
- Sterner warnings and deprecation notice for unauthenticated tcp access [moby/moby#41285](https://github.com/moby/moby/pull/41285)
- Deprecate KernelMemory (`docker run --kernel-memory`) [moby/moby#41254](https://github.com/moby/moby/pull/41254) [docker/cli#2652](https://github.com/docker/cli/pull/2652)
- Deprecate `aufs` storage driver [docker/cli#1484](https://github.com/docker/cli/pull/1484)
- Deprecate host-discovery and overlay networks with external k/v stores [moby/moby#40614](https://github.com/moby/moby/pull/40614) [moby/moby#40510](https://github.com/moby/moby/pull/40510)
- Deprecate Dockerfile legacy 'ENV name value' syntax, use `ENV name=value` instead [docker/cli#2743](https://github.com/docker/cli/pull/2743)
- Remove deprecated "filter" parameter for API v1.41 and up [moby/moby#40491](https://github.com/moby/moby/pull/40491)
- Disable distribution manifest v2 schema 1 on push [moby/moby#41295](https://github.com/moby/moby/pull/41295)
- Remove hack MalformedHostHeaderOverride breaking old docker clients (<= 1.12) in which case, set `DOCKER_API_VERSION` [moby/moby#39076](https://github.com/moby/moby/pull/39076)
- Remove "docker engine" subcommands [docker/cli#2207](https://github.com/docker/cli/pull/2207)
- Remove experimental "deploy" from "dab" files [docker/cli#2216](https://github.com/docker/cli/pull/2216)
- Remove deprecated `docker search --automated` and `--stars` flags [docker/cli#2338](https://github.com/docker/cli/pull/2338)
- No longer allow reserved namespaces in engine labels [docker/cli#2326](https://github.com/docker/cli/pull/2326)

### API

- Update API version to v1.41
- Do not require "experimental" for metrics API [moby/moby#40427](https://github.com/moby/moby/pull/40427)
- `GET /events` now returns `prune` events after pruning resources have completed [moby/moby#41259](https://github.com/moby/moby/pull/41259)
  - Prune events are returned for `container`, `network`, `volume`, `image`, and `builder`, and have a `reclaimed` attribute, indicating the amount of space reclaimed (in bytes)
- Add `one-shot` stats option to not prime the stats [moby/moby#40478](https://github.com/moby/moby/pull/40478)
- Adding OS version info to the system info's API (`/info`) [moby/moby#38349](https://github.com/moby/moby/pull/38349)
- Add DefaultAddressPools to docker info [moby/moby#40714](https://github.com/moby/moby/pull/40714)
- Add API support for PidsLimit on services [moby/moby#39882](https://github.com/moby/moby/pull/39882)

### Builder

- buildkit,dockerfile: Support for `RUN --mount` options without needing to specify experimental dockerfile `#syntax` directive. [moby/buildkit#1717](https://github.com/moby/buildkit/pull/1717)
- dockerfile: `ARG` command now supports defining multiple build args on the same line similarly to `ENV` [moby/buildkit#1692](https://github.com/moby/buildkit/pull/1692)
- dockerfile: `--chown` flag in `ADD` now allows parameter expansion [moby/buildkit#1473](https://github.com/moby/buildkit/pull/1473)
- buildkit: Fetching authorization tokens has been moved to client-side (if the client supports it). Passwords do not leak into the build daemon anymore and users can see from build output when credentials or tokens are accessed. [moby/buildkit#1660](https://github.com/moby/buildkit/pull/1660)
- buildkit: Connection errors while communicating with the registry for push and pull now trigger a retry [moby/buildkit#1791](https://github.com/moby/buildkit/pull/1791)
- buildkit: Git source now supports token authentication via build secrets [moby/moby#41234](https://github.com/moby/moby/pull/41234) [docker/cli#2656](https://github.com/docker/cli/pull/2656) [moby/buildkit#1533](https://github.com/moby/buildkit/pull/1533)
- buildkit: Building from git source now supports forwarding SSH socket for authentication [moby/buildkit#1782](https://github.com/moby/buildkit/pull/1782)
- buildkit: Avoid builds that generate excessive logs to cause a crash or slow down the build. Clipping is performed if needed. [moby/buildkit#1754](https://github.com/moby/buildkit/pull/1754)
- buildkit: Change default Seccomp profile to the one provided by Docker [moby/buildkit#1807](https://github.com/moby/buildkit/pull/1807)
- buildkit: Support for exposing SSH agent socket on Windows has been improved [moby/buildkit#1695](https://github.com/moby/buildkit/pull/1695)
- buildkit: Disable truncating by default when using --progress=plain [moby/buildkit#1435](https://github.com/moby/buildkit/pull/1435)
- buildkit: Allow better handling client sessions dropping while it is being shared by multiple builds [moby/buildkit#1551](https://github.com/moby/buildkit/pull/1551)
- buildkit: secrets: allow providing secrets with env [moby/moby#41234](https://github.com/moby/moby/pull/41234) [docker/cli#2656](https://github.com/docker/cli/pull/2656) [moby/buildkit#1534](https://github.com/moby/buildkit/pull/1534)
  - Support `--secret id=foo,env=MY_ENV` as an alternative for storing a secret value to a file.
  - `--secret id=GIT_AUTH_TOKEN` will load env if it exists and the file does not.
- buildkit: Support for mirrors fallbacks, insecure TLS and custom TLS config [moby/moby#40814](https://github.com/moby/moby/pull/40814)
- buildkit: remotecache: Only visit each item once when walking results [moby/moby#41234](https://github.com/moby/moby/pull/41234) [moby/buildkit#1577](https://github.com/moby/buildkit/pull/1577)
  - Improves performance and CPU use on bigger graphs
- buildkit: Check remote when local image platform doesn't match [moby/moby#40629](https://github.com/moby/moby/pull/40629)
- buildkit: image export: Use correct media type when creating new layer blobs [moby/moby#41234](https://github.com/moby/moby/pull/41234) [moby/buildkit#1541](https://github.com/moby/buildkit/pull/1541)
- buildkit: progressui: fix logs time formatting [moby/moby#41234](https://github.com/moby/moby/pull/41234) [docker/cli#2656](https://github.com/docker/cli/pull/2656) [moby/buildkit#1549](https://github.com/moby/buildkit/pull/1549)
- buildkit: mitigate containerd issue on parallel push [moby/moby#41234](https://github.com/moby/moby/pull/41234) [moby/buildkit#1548](https://github.com/moby/buildkit/pull/1548)
- buildkit: inline cache: fix handling of duplicate blobs [moby/moby#41234](https://github.com/moby/moby/pull/41234) [moby/buildkit#1568](https://github.com/moby/buildkit/pull/1568)
  - Fixes https://github.com/moby/buildkit/issues/1388 cache-from working unreliably
  - Fixes https://github.com/moby/moby/issues/41219 Image built from cached layers is missing data
- Allow ssh:// for remote context URLs [moby/moby#40179](https://github.com/moby/moby/pull/40179)
- builder: remove legacy build's session handling (was experimental) [moby/moby#39983](https://github.com/moby/moby/pull/39983)

### Client

- Add swarm jobs support to CLI [docker/cli#2262](https://github.com/docker/cli/pull/2262)
- Add `-a/--all-tags` to docker push [docker/cli#2220](https://github.com/docker/cli/pull/2220)
- Add support for Kubernetes username/password auth [docker/cli#2308](https://github.com/docker/cli/pull/2308)
- Add `--pull=missing|always|never` to `run` and `create` commands [docker/cli#1498](https://github.com/docker/cli/pull/1498)
- Add `--env-file` flag to `docker exec` for parsing environment variables from a file [docker/cli#2602](https://github.com/docker/cli/pull/2602)
- Add shorthand `-n` for `--tail` option [docker/cli#2646](https://github.com/docker/cli/pull/2646)
- Add log-driver and options to service inspect "pretty" format [docker/cli#1950](https://github.com/docker/cli/pull/1950)
- docker run: specify cgroup namespace mode with `--cgroupns` [docker/cli#2024](https://github.com/docker/cli/pull/2024)
- `docker manifest rm` command to remove manifest list draft from local storage [docker/cli#2449](https://github.com/docker/cli/pull/2449)
- Add "context" to "docker version" and "docker info" [docker/cli#2500](https://github.com/docker/cli/pull/2500)
- Propagate platform flag to container create API [docker/cli#2551](https://github.com/docker/cli/pull/2551)
- The `docker ps --format` flag now has a `.State` placeholder to print the container's state without additional details about uptime and health check [docker/cli#2000](https://github.com/docker/cli/pull/2000)
- Add support for docker-compose schema v3.9 [docker/cli#2073](https://github.com/docker/cli/pull/2073)
- Add support for docker push `--quiet` [docker/cli#2197](https://github.com/docker/cli/pull/2197)
- Hide flags that are not supported by BuildKit, if BuildKit is enabled [docker/cli#2123](https://github.com/docker/cli/pull/2123)
- Update flag description for `docker rm -v` to clarify the option only removes anonymous (unnamed) volumes [docker/cli#2289](https://github.com/docker/cli/pull/2289)
- Improve tasks printing for docker services [docker/cli#2341](https://github.com/docker/cli/pull/2341)
- docker info: list CLI plugins alphabetically [docker/cli#2236](https://github.com/docker/cli/pull/2236)
- Fix order of processing of `--label-add/--label-rm`, `--container-label-add/--container-label-rm`, and `--env-add/--env-rm` flags on `docker service update` to allow replacing existing values [docker/cli#2668](https://github.com/docker/cli/pull/2668)
- Fix `docker rm --force` returning a non-zero exit code if one or more containers did not exist [docker/cli#2678](https://github.com/docker/cli/pull/2678)
- Improve memory stats display by using `total_inactive_file` instead of `cache` [docker/cli#2415](https://github.com/docker/cli/pull/2415)
- Mitigate against YAML files that has excessive aliasing [docker/cli#2117](https://github.com/docker/cli/pull/2117)
- Allow using advanced syntax when setting a config or secret with only the source field [docker/cli#2243](https://github.com/docker/cli/pull/2243)
- Fix reading config files containing `username` and `password` auth even if `auth` is empty [docker/cli#2122](https://github.com/docker/cli/pull/2122)
- docker cp: prevent NPE when failing to stat destination [docker/cli#2221](https://github.com/docker/cli/pull/2221)
- config: preserve ownership and permissions on configfile [docker/cli#2228](https://github.com/docker/cli/pull/2228)

### Logging

- Support reading `docker logs` with all logging drivers (best effort) [moby/moby#40543](https://github.com/moby/moby/pull/40543)
- Add `splunk-index-acknowledgment` log option to work with Splunk HECs with index acknowledgment enabled [moby/moby#39987](https://github.com/moby/moby/pull/39987)
- Add partial metadata to journald logs [moby/moby#41407](https://github.com/moby/moby/pull/41407)
- Reduce allocations for logfile reader [moby/moby#40796](https://github.com/moby/moby/pull/40796)
- Fluentd: add fluentd-async, fluentd-request-ack, and deprecate fluentd-async-connect [moby/moby#39086](https://github.com/moby/moby/pull/39086)

### Runtime

- Support cgroup2 [moby/moby#40174](https://github.com/moby/moby/pull/40174) [moby/moby#40657](https://github.com/moby/moby/pull/40657) [moby/moby#40662](https://github.com/moby/moby/pull/40662)
- cgroup2: use "systemd" cgroup driver by default when available [moby/moby#40846](https://github.com/moby/moby/pull/40846)
- new storage driver: fuse-overlayfs [moby/moby#40483](https://github.com/moby/moby/pull/40483)
- Update containerd binary to v1.4.3 [moby/moby#41732](https://github.com/moby/moby/pull/41732)
- `docker push` now defaults to `latest` tag instead of all tags [moby/moby#40302](https://github.com/moby/moby/pull/40302)
- Added ability to change the number of reconnect attempts during connection loss while pulling an image by adding max-download-attempts to the config file [moby/moby#39949](https://github.com/moby/moby/pull/39949)
- Add support for containerd v2 shim by using the now default `io.containerd.runc.v2` runtime [moby/moby#41182](https://github.com/moby/moby/pull/41182)
- cgroup v1: change the default runtime to io.containerd.runc.v2. Requires containerd v1.3.0 or later. v1.3.5 or later is recommended [moby/moby#41210](https://github.com/moby/moby/pull/41210)
- Start containers in their own cgroup namespaces [moby/moby#38377](https://github.com/moby/moby/pull/38377)
- Enable DNS Lookups for CIFS Volumes [moby/moby#39250](https://github.com/moby/moby/pull/39250)
- Use MemAvailable instead of MemFree to estimate actual available memory [moby/moby#39481](https://github.com/moby/moby/pull/39481)
- The `--device` flag in `docker run` will now be honored when the container is started in privileged mode [moby/moby#40291](https://github.com/moby/moby/pull/40291)
- Enforce reserved internal labels [moby/moby#40394](https://github.com/moby/moby/pull/40394)
- Raise minimum memory limit to 6M, to account for higher memory use by runtimes during container startup [moby/moby#41168](https://github.com/moby/moby/pull/41168)
- vendor runc v1.0.0-rc92 [moby/moby#41344](https://github.com/moby/moby/pull/41344) [moby/moby#41317](https://github.com/moby/moby/pull/41317)
- info: add warnings about missing blkio cgroup support [moby/moby#41083](https://github.com/moby/moby/pull/41083)
- Accept platform spec on container create [moby/moby#40725](https://github.com/moby/moby/pull/40725)
- Fix handling of looking up user- and group-names with spaces [moby/moby#41377](https://github.com/moby/moby/pull/41377)

### Networking

- Support host.docker.internal in dockerd on Linux [moby/moby#40007](https://github.com/moby/moby/pull/40007)
- Include IPv6 address of linked containers in /etc/hosts [moby/moby#39837](https://github.com/moby/moby/pull/39837)
- `--ip6tables` enables IPv6 iptables rules (only if experimental) [moby/moby#41622](https://github.com/moby/moby/pull/41622)
- Add alias for hostname if hostname != container name [moby/moby#39204](https://github.com/moby/moby/pull/39204)
- Better selection of DNS server (with systemd) [moby/moby#41022](https://github.com/moby/moby/pull/41022)
- Add docker interfaces to firewalld docker zone [moby/moby#41189](https://github.com/moby/moby/pull/41189) [moby/libnetwork#2548](https://github.com/moby/libnetwork/pull/2548)
  - Fixes DNS issue on CentOS8 [docker/for-linux#957](https://github.com/docker/for-linux/issues/957)
  - Fixes Port Forwarding on RHEL 8 with Firewalld running with FirewallBackend=nftables [moby/libnetwork#2496](https://github.com/moby/libnetwork/issues/2496)
- Fix an issue reporting 'failed to get network during CreateEndpoint' [moby/moby#41189](https://github.com/moby/moby/pull/41189) [moby/libnetwork#2554](https://github.com/moby/libnetwork/pull/2554)
- Log error instead of disabling IPv6 router advertisement failed [moby/moby#41189](https://github.com/moby/moby/pull/41189) [moby/libnetwork#2563](https://github.com/moby/libnetwork/pull/2563)
- No longer ignore `--default-address-pool` option in certain cases [moby/moby#40711](https://github.com/moby/moby/pull/40711)
- Produce an error with invalid address pool [moby/moby#40808](https://github.com/moby/moby/pull/40808) [moby/libnetwork#2538](https://github.com/moby/libnetwork/pull/2538)
- Fix `DOCKER-USER` chain not created when IPTableEnable=false [moby/moby#40808](https://github.com/moby/moby/pull/40808) [moby/libnetwork#2471](https://github.com/moby/libnetwork/pull/2471)
- Fix panic on startup in systemd environments [moby/moby#40808](https://github.com/moby/moby/pull/40808) [moby/libnetwork#2544](https://github.com/moby/libnetwork/pull/2544)
- Fix issue preventing containers to communicate over macvlan internal network [moby/moby#40596](https://github.com/moby/moby/pull/40596) [moby/libnetwork#2407](https://github.com/moby/libnetwork/pull/2407)
- Fix InhibitIPv4 nil panic [moby/moby#40596](https://github.com/moby/moby/pull/40596)
- Fix VFP leak in Windows overlay network deletion [moby/moby#40596](https://github.com/moby/moby/pull/40596) [moby/libnetwork#2524](https://github.com/moby/libnetwork/pull/2524)

### Packaging

- docker.service: Add multi-user.target to After= in unit file [moby/moby#41297](https://github.com/moby/moby/pull/41297)
- docker.service: Allow socket activation [moby/moby#37470](https://github.com/moby/moby/pull/37470)
- seccomp: Remove dependency in dockerd on libseccomp [moby/moby#41395](https://github.com/moby/moby/pull/41395)

### Rootless

- rootless: graduate from experimental [moby/moby#40759](https://github.com/moby/moby/pull/40759)
- Add dockerd-rootless-setuptool.sh [moby/moby#40950](https://github.com/moby/moby/pull/40950)
- Support `--exec-opt native.cgroupdriver=systemd` [moby/moby#40486](https://github.com/moby/moby/pull/40486)

### Security

- Fix CVE-2019-14271 loading of nsswitch based config inside chroot under Glibc [moby/moby#39612](https://github.com/moby/moby/pull/39612)
- seccomp: Whitelist `clock_adjtime`. `CAP_SYS_TIME` is still required for time adjustment [moby/moby#40929](https://github.com/moby/moby/pull/40929)
- seccomp: Add openat2 and faccessat2 to default seccomp profile [moby/moby#41353](https://github.com/moby/moby/pull/41353)
- seccomp: allow 'rseq' syscall in default seccomp profile [moby/moby#41158](https://github.com/moby/moby/pull/41158)
- seccomp: allow syscall membarrier [moby/moby#40731](https://github.com/moby/moby/pull/40731)
- seccomp: whitelist io-uring related system calls [moby/moby#39415](https://github.com/moby/moby/pull/39415)
- Add default sysctls to allow ping sockets and privileged ports with no capabilities [moby/moby#41030](https://github.com/moby/moby/pull/41030)
- Fix seccomp profile for clone syscall [moby/moby#39308](https://github.com/moby/moby/pull/39308)

### Swarm

- Add support for swarm jobs [moby/moby#40307](https://github.com/moby/moby/pull/40307)
- Add capabilities support to stack/service commands [docker/cli#2687](https://github.com/docker/cli/pull/2687) [docker/cli#2709](https://github.com/docker/cli/pull/2709) [moby/moby#39173](https://github.com/moby/moby/pull/39173) [moby/moby#41249](https://github.com/moby/moby/pull/41249)
- Add support for sending down service Running and Desired task counts [moby/moby#39231](https://github.com/moby/moby/pull/39231)
- service: support `--mount type=bind,bind-nonrecursive` [moby/moby#38788](https://github.com/moby/moby/pull/38788)
- Support ulimits on Swarm services. [moby/moby#41284](https://github.com/moby/moby/pull/41284) [docker/cli#2712](https://github.com/docker/cli/pull/2712)
- Fixed an issue where service logs could leak goroutines on the worker [moby/moby#40426](https://github.com/moby/moby/pull/40426)


---

# Docker Engine 23.0 release notes

*Sección: Engine*

> [!NOTE]
>
> From Docker Engine version 23.0.0, Buildx is distributed in a separate package: `docker-buildx-plugin`.
> In earlier versions, Buildx was included in the `docker-ce-cli` package.
> When you upgrade to this version of Docker Engine, make sure you update all
> packages. For example, on Ubuntu:
>
> ```console
> $ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
> ```
>
> Refer to the [Docker Engine installation instructions][1] for your operating system
> for more details on upgrading Docker Engine.

[1]: ../install/index.md

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 23.0.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

Starting with the 23.0.0 release, Docker Engine moves away from using CalVer versioning,
and starts using the [SemVer versioning format](https://semver.org/).
Changing the version format is a stepping-stone towards Go module compatibility,
but the repository doesn't yet use Go modules, and still requires using a "+incompatible" version.
Work continues towards Go module compatibility in a future release.

## 23.0.6

{{< release-date date="2023-05-08" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 23.0.6 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A23.0.6)
- [moby/moby, 23.0.6 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A23.0.6)

### Bug fixes and enhancements

- Fix vfs storage driver not working on NFS. [moby/moby#45465](https://github.com/moby/moby/pull/45465)

### Packaging Updates

- Upgrade Go to `1.19.9`. [docker/docker-ce-packaging#889](https://github.com/docker/docker-ce-packaging/pull/889),
  [docker/cli#4254](https://github.com/docker/cli/pull/4254), [moby/moby#45455](https://github.com/moby/moby/pull/45455)
- Upgrade `containerd` to [v1.6.21](https://github.com/containerd/containerd/releases/tag/v1.6.21)
- Upgrade `runc` to [v1.1.7](https://github.com/opencontainers/runc/releases/tag/v1.1.7)


## 23.0.5

{{< release-date date="2023-04-26" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 23.0.5 milestone](https://github.com/docker/cli/milestone/79?closed=1)
- [moby/moby, 23.0.5 milestone](https://github.com/moby/moby/milestone/118?closed=1)

### Bug fixes and enhancements

- Add the `--all` / `-a` option when pruning volumes. [docker/cli#4229](https://github.com/docker/cli/pull/4229)
- Add `--format=json` for `docker info`. [docker/cli#4320](https://github.com/docker/cli/pull/4230)
- Fix log loss with the AWSLogs log driver. [moby/moby#45350](https://github.com/moby/moby/pull/45350)
- Fix a regression introduced in v23.0.4 where dockerd would refuse to start if the fixed-cidr config parameter is provided but not bip. [moby/moby#45403](https://github.com/moby/moby/pull/45403)
- Fix a panic in libnetwork during daemon start [moby/moby#45376](https://github.com/moby/moby/pull/45376)
- Fix "tag" event not being sent when an image is built with `buildx`. [moby/moby#45410](https://github.com/moby/moby/pull/45410)

### Packaging Updates

- Upgrade Compose to `2.17.3`. [docker/docker-ce-packaging#883](https://github.com/docker/docker-ce-packaging/pull/883)

## 23.0.4

{{< release-date date="2023-04-17" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 23.0.4 milestone](https://github.com/docker/cli/milestone/77?closed=1)
- [moby/moby, 23.0.4 milestone](https://github.com/moby/moby/milestone/117?closed=1)

### Bug fixes and enhancements

- Fix a performance regression in Docker CLI 23.0.0 [docker/cli#4141](https://github.com/docker/cli/pull/4141).
- Fix progress indicator on `docker cp` not functioning as intended [docker/cli#4157](https://github.com/docker/cli/pull/4157).
- Fix shell completion for `docker compose --file` [docker/cli#4177](https://github.com/docker/cli/pull/4177).
- Fix an error caused by incorrect handling of "default-address-pools" in `daemon.json` [moby/moby#45246](https://github.com/moby/moby/pull/45246).

### Packaging Updates

- Fix missing packages for CentOS 9 Stream.
- Upgrade Go to `1.19.8`. [docker/docker-ce-packaging#878](https://github.com/docker/docker-ce-packaging/pull/878),
  [docker/cli#4164](https://github.com/docker/cli/pull/4164), [moby/moby#45277](https://github.com/moby/moby/pull/45277),
  which contains fixes for [CVE-2023-24537](https://github.com/advisories/GHSA-fp86-2355-v99r),
  [CVE-2023-24538](https://github.com/advisories/GHSA-v4m2-x4rp-hv22),
  [CVE-2023-24534](https://github.com/advisories/GHSA-8v5j-pwr7-w5f8),
  and [CVE-2023-24536](https://github.com/advisories/GHSA-9f7g-gqwh-jpf5)


## 23.0.3

{{< release-date date="2023-04-04" >}}

> [!NOTE]
> 
> Due to an issue with CentOS 9 Stream's package repositories, packages for
> CentOS 9 are currently unavailable. Packages for CentOS 9 may be added later,
> or as part of the next (23.0.4) patch release.

### Bug fixes and enhancements

- Fixed a number of issues that can cause Swarm encrypted overlay networks
  to fail to uphold their guarantees, addressing [CVE-2023-28841](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28841),
  [CVE-2023-28840](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28840), and
  [CVE-2023-28842](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-28842).
  - A lack of kernel support for encrypted overlay networks now reports
    as an error.
  - Encrypted overlay networks are eagerly set up, rather than waiting for
    multiple nodes to attach.
  - Encrypted overlay networks are now usable on Red Hat Enterprise Linux 9
    through the use of the `xt_bpf` kernel module.
  - Users of Swarm overlay networks should review [GHSA-vwm3-crmr-xfxw](https://github.com/moby/moby/security/advisories/GHSA-vwm3-crmr-xfxw)
    to ensure that unintentional exposure has not occurred.

### Packaging Updates

- Upgrade `containerd` to [v1.6.20](https://github.com/containerd/containerd/releases/tag/v1.6.20).
- Upgrade `runc` to [v1.1.5](https://github.com/opencontainers/runc/releases/tag/v1.1.5).


## 23.0.2

{{< release-date date="2023-03-28" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 23.0.2 milestone](https://github.com/docker/cli/milestone/75?closed=1)
- [moby/moby, 23.0.2 milestone](https://github.com/moby/moby/milestone/114?closed=1)

### Bug fixes and enhancements

- Fully resolve missing checks for `apparmor_parser` when an AppArmor enabled kernel is detected. [containerd/containerd#8087](https://github.com/containerd/containerd/pull/8087), [moby/moby#45043](https://github.com/moby/moby/pull/45043)
- Ensure that credentials are redacted from Git URLs when generating BuildKit buildinfo. Fixes [CVE-2023-26054](https://github.com/moby/buildkit/security/advisories/GHSA-gc89-7gcr-jxqc). [moby/moby#45110](https://github.com/moby/moby/pull/45110)
- Fix anonymous volumes created by a `VOLUME` line in a Dockerfile being excluded from volume prune. [moby/moby#45159](https://github.com/moby/moby/pull/45159)
- Fix a failure to properly propagate errors during removal of volumes on a Swarm node. [moby/moby#45155](https://github.com/moby/moby/pull/45155)
- Temporarily work around a bug in BuildKit `COPY --link` by disabling mergeop/diffop optimization. [moby/moby#45112](https://github.com/moby/moby/pull/45112)
- Properly clean up child tasks when a parent Swarm job is removed. [moby/swarmkit#3112](https://github.com/moby/swarmkit/pull/3112), [moby/moby#45107](https://github.com/moby/moby/pull/45107)
- Fix Swarm service creation logic so that both a GenericResource and a non-default network can be used together. [moby/swarmkit#3082](https://github.com/moby/swarmkit/pull/3082), [moby/moby#45107](https://github.com/moby/moby/pull/45107)
- Fix Swarm CSI support requiring the CSI plugin to offer staging endpoints in order to publish a volume. [moby/swarmkit#3116](https://github.com/moby/swarmkit/pull/3116), [moby/moby#45107](https://github.com/moby/moby/pull/45107)
- Fix a panic caused by log buffering in some configurations. [containerd/fifo#47](https://github.com/containerd/fifo/pull/47), [moby/moby#45051](https://github.com/moby/moby/pull/45051)
- Log errors in the REST to Swarm gRPC API translation layer at the debug level to reduce redundancy and noise. [moby/moby#45016](https://github.com/moby/moby/pull/45016)
- Fix a DNS resolution issue affecting containers created with `--dns-opt` or `--dns-search` when `systemd-resolved` is used outside the container. [moby/moby#45000](https://github.com/moby/moby/pull/45000)
- Fix a panic when logging errors in handling DNS queries originating from inside a container. [moby/moby#44980](https://github.com/moby/moby/pull/44980)
- Improve the speed of `docker ps` by allowing users to opt out of size calculations with `--size=false`. [docker/cli#4107](https://github.com/docker/cli/pull/4107)
- Extend support for Bash completion to all plugins. [docker/cli#4092](https://github.com/docker/cli/pull/4092)
- Fix `docker stack deploy` failing on Windows when special environment variables set by `cmd.exe` are present. [docker/cli#4083](https://github.com/docker/cli/pull/4083)
- Add forward compatibility for future API versions by considering empty image tags to be the same as `<none>`. [docker/cli#4065](https://github.com/docker/cli/pull/4065)
- Atomically write context files to greatly reduce the probability of corruption, and improve the error message for a corrupt context. [docker/cli#4063](https://github.com/docker/cli/pull/4063)

### Packaging

- Upgrade Go to `1.19.7`. [docker/docker-ce-packaging#857](https://github.com/docker/docker-ce-packaging/pull/857), [docker/cli#4086](https://github.com/docker/cli/pull/4086), [moby/moby#45137](https://github.com/moby/moby/pull/45137)
- Upgrade `containerd` to `v1.6.19`. [moby/moby#45084](https://github.com/moby/moby/pull/45084), [moby/moby#45099](https://github.com/moby/moby/pull/45099)
- Upgrade Buildx to `v0.10.4`. [docker/docker-ce-packaging#855](https://github.com/docker/docker-ce-packaging/pull/855)
- Upgrade Compose to `v2.17.2`. [docker/docker-ce-packaging#867](https://github.com/docker/docker-ce-packaging/pull/867)

## 23.0.1

{{< release-date date="2023-02-09" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 23.0.1 milestone](https://github.com/docker/cli/milestone/73?closed=1)
- [moby/moby, 23.0.1 milestone](https://github.com/moby/moby/milestone/113?closed=1)

### Bug fixes and enhancements

- Fix containers not starting if the kernel has AppArmor enabled, but `apparmor_parser` is not available. [moby/moby#44942](https://github.com/moby/moby/pull/44942)
- Fix BuildKit-enabled builds with inline caching causing the daemon to crash. [moby/moby#44944](https://github.com/moby/moby/pull/44944)
- Fix BuildKit improperly loading cached layers created by previous versions. [moby/moby#44959](https://github.com/moby/moby/pull/44959)
- Fix an issue where `ipvlan` networks created prior to upgrading would prevent the daemon from starting. [moby/moby#44937](https://github.com/moby/moby/pull/44937)
- Fix the `overlay2` storage driver failing early in `metacopy` testing when initialized on an unsupported backing filesystem. [moby/moby#44922](https://github.com/moby/moby/pull/44922)
- Fix `exec` exit events being misinterpreted as container exits under some runtimes, such as Kata Containers. [moby/moby#44892](https://github.com/moby/moby/pull/44892)
- Improve the error message returned by the CLI when receiving a truncated JSON response caused by the API hanging up mid-request. [docker/cli#4004](https://github.com/docker/cli/pull/4004)
- Fix an incorrect CLI exit code when attempting to execute a directory with a `runc` compiled using Go 1.20. [docker/cli#4004](https://github.com/docker/cli/pull/4004)
- Fix mishandling the size argument to `--device-write-bps` as a path. [docker/cli#4004](https://github.com/docker/cli/pull/4004)

### Packaging

- Add `/etc/docker` to RPM and DEB packaging. [docker/docker-ce-packaging#842](https://github.com/docker/docker-ce-packaging/pull/842)
  - Not all use cases will benefit; if you depend on this, you should explicitly `mkdir -p /etc/docker`.
- Upgrade Compose to `v2.16.0`. [docker/docker-ce-packaging#844](https://github.com/docker/docker-ce-packaging/pull/844)

## 23.0.0

{{< release-date date="2023-02-01" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 23.0.0 milestone](https://github.com/docker/cli/milestone/51?closed=1)
- [moby/moby, 23.0.0 milestone](https://github.com/moby/moby/milestone/91?closed=1)

### New

- Set Buildx and BuildKit as the default builder on Linux. [moby/moby#43992](https://github.com/moby/moby/pull/43992)
  - Alias `docker build` to `docker buildx build`. [docker/cli#3314](https://github.com/docker/cli/pull/3314)
  - The legacy builder can still be used by explicitly setting `DOCKER_BUILDKIT=0`.
  - There are differences in how BuildKit and the legacy builder handle multi-stage builds. For more information, see
    [Multi-stage builds](../../build/building/multi-stage.md#differences-between-legacy-builder-and-buildkit).
- Add support for pulling `zstd` compressed layers. [moby/moby#41759](https://github.com/moby/moby/pull/41759), [moby/moby#42862](https://github.com/moby/moby/pull/42862)
- Add support for alternate OCI runtimes on Linux, compatible with the containerd runtime v2 API. [moby/moby#43887](https://github.com/moby/moby/pull/43887), [moby/moby#43993](https://github.com/moby/moby/pull/43993)
- Add support for the containerd `runhcs` shim on Windows (off by default). [moby/moby#42089](https://github.com/moby/moby/pull/42089)
- Add `dockerd --validate` to check the daemon JSON config and exit. [moby/moby#42393](https://github.com/moby/moby/pull/42393)
- Add the ability to configure the daemon's HTTP proxy via flags or JSON config. [moby/moby#42835](https://github.com/moby/moby/pull/42835)
- Add support for RFC 3021 point-to-point networks (IPv4 /31s) and single hosts (IPv4 /32s). For networks with two or fewer addresses, IPAM won't reserve a network and broadcast address. [moby/moby#42626](https://github.com/moby/moby/pull/42626)
- Add support for setting `ipvlan_flag` and using the `l3s` `ipvlan_mode` in the `ipvlan` network driver. [moby/moby#42542](https://github.com/moby/moby/pull/42542)
- Add support for displaying the value of the `metacopy` option for the `overlay2` storage driver. [moby/moby#43557](https://github.com/moby/moby/pull/43557)
- Add support for describing Windows devices using the syntax `IDType://ID`. [moby/moby#43368](https://github.com/moby/moby/pull/43368)
- Add `RootlessKit`, `slirp4netns`, and `VPNKit` version reporting. [moby/moby#42330](https://github.com/moby/moby/pull/42330)
- Add experimental support for SwarmKit cluster volumes (CSI). [moby/moby#41982](https://github.com/moby/moby/pull/41982)
  - CLI: Add cluster volume (CSI) options to `docker volume`. [docker/cli#3606](https://github.com/docker/cli/pull/3606)
  - CLI: Add cluster volume (CSI) support to `docker stack`. [docker/cli#3662](https://github.com/docker/cli/pull/3662)
- Add support for SwarmKit jobs in `docker stack deploy`. [docker/cli#2907](https://github.com/docker/cli/pull/2907)
- Add the `docker stack config` command to output the merged and interpolated config files as utilized by `stack deploy`. [docker/cli#3544](https://github.com/docker/cli/pull/3544)
- Add a new `docker context show` command that prints the name of the current context. [docker/cli#3567](https://github.com/docker/cli/pull/3567)
- Add the `--format=json` shorthand variant of `--format="{{ json . }}"` to all commands supporting the `--format` flag. [docker/cli#2936](https://github.com/docker/cli/pull/2936)
- Add a `--quiet` option to `docker create` and `docker run` commands to suppress output when pulling an image. [docker/cli#3377](https://github.com/docker/cli/pull/3377)
- Add a `--force` option to `docker network rm` subcommand. Causes CLI to return a 0 exit code even if the network doesn't exist. Has no effect on the server-side procedure for removing a network. [docker/cli#3547](https://github.com/docker/cli/pull/3547)
- Add a `--signal` option to `docker stop` and `docker restart`. [docker/cli#3614](https://github.com/docker/cli/pull/3614)
- Add a `-v/--version` flag to `docker-proxy`. [moby/moby#44703](https://github.com/moby/moby/pull/44703)
- Plugins are now discovered in well-known user-level paths when the daemon is running in rootless mode. [moby/moby#44778](https://github.com/moby/moby/pull/44778)
- The daemon now handles common alternate JSON encodings in the JSON configuration file gracefully, and reports useful errors. [moby/moby#44777](https://github.com/moby/moby/pull/44777), [moby/moby#44832](https://github.com/moby/moby/pull/44832)
  - UTF-8 with a byte order mark is accepted.
  - UTF-16 with a byte order mark is accepted.
  - Invalid UTF-8 is reported early and with a comprehensible error message.
- Allow use of `STOPSIGNAL` via `docker commit`. [moby/moby#43369](https://github.com/moby/moby/pull/43369)
- Add a new option to the `awslogs` log driver to allow skipping log stream creation in CloudWatch. [moby/moby#42132](https://github.com/moby/moby/pull/42132)
- Add a new option to the `awslogs` log driver to specify the log format that's sent to CloudWatch. [moby/moby#42838](https://github.com/moby/moby/pull/42838)
- Add a new option to the `fluentd` log driver to set the reconnection interval. [moby/moby#43100](https://github.com/moby/moby/pull/43100)
- Add new options-setters to the Go API client: `WithTLSClientConfigFromEnv()`, `WithHostFromEnv()`, and `WithVersionFromEnv()`. [moby/moby#42224](https://github.com/moby/moby/pull/42224)
- Add generation of shell command completion through a `docker completion` subcommand. [docker/cli#3429](https://github.com/docker/cli/pull/3429)
- API: Add a `Swarm` header to `GET /_ping` and `HEAD /_ping`, allowing single-request detection of Swarm support. [moby/moby#42064](https://github.com/moby/moby/pull/42064)
- API: Add a `signal` parameter to `POST /containers/{id}/stop` and `POST /containers/{id}/restart` to set the signal used. [moby/moby#43206](https://github.com/moby/moby/pull/43206)
- API: Add a `CreateMountPoint` parameter to `POST /containers/create`. [moby/moby#43484](https://github.com/moby/moby/pull/43484)
- API: Add a `shared-size` parameter to `GET /images/json` to enable shared-size computation of images. [moby/moby#42531](https://github.com/moby/moby/pull/42531)
- API: Add a `type` parameter to `GET /system/df`, to control what object types to are considered when computing disk usage. [moby/moby#42559](https://github.com/moby/moby/pull/42559)
- systemd: Use a systemd-managed containerd instead of a daemon-managed containerd. [moby/moby#42373](https://github.com/moby/moby/pull/42373)
- systemd: Start `docker.service` after `time-set.target`. [moby/moby#43107](https://github.com/moby/moby/pull/43107)

### Removed

- Remove support for reading configuration from `~/.dockercfg`. [docker/cli#2504](https://github.com/docker/cli/pull/2504)
  - This location has been deprecated since 1.7.0.
  - [Deprecation notice](../deprecated.md#support-for-legacy-dockercfg-configuration-files)
- Remove the `-g` and `--graph` daemon options in favor of `--data-root`. [docker/cli#3739](https://github.com/docker/cli/pull/3739)
  - These options have been hidden and deprecated since 17.05.
  - [Deprecation notice](../deprecated.md#-g-and---graph-flags-on-dockerd)
- Remove client-side sorting of results, in favor of the order in which the search API returns. [docker/cli#3470](https://github.com/docker/cli/pull/3470)
- Remove warnings related to deprecated storage drivers from the CLI. Warnings are now handled by the daemon instead. [docker/cli#3542](https://github.com/docker/cli/pull/3542)
- Remove `Experimental` client field from `docker version`. [docker/cli#3543](https://github.com/docker/cli/pull/3543)
  - [Deprecation notice](../deprecated.md#configuration-options-for-experimental-cli-features)
- Require explicit opt-in to use deprecated storage drivers, and don't automatically select them when upgrading. [moby/moby#43378](https://github.com/moby/moby/pull/43378)
- Remove deprecated support for `overlay` and `overlay2` storage drivers on backing filesystems without `d_type` support. [moby/moby#43472](https://github.com/moby/moby/pull/43472)
  - [Deprecation notice](../deprecated.md#backing-filesystem-without-d_type-support-for-overlayoverlay2)
- Remove the deprecated `overrideKernelCheck` option from the `overlay2` storage driver. [moby/moby#44279](https://github.com/moby/moby/pull/44279)
  [Deprecation notice](../deprecated.md#support-for-the-overlay2override_kernel_check-storage-option)
- Remove support for the deprecated `io.containerd.runtime.v1.linux` OCI runtime. [moby/moby#43695](https://github.com/moby/moby/pull/43695)
- Remove LCOW (Linux Containers on Windows). [moby/moby#42451](https://github.com/moby/moby/pull/42451), [moby/moby#42499](https://github.com/moby/moby/pull/42499), [moby/moby#42506](https://github.com/moby/moby/pull/42506), [moby/moby#42511](https://github.com/moby/moby/pull/42511), [moby/moby#42520](https://github.com/moby/moby/pull/42520), [moby/moby#42683](https://github.com/moby/moby/pull/42683), [moby/moby#42684](https://github.com/moby/moby/pull/42684), [moby/moby#42685](https://github.com/moby/moby/pull/42685), [moby/moby#43187](https://github.com/moby/moby/pull/43187)
  - LCOW was introduced as a technical preview in 17.09 and deprecated in 20.10.
  - [Deprecation notice](../deprecated.md#linux-containers-on-windows-lcow-experimental)
- Remove daemon options related to legacy overlay networks used with standalone Swarm.
  - Remove `--cluster-xx` options from `dockerd`. [moby/moby#40383](https://github.com/moby/moby/issues/40383)
  - Remove `host-discovery` and overlay networks with external k/v stores. [moby/moby#42247](https://github.com/moby/moby/pull/42247)
  - [Deprecation notice](../deprecated.md#classic-swarm-and-overlay-networks-using-cluster-store)
- Remove a deprecated `arm` platform fallback. `--platform linux/arm/vY` will now return a error when `arm/vY` isn't available instead of pulling the wrong image. [moby/moby#44414](https://github.com/moby/moby/pull/44414)
- Remove the deprecated `SetCustomHTTPHeaders()`, `CustomHTTPHeaders()` options-setters from the Go client API. [moby/moby#42694](https://github.com/moby/moby/pull/42694)
- Remove the deprecated `WithDialer()` option-setter from the Go client API. [moby/moby#44022](https://github.com/moby/moby/pull/44022)
  - Use `WithDialContext()` instead.
- Remove the daemon implementation of `opts.QuotedString`. The implementation has moved to the CLI. [moby/moby#43250](https://github.com/moby/moby/pull/43250)
- Remove separate daemon ID from trust-key in the daemon, and disable generating the trust-key. [moby/moby#43555](https://github.com/moby/moby/pull/43555)
- API: Remove the deprecated `KernelMemory` option from `POST /containers/create` on API version >= 1.42. [moby/moby#43214](https://github.com/moby/moby/pull/43214)
  - [Deprecation notice](../deprecated.md#kernel-memory-limit)

### Deprecated

- Require Windows Server RS5 / LTSC 2019 (build 17763) as the minimum to run the daemon. [moby/moby#43254](https://github.com/moby/moby/pull/43254)
- Deprecate `BuilderSize` on API version >= 1.42. [moby/moby#42608](https://github.com/moby/moby/pull/42608)
- Deprecate `BuildCache.Parent` in favor of the newly introduced `BuildCache.Parents` on API version >= 1.42. [moby/moby#43908](https://github.com/moby/moby/pull/43908)
- Deprecate `pkg/urlutil`, moving the implementation to `builder/remotecontext/urlutil`. [moby/moby#43477](https://github.com/moby/moby/pull/43477)

### Upgrades

- Upgrade Go to `1.19.5`. [docker/cli#3958](https://github.com/docker/cli/pull/3958), [moby/moby#44794](https://github.com/moby/moby/pull/44794)
- Upgrade `rootlesskit` to `v0.14.4`. [moby/moby#42708](https://github.com/moby/moby/pull/42708)
- Upgrade `buildkit` to `v0.10.6`. [moby/moby#43239](https://github.com/moby/moby/pull/43239)
- Upgrade `buildx` to `v0.10.2`. [docker/docker-ce-packaging#840](https://github.com/docker/docker-ce-packaging/pull/840)
- Upgrade `swarmkit` to `v2.0.0-20230119195359-904c221ac281`. [moby/moby#44858](https://github.com/moby/moby/pull/44858)
- Upgrade `containerd` to `v1.6.16`. [moby/moby#44766](https://github.com/moby/moby/pull/44766), [moby/moby#44769](https://github.com/moby/moby/pull/44769), [moby/moby#44881](https://github.com/moby/moby/pull/44881)
- Upgrade `runc` to `v1.1.4`. [moby/moby#44039](https://github.com/moby/moby/pull/44039)
- Upgrade `hcsshim` `v0.9.6`. [moby/moby#44658](https://github.com/moby/moby/pull/44658)
- The `btrfs` storage driver now depends on Linux kernel headers (>= 4.12) instead of headers from btrfs-progs. [moby/moby#44776](https://github.com/moby/moby/pull/44776)

### Security

- Change permissions on container `hostconfig.json` files to `0600` (was `0644`). [moby/moby#41620](https://github.com/moby/moby/pull/41620)
- Fix `--seccomp-profile` not accepting `unconfined` and renamed the default seccomp profile to `builtin`. [moby/moby#42481](https://github.com/moby/moby/pull/42481)
- Always build with seccomp support, and remove the `seccomp` build tag. [moby/moby#42501](https://github.com/moby/moby/pull/42501)
- Add seccomp support on `riscv64`. [moby/moby#43553](https://github.com/moby/moby/pull/43553)
- Add support for setting flags passed to `seccomp(2)` in seccomp profiles. [moby/moby#42648](https://github.com/moby/moby/pull/42648)
- Refactor seccomp types to reuse runtime-spec, and add support for `ErrnoRet`. [moby/moby#42005](https://github.com/moby/moby/pull/42005)
- Add support for `DefaultErrnoRet` in `seccomp` profiles. [moby/moby#42604](https://github.com/moby/moby/pull/42604)
- Add an explicit `DefaultErrnoRet` field to the default seccomp profile, with no behavior change. [moby/moby#42649](https://github.com/moby/moby/pull/42649)
- Block `socket` with `AF_VSOCK` in the default seccomp profile. [moby/moby#44563](https://github.com/moby/moby/pull/44563)
- Re-enable `process_vm_readv` and `process_vm_writev` in the default seccomp profile. [moby/moby#42083](https://github.com/moby/moby/pull/42083)
- Add syscalls related to PKU to the default seccomp profile. [moby/moby#43812](https://github.com/moby/moby/pull/43812)
- Allow `clock_settime64` with `CAP_SYS_TIME`. [moby/moby#43775](https://github.com/moby/moby/pull/43775)
- Allow `bpf` with `CAP_BPF` and `perf_event_open` with `CAP_PERFMON`. [moby/moby#43988](https://github.com/moby/moby/pull/43988)
- Explicitly set the `clone3` syscall to return `ENOSYS` in the default seccomp profile, in order to ensure `glibc` will correctly fallback to using `clone`. [moby/moby#42681](https://github.com/moby/moby/pull/42681)

### Bug fixes and enhancements

- Promote `overlay2` to be the default storage driver (`btrfs` and `zfs` are now opt-in). [moby/moby#42661](https://github.com/moby/moby/pull/42661)
- Add a loading spinner to the `docker cp` command. [docker/cli#2708](https://github.com/docker/cli/pull/2708)
- Deprecate the `ElectAuthServer` function, and made it return the default registry without calling the `GET /info` API endpoint. [docker/cli#2819](https://github.com/docker/cli/pull/2819)
- Progress bars are no longer reversed when rolling back Swarm services. [docker/cli#2940](https://github.com/docker/cli/pull/2940)
- Use `net.JoinHostPort()` to fix formatting with IPv6 addresses. [docker/cli#2972](https://github.com/docker/cli/pull/2972)
- CLI error messages are now printed to `stderr`. [docker/cli#3044](https://github.com/docker/cli/pull/3044)
- Improve performance of `docker info` if a custom `--format` is used that only uses local information. With this change, the CLI only uses the daemon API if it detects that information from the daemon is needed. [docker/cli#3179](https://github.com/docker/cli/pull/3179)
- Remove the default value from the `--stop-signal` flag, as it may not reflect the actual default used by the daemon. [docker/cli#3245](https://github.com/docker/cli/pull/3245)
- Add Compose schema `3.10` to `docker stack`; allow omitting the `version` field (resulting in `latest`). [docker/cli#3257](https://github.com/docker/cli/pull/3257)
- Compose version `3` is now equivalent to `3.x` (latest) in `docker stack`. [docker/cli#3445](https://github.com/docker/cli/pull/3445)
- Fix `<Ctrl-c>` hanging on Windows to exit after running a container in non-interactive mode. [docker/cli#3302](https://github.com/docker/cli/pull/3302)
- Add relative source paths to the `run` command in the `-v`/`--volume` and `-m`/`--mount` flags. [docker/cli#3469](https://github.com/docker/cli/pull/3469)
- `docker exec -t` now sets the console size for the executed process immediately when it's created. [docker/cli#3627](https://github.com/docker/cli/pull/3627)
- Update the pretty-print format of `docker info` to provide more details on installed plugins. [docker/cli#3645](https://github.com/docker/cli/pull/3645)
- Print warning messages for the `docker context list` and `docker context use` commands when the context is overridden by the environment. [docker/cli#3668](https://github.com/docker/cli/pull/3668)
- Add a custom `aliases` annotation that can be used to print all available aliases for a command. [docker/cli#3694](https://github.com/docker/cli/pull/3694)
- The CLI no longer creates or updates the CLI configuration file when running `docker context use` and selecting the current context. [docker/cli#3721](https://github.com/docker/cli/pull/3721)
- Non-existing contexts are now ignored when running `docker context rm --force`. [docker/cli#3791](https://github.com/docker/cli/pull/3791)
- Add the ability to override integers to `0` in Compose files. [docker/cli#3812](https://github.com/docker/cli/pull/3812)
- SIGINT (`<Ctrl-c>`) now passes through to running containers instead of causing the CLI to exit. [docker/cli#3849](https://github.com/docker/cli/pull/3849)
- Improve `docker port CONTAINER` UX by sorting ports before printing. [docker/cli#3892](https://github.com/docker/cli/pull/3892)
- API: `GET /containers/{id}/logs` and `POST /containers/{id}/attach` now report which raw-stream format is in use using the `Content-type` response header on API version >= 1.42. [moby/moby#39812](https://github.com/moby/moby/pull/39812)
- Set default sandbox size for Windows layers to 127GB, and ensure that the `--storage-opts` flag applies to all storage on Windows. [moby/moby#41636](https://github.com/moby/moby/pull/41636)
- Remove the plugin section from the containerd configuration file (`/var/run/docker/containerd/containerd.toml`). [moby/moby#41675](https://github.com/moby/moby/pull/41675)
- Reject `null` manifests during tar import. [moby/moby#41842](https://github.com/moby/moby/pull/41842)
- Add shim config for custom runtimes for plugins. [moby/moby#41854](https://github.com/moby/moby/pull/41854)
- Container health checks now resume when the daemon is restarted. [moby/moby#41935](https://github.com/moby/moby/pull/41935)
- Quota is no longer disabled on cleanup of the `btrfs` driver. [moby/moby#42273](https://github.com/moby/moby/pull/42273)
- Host devices that are accessible can now be mounted in `--privileged` rootless containers. [moby/moby#42638](https://github.com/moby/moby/pull/42638)
- Fix incorrect handling of `**/foo` recursive wildcard directory patterns in `.dockerignore`. [moby/moby#42676](https://github.com/moby/moby/pull/42676)
- Extend `docker import --platform` to allow marking an imported image as a foreign architecture. [moby/moby#43103](https://github.com/moby/moby/pull/43103)
- Validation of CPU real-time options is now performed when the daemon starts instead of performing validations for each individual container, allowing startup to fail early. [moby/moby#43131](https://github.com/moby/moby/pull/43131)
- Freeze the `namesgenerator` package against new additions. Users will have to be satisfied with the existing 25359 adjective-name combinations. [moby/moby#43210](https://github.com/moby/moby/pull/43210)
- API: `containers/{id}/attach/ws` only to streams according by `stdin`, `stdout` and `stderr` parameters on API version >= 1.42. [moby/moby#43322](https://github.com/moby/moby/pull/43322)
- Fix UDP traffic in containers not working after the container is restarted under sustained traffic. [moby/moby#43409](https://github.com/moby/moby/pull/43409)
- Add support for pulling images with custom amd64 micro-architecture feature levels as supported by the latest versions of Go, GCC, LLVM, and other compiler tools. [moby/moby#43434](https://github.com/moby/moby/pull/43434)
- Improve validation of invalid JSON requests in the API. [moby/moby#43463](https://github.com/moby/moby/pull/43463)
- Mitigate the impact of slow `exec` starts on health checks. Check timeout now only applies to the duration that the health check command is running. The time it takes to start the command no longer counts against the timeout. [moby/moby#43480](https://github.com/moby/moby/pull/43480)
- Console `tty` size is set immediately on creation. [moby/moby#43593](https://github.com/moby/moby/pull/43593), [moby/moby#43622](https://github.com/moby/moby/pull/43622)
- Fix `overlay2` mounts not being cleaned up after failed container starts, or daemon shutdown. [moby/moby#43659](https://github.com/moby/moby/pull/43659)
- Match manifest list resolution with `containerd`. [moby/moby#43675](https://github.com/moby/moby/pull/43675)
- Skip use of `firewalld` for networking when the daemon is running in rootless mode. [moby/moby#43813](https://github.com/moby/moby/pull/43813)
- Custom NAT networks are now re-created after daemon restart if missing on Windows. [moby/moby#43858](https://github.com/moby/moby/pull/43858)
- Fix terminating the container health-check process when it times out. [moby/moby#43994](https://github.com/moby/moby/pull/43994)
- Fix `live-restore` with restart policies and volume refs. [moby/moby#44237](https://github.com/moby/moby/pull/44237)
- API: Only anonymous volumes now pruned by default on API version >= v1.42. Pass the filter `all=true` to prune named volumes in addition to anonymous. [moby/moby#44259](https://github.com/moby/moby/pull/44259)
- API: Support concurrent calls on the `GET /system/df` endpoint. [moby/moby#42715](https://github.com/moby/moby/pull/42715)
- Improve the reliability of the daemon dumping the stack and exits with code 2 when sent a SIGQUIT. [moby/moby#44831](https://github.com/moby/moby/pull/44831)
- Improve the reliability of `docker logs -f` on Windows, and prevent newlines from being dropped in the `local` log driver. [moby/moby#43294](https://github.com/moby/moby/pull/43294)
- Fix a rare deadlock in the daemon caused by buffering of container logs. [moby/moby#44856](https://github.com/moby/moby/pull/44856)
- Improve error handling in misc filesystem operations so that the daemon can start on a overlayfs backing filesystem. [moby/moby#44834](https://github.com/moby/moby/pull/44834)
- Fix an issue where `--ipc=host` wasn't handled correctly when the daemon is running in rootless mode. [moby/moby#44863](https://github.com/moby/moby/pull/44863)
- Fix a long-standing set of issues where stale conntrack entries caused incorrect routing of UDP traffic for containers. [moby/moby#44752](https://github.com/moby/moby/pull/44752)
- Fix half-registered containers being listed in the API, as well as a nil pointer de-reference and panic caused by using a partially registered container in API calls. [moby/moby#44633](https://github.com/moby/moby/pull/44633)
- Fix a failure to create the `DOCKER-USER` ip6tables chain. [moby/moby#44845](https://github.com/moby/moby/pull/44845)
- Fix a failure to clean up iptables rules when the `ip6tables` command isn't available. [moby/moby#44727](https://github.com/moby/moby/pull/44727)
- Fix an issue where some iptables NAT rules weren't cleaned up after enabling the userland proxy. [moby/moby#44811](https://github.com/moby/moby/pull/44811)
- Fix a potentially leaked process in rare situations where cleaning up a failed attempt to start a container was mishandled. [moby/moby#44400](https://github.com/moby/moby/pull/44400)
- Fix the `CreatedAt` time of a volume reflecting initialization and not creation. [moby/moby#44725](https://github.com/moby/moby/pull/44725)
- Fix an issue where the CLI incorrectly reported an incompatible server instead of an unreachable server in some commands. [docker/cli#3901](https://github.com/docker/cli/pull/3901), [docker/cli#3904](https://github.com/docker/cli/pull/3904)
- Fix broken completion of volumes in Zsh. [docker/cli#2998](https://github.com/docker/cli/pull/2998)
- Improve output of `docker context` when an invalid context is present. [docker/cli#3847](https://github.com/docker/cli/pull/3847)
- Remove ANSI decoration of CLI help annotations when the output isn't a TTY, and added a newline for readability. [docker/cli#3973](https://github.com/docker/cli/pull/3973)
- Add `docker container remove` as an alias for `docker container rm`. [docker/cli#3986](https://github.com/docker/cli/pull/3986)

### Known issues

#### apparmor_parser ([tracking issue](https://github.com/moby/moby/issues/44900))

Some Debian users have reported issues with containers failing to start after upgrading to the 23.0 branch.
The error message indicates that the issue is due to a missing `apparmor_parser` binary:

```console
Error response from daemon: AppArmor enabled on system but the docker-default profile could not be loaded: running `apparmor_parser apparmor_parser --version` failed with output:
error: exec: "apparmor_parser": executable file not found in $PATH
Error: failed to start containers: somecontainer
```

The workaround to this issue is to install the `apparmor` package manually:

```console
apt-get install apparmor
```

#### BuildKit inline cache ([tracking issue](https://github.com/moby/moby/issues/44918))

Attempting to build an image with BuildKit's inline cache feature (e.g. `docker build --build-arg BUILDKIT_INLINE_CACHE=1 .`, `docker buildx build --cache-to type=inline .`) will result in the daemon unexpectedly exiting:

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x147ff00]

goroutine 693 [running]:
github.com/docker/docker/vendor/github.com/moby/buildkit/cache.computeBlobChain.func4.1({0x245cca8, 0x4001394960})
        /go/src/github.com/docker/docker/vendor/github.com/moby/buildkit/cache/blobs.go:206 +0xc90
github.com/docker/docker/vendor/github.com/moby/buildkit/util/flightcontrol.(*call).run(0x40013c2240)
        /go/src/github.com/docker/docker/vendor/github.com/moby/buildkit/util/flightcontrol/flightcontrol.go:121 +0x64
sync.(*Once).doSlow(0x0?, 0x4001328240?)
        /usr/local/go/src/sync/once.go:74 +0x100
sync.(*Once).Do(0x4001328240?, 0x0?)
        /usr/local/go/src/sync/once.go:65 +0x24
created by github.com/docker/docker/vendor/github.com/moby/buildkit/util/flightcontrol.(*call).wait
```

The daemon will restart if configured to do so (e.g. via systemd) after such a crash. The only available mitigation in this release is to avoid performing builds with the inline cache feature enabled.

#### BuildKit with warm cache ([tracking issue](https://github.com/moby/moby/issues/44943))

If an image was built with BuildKit on a previous version of the daemon, and is built with a 23.0 daemon, previously cached layers will not be restored correctly. The image may appear to build correctly if no lines are changed in the Dockerfile; however, if partial cache invalidation occurs due to changing some lines in the Dockerfile, the still valid and previously cached layers will not be loaded correctly.

This most often presents as files that should be present in the image not being present in a `RUN` stage, or any other stage that references files, after changing some lines in the Dockerfile:

```
[+] Building 0.4s (6/6) FINISHED
 => [internal] load build definition from Dockerfile
 => => transferring dockerfile: 102B
 => [internal] load .dockerignore
 => => transferring context: 2B
 => [internal] load metadata for docker.io/library/node:18-alpine
 => [base 1/2] FROM docker.io/library/node:18-alpine@sha256:bc329c7332cffc30c2d4801e38df03cbfa8dcbae2a7a52a449db104794f168a3
 => CACHED [base 2/2] WORKDIR /app
 => ERROR [stage-1 1/1] RUN uname -a
------
 > [stage-1 1/1] RUN uname -a:
#0 0.138 runc run failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory
------
Dockerfile:5
--------------------
   3 |
   4 |     FROM base
   5 | >>> RUN uname -a
   6 |
--------------------
ERROR: failed to solve: process "/bin/sh -c uname -a" did not complete successfully: exit code: 1
```

To mitigate this, the previous build cache must be discarded. `docker builder prune -a` will completely empty the build cache, and allow the affected builds to proceed again by removing the mishandled cache layers.

#### ipvlan networks ([tracking issue](https://github.com/moby/moby/issues/44925))

When upgrading to the 23.0 branch, the existence of any [ipvlan](../network/drivers/ipvlan.md) networks will prevent the daemon from starting:

```
panic: interface conversion: interface {} is nil, not string

goroutine 1 [running]:
github.com/docker/docker/libnetwork/drivers/ipvlan.(*configuration).UnmarshalJSON(0x40011533b0, {0x400069c2d0, 0xef, 0xef})
        /go/src/github.com/docker/docker/libnetwork/drivers/ipvlan/ipvlan_store.go:196 +0x414
encoding/json.(*decodeState).object(0x4001153440, {0x5597157640?, 0x40011533b0?, 0x559524115c?})
        /usr/local/go/src/encoding/json/decode.go:613 +0x650
encoding/json.(*decodeState).value(0x4001153440, {0x5597157640?, 0x40011533b0?, 0x559524005c?})
        /usr/local/go/src/encoding/json/decode.go:374 +0x40
encoding/json.(*decodeState).unmarshal(0x4001153440, {0x5597157640?, 0x40011533b0?})
        /usr/local/go/src/encoding/json/decode.go:181 +0x204
encoding/json.Unmarshal({0x400069c2d0, 0xef, 0xef}, {0x5597157640, 0x40011533b0})
        /usr/local/go/src/encoding/json/decode.go:108 +0xf4
github.com/docker/docker/libnetwork/drivers/ipvlan.(*configuration).SetValue(0x4000d18050?, {0x400069c2d0?, 0x23?, 0x23?})
        /go/src/github.com/docker/docker/libnetwork/drivers/ipvlan/ipvlan_store.go:230 +0x38
```

To mitigate this, affected users can downgrade and remove the network, then upgrade again.
Alternatively, the entire network store can be removed, and networks can be recreated after the upgrade. The network store is located at `/var/lib/docker/network/files/local-kv.db`. If the daemon is using an alternate `--data-root`, substitute `/var/lib/docker` for the alternate path.

#### Kata Containers ([tracking issue](https://github.com/kata-containers/kata-containers/issues/6154))

The 23.0 branch brings support for alternate containerd shims, such as `io.containerd.runsc.v1` (gVisor) and `io.containerd.kata.v2` (Kata Containers).

When using the Kata Containers runtime, exiting an `exec` session stops the running container, and hangs the connected CLI if a TTY was opened. There is no mitigation at this time beyond avoiding execing into containers running on the Kata runtime.

The root cause of this issue is a long-standing bug in Moby. This will be resolved in a future release. Be advised that support for alternate OCI runtimes is a new feature and that similar issues may be discovered as more users start exercising this functionality.


---

# Docker Engine 24.0 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 24.0.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 24.0.9

{{< release-date date="2024-01-31" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.9 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.9)
- [moby/moby, 24.0.9 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.9)

## Security

This release contains security fixes for the following CVEs
affecting Docker Engine and its components.

| CVE                                                         | Component     | Fix version | Severity         |
| ----------------------------------------------------------- | ------------- | ----------- | ---------------- |
| [CVE-2024-21626](https://scout.docker.com/v/CVE-2024-21626) | runc          | 1.1.12      | High, CVSS 8.6   |
| [CVE-2024-24557](https://scout.docker.com/v/CVE-2024-24557) | Docker Engine | 24.0.9      | Medium, CVSS 6.9 |

> [!IMPORTANT]
>
> Note that this release of Docker Engine doesn't include fixes for
> the following known vulnerabilities in BuildKit:
>
> - [CVE-2024-23651](https://scout.docker.com/v/CVE-2024-23651)
> - [CVE-2024-23652](https://scout.docker.com/v/CVE-2024-23652)
> - [CVE-2024-23653](https://scout.docker.com/v/CVE-2024-23653)
> - [CVE-2024-23650](https://scout.docker.com/v/CVE-2024-23650)
>
> To address these vulnerabilities,
> upgrade to [Docker Engine v25.0.2](25.0.md#2502).

For more information about the security issues addressed in this release,
and the unaddressed vulnerabilities in BuildKit,
refer to the
[blog post](https://www.docker.com/blog/docker-security-advisory-multiple-vulnerabilities-in-runc-buildkit-and-moby/).

For details about each vulnerability, see the relevant security advisory:

- [CVE-2024-21626](https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv)
- [CVE-2024-24557](https://github.com/moby/moby/security/advisories/GHSA-xw73-rw38-6vjc)

### Packaging updates

- Upgrade runc to [v1.1.12](https://github.com/opencontainers/runc/releases/tag/v1.1.12). [moby/moby#47269](https://github.com/moby/moby/pull/47269)
- Upgrade containerd to [v1.7.13](https://github.com/containerd/containerd/releases/tag/v1.7.13) (static binaries only). [moby/moby#47280](https://github.com/moby/moby/pull/47280)

## 24.0.8

{{< release-date date="2024-01-25" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.8 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.8)
- [moby/moby, 24.0.8 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.8)

### Bug fixes and enhancements
* Live restore: Containers with auto remove (`docker run --rm`) are no longer forcibly removed on engine restart. [moby/moby#46857](https://github.com/moby/moby/pull/46869)

### Packaging updates
* Upgrade Go to `go1.20.13`. [moby/moby#47054](https://github.com/moby/moby/pull/47054), [docker/cli#4826](https://github.com/docker/cli/pull/4826), [docker/docker-ce-packaging#975](https://github.com/docker/docker-ce-packaging/pull/975)
* Upgrade containerd (static binaries only) to [v1.7.12](https://github.com/containerd/containerd/releases/tag/v1.7.12) [moby/moby#47096](https://github.com/moby/moby/pull/47096)
* Upgrade runc to v1.1.11. [moby/moby#47010](https://github.com/moby/moby/pull/47010)

## 24.0.7

{{< release-date date="2023-10-27" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.7 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.7)
- [moby/moby, 24.0.7 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.7)

### Bug fixes and enhancements

* Write overlay2 layer metadata atomically. [moby/moby#46703](https://github.com/moby/moby/pull/46703)
* Fix "Rootful-in-Rootless" Docker-in-Docker on systemd version 250 and later. [moby/moby#46626](https://github.com/moby/moby/pull/46626)
* Fix `dockerd-rootless-setuptools.sh` when username contains a backslash. [moby/moby#46407](https://github.com/moby/moby/pull/46407)
* Fix a bug that would prevent network sandboxes to be fully deleted when stopping containers with no network attachments and when `dockerd --bridge=none` is used. [moby/moby#46702](https://github.com/moby/moby/pull/46702)
* Fix a bug where cancelling an API request could interrupt container restart. [moby/moby#46697](https://github.com/moby/moby/pull/46697)
* Fix an issue where containers would fail to start when providing `--ip-range` with a range larger than the subnet. [docker/for-mac#6870](https://github.com/docker/for-mac/issues/6870)
* Fix data corruption with zstd output. [moby/moby#46709](https://github.com/moby/moby/pull/46709)
* Fix the conditions under which the container's MAC address is applied. [moby/moby#46478](https://github.com/moby/moby/pull/46478)
* Improve the performance of the stats collector. [moby/moby#46448](https://github.com/moby/moby/pull/46448)
* Fix an issue with source policy rules ending up in the wrong order. [moby/moby#46441](https://github.com/moby/moby/pull/46441)

### Packaging updates

* Add support for Fedora 39 and Ubuntu 23.10. [docker/docker-ce-packaging#940](https://github.com/docker/docker-ce-packaging/pull/940), [docker/docker-ce-packaging#955](https://github.com/docker/docker-ce-packaging/pull/955)
* Fix `docker.socket` not getting disabled when uninstalling the `docker-ce` RPM package. [docker/docker-ce-packaging#852](https://github.com/docker/docker-ce-packaging/pull/852)
* Upgrade Go to `go1.20.10`. [docker/docker-ce-packaging#951](https://github.com/docker/docker-ce-packaging/pull/951)
* Upgrade containerd to `v1.7.6` (static binaries only). [moby/moby#46103](https://github.com/moby/moby/pull/46103)
* Upgrade the `containerd.io` package to [`v1.6.24`](https://github.com/containerd/containerd/releases/tag/v1.6.24).

### Security

* Deny containers access to `/sys/devices/virtual/powercap` by default. This change hardens against
  [CVE-2020-8694](https://scout.docker.com/v/CVE-2020-8694),
  [CVE-2020-8695](https://scout.docker.com/v/CVE-2020-8695), and
  [CVE-2020-12912](https://scout.docker.com/v/CVE-2020-12912),
  and an attack known as [the PLATYPUS attack](https://platypusattack.com/).

  For more details, see
  [advisory](https://github.com/moby/moby/security/advisories/GHSA-jq35-85cj-fj4p),
  [commit](https://github.com/moby/moby/commit/c9ccbfad11a60e703e91b6cca4f48927828c7e35).

## 24.0.6

{{< release-date date="2023-09-05" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.6 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.6)
- [moby/moby, 24.0.6 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.6)

### Bug fixes and enhancements

* containerd storage backend: Fix `docker ps` failing when a container image is no longer present in the content store. [moby/moby#46095](https://github.com/moby/moby/pull/46095)
* containerd storage backend: Fix `docker ps -s -a` and `docker container prune` failing when a container image config is no longer present in the content store. [moby/moby#46097](https://github.com/moby/moby/pull/46097)
* containerd storage backend: Fix `docker inspect` failing when a container image config is no longer (or was never) present in the content store. [moby/moby#46244](https://github.com/moby/moby/pull/46244)
* containerd storage backend: Fix diff and export with the `overlayfs` snapshotter by using reference-counted rootfs mounts. [moby/moby#46266](https://github.com/moby/moby/pull/46266)
* containerd storage backend: Fix a misleading error message when the image platforms available locally do not match the desired platform. [moby/moby#46300](https://github.com/moby/moby/pull/46300)
* containerd storage backend: Fix the `FROM scratch` Dockerfile instruction with the classic builder. [moby/moby#46302](https://github.com/moby/moby/pull/46302)
* containerd storage backend: Fix `mismatched image rootfs and manifest layers` errors with the classic builder. [moby/moby#46310](https://github.com/moby/moby/pull/46310)
* Warn when pulling Docker Image Format v1, and Docker Image manifest version 2, schema 1 images from all registries. [moby/moby#46290](https://github.com/moby/moby/pull/46290)
* Fix live-restore of volumes with custom volume options. [moby/moby#46366](https://github.com/moby/moby/pull/46366)
* Fix incorrectly dropping capabilities bits when running a container as a non-root user (note: this change was already effectively present due to a regression). [moby/moby#46221](https://github.com/moby/moby/pull/46221)
* Fix network isolation iptables rules preventing IPv6 Neighbor Solicitation packets from being exchanged between containers. [moby/moby#46214](https://github.com/moby/moby/pull/46214)
* Fix `dockerd.exe --register-service` not working when the binary is in the current directory on Windows. [moby/moby#46215](https://github.com/moby/moby/pull/46215)
* Add a hint suggesting the use of a PAT to `docker login` against Docker Hub. [docker/cli#4500](https://github.com/docker/cli/pull/4500)
* Improve shell startup time for users of Bash completion for the CLI. [docker/cli#4517](https://github.com/docker/cli/pull/4517)
* Improve the speed of some commands by skipping `GET /_ping` when possible. [docker/cli#4508](https://github.com/docker/cli/pull/4508)
* Fix credential scopes when using a PAT to `docker manifest inspect` an image on Docker Hub. [docker/cli#4512](https://github.com/docker/cli/pull/4512)
* Fix `docker events` not supporting `--format=json`. [docker/cli#4544](https://github.com/docker/cli/pull/4544)

### Packaging updates

* Upgrade Go to `go1.20.7`. [moby/moby#46140](https://github.com/moby/moby/pull/46140), [docker/cli#4476](https://github.com/docker/cli/pull/4476), [docker/docker-ce-packaging#932](https://github.com/docker/docker-ce-packaging/pull/932)
* Upgrade containerd to `v1.7.3` (static binaries only). [moby/moby#46103](https://github.com/moby/moby/pull/46103)
* Upgrade Compose to `v2.21.0`. [docker/docker-ce-packaging#936](https://github.com/docker/docker-ce-packaging/pull/936)

## 24.0.5

{{< release-date date="2023-07-24" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.5 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.5)
- [moby/moby, 24.0.5 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.5)

### Bug fixes and enhancements

* The Go client now avoids using UNIX socket paths in the HTTP `Host:` header, in order to be compatible with changes introduced in `go1.20.6`. [moby/moby#45962](https://github.com/moby/moby/pull/45962), [moby/moby#45990](https://github.com/moby/moby/pull/45990)
* containerd storage backend: Fix `Variant` not being included in `docker image inspect` and `GET /images/{name}/json`. [moby/moby#46025](https://github.com/moby/moby/pull/46025)
* containerd storage backend: Prevent potential garbage collection of content during image export. [moby/moby#46021](https://github.com/moby/moby/pull/46021)
* containerd storage backend: Prevent duplicate digest entries in `RepoDigests`. [moby/moby#46014](https://github.com/moby/moby/pull/46014)
* containerd storage backend: Fix operations taking place against the incorrect tag when working with an image referenced by tag and digest. [moby/moby#46013](https://github.com/moby/moby/pull/46013)
* containerd storage backend: Fix a panic caused by `EXPOSE` when building containers with the legacy builder. [moby/moby#45921](https://github.com/moby/moby/pull/45921)
* Fix a regression causing unintuitive errors to be returned when attempting to create an `overlay` network on a non-Swarm node. [moby/moby#45974](https://github.com/moby/moby/pull/45974)
* Properly report errors parsing volume specifications from the command line. [docker/cli#4423](https://github.com/docker/cli/pull/4423)
* Fix a panic caused when `auths: null` is found in the CLI config file. [docker/cli#4450](https://github.com/docker/cli/pull/4450)

### Packaging updates

* Use init scripts as provided by in moby/moby `contrib/init`. [docker/docker-ce-packaging#914](https://github.com/docker/docker-ce-packaging/pull/914), [docker/docker-ce-packaging#926](https://github.com/docker/docker-ce-packaging/pull/926)
* Drop Upstart from `contrib/init`. [moby/moby#46044](https://github.com/moby/moby/pull/46044)
* Upgrade Go to `go1.20.6`. [docker/cli#4428](https://github.com/docker/cli/pull/4428), [moby/moby#45970](https://github.com/moby/moby/pull/45970), [docker/docker-ce-packaging#921](https://github.com/docker/docker-ce-packaging/pull/921)
* Upgrade Compose to `v2.20.2`. [docker/docker-ce-packaging#924](https://github.com/docker/docker-ce-packaging/pull/924)
* Upgrade buildx to `v0.11.2`. [docker/docker-ce-packaging#922](https://github.com/docker/docker-ce-packaging/pull/922)


## 24.0.4

{{< release-date date="2023-07-07" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.4 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.4)
- [moby/moby, 24.0.4 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.4)

### Bug fixes and enhancements

* Fix a regression introduced during 24.0.3 that causes a panic during live-restore of containers with bind mounts. [moby/moby#45903](https://github.com/moby/moby/pull/45903)


## 24.0.3

{{< release-date date="2023-07-06" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.3)
- [moby/moby, 24.0.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.3)

### Bug fixes and enhancements

* containerd image store: Fix an issue where multi-platform images that did not include a manifest for the default platform could not be interacted with. [moby/moby#45849](https://github.com/moby/moby/pull/45849)
* containerd image store: Fix specious attempts to cache `FROM scratch` in container builds. [moby/moby#45822](https://github.com/moby/moby/pull/45822)
* containerd image store: Fix `docker cp` with snapshotters that cannot mount the same content multiple times. [moby/moby#45780](https://github.com/moby/moby/pull/45780), [moby/moby#45786](https://github.com/moby/moby/pull/45786)
* containerd image store: Fix builds with `type=image` not being correctly unpacked/stored. [moby/moby#45692](https://github.com/moby/moby/pull/45692)
* containerd image store: Fix incorrectly attempting to unpack pseudo-images (including attestations) in `docker load`. [moby/moby#45688](https://github.com/moby/moby/pull/45688)
* containerd image store: Correctly set the user agent, and include additional information like the snapshotter when interacting with registries. [moby/moby#45671](https://github.com/moby/moby/pull/45671), [moby/moby#45684](https://github.com/moby/moby/pull/45684)
* containerd image store: Fix a failure to unpack already-pulled content after switching between snapshotters. [moby/moby#45678](https://github.com/moby/moby/pull/45678)
* containerd image store: Fix images that have been re-tagged or with all tags removed being pruned while still in use. [moby/moby#45857](https://github.com/moby/moby/pull/45857)
* Fix a Swarm CSI issue where the Topology field was not propagated into NodeCSIInfo. [moby/moby#45810](https://github.com/moby/moby/pull/45810)
* Fix failures to add new Swarm managers caused by a very large raft log. [moby/moby#45703](https://github.com/moby/moby/pull/45703), [moby/swarmkit#3122](https://github.com/moby/swarmkit/pull/3122), [moby/swarmkit#3128](https://github.com/moby/swarmkit/pull/3128)
* `name_to_handle_at(2)` is now always allowed in the default seccomp profile. [moby/moby#45833](https://github.com/moby/moby/pull/45833)
* Fix an issue that prevented encrypted Swarm overlay networks from working on ports other than the default (4789). [moby/moby#45637](https://github.com/moby/moby/pull/45637)
* Fix a failure to restore mount reference-counts during live-restore. [moby/moby#45824](https://github.com/moby/moby/pull/45824)
* Fix various networking-related failures during live-restore. [moby/moby#45658](https://github.com/moby/moby/pull/45658), [moby/moby#45659](https://github.com/moby/moby/pull/45659)
* Fix running containers restoring with a zero (successful) exit status when the daemon is unexpectedly terminated. [moby/moby#45801](https://github.com/moby/moby/pull/45801)
* Fix a potential panic while executing healthcheck probes. [moby/moby#45798](https://github.com/moby/moby/pull/45798)
* Fix a panic caused by a race condition in container exec start. [moby/moby#45794](https://github.com/moby/moby/pull/45794)
* Fix an exception caused by attaching a terminal to an exec with a non-existent command. [moby/moby#45643](https://github.com/moby/moby/pull/45643)
* Fix `host-gateway` with BuildKit by passing the IP as a label (also requires [docker/buildx#1894](https://github.com/docker/buildx/pull/1894)). [moby/moby#45790](https://github.com/moby/moby/pull/45790)
* Fix an issue where `POST /containers/{id}/stop` would forcefully terminate the container when the request was canceled, instead of waiting until the specified timeout for a 'graceful' stop. [moby/moby#45774](https://github.com/moby/moby/pull/45774)
* Fix an issue where `docker cp -a` from the root (`/`) directory would fail. [moby/moby#45748](https://github.com/moby/moby/pull/45748)
* Improve compatibility with non-runc container runtimes by more correctly setting resource constraint parameters in the OCI config. [moby/moby#45746](https://github.com/moby/moby/pull/45746)
* Fix an issue caused by overlapping subuid/subgid ranges in certain configurations (e.g. LDAP) in rootless mode. [moby/moby#45747](https://github.com/moby/moby/pull/45747), [rootless-containers/rootlesskit#369](https://github.com/rootless-containers/rootlesskit/pull/369)
* Greatly reduce CPU and memory usage while populating the Debug section of `GET /info`. [moby/moby#45856](https://github.com/moby/moby/pull/45856)
* Fix an issue where debug information was not correctly printed during `docker info` when only the client is in debug mode. [docker/cli#4393](https://github.com/docker/cli/pull/4393)
* Fix issues related to hung connections when connecting to hosts over a SSH connection. [docker/cli#4395](https://github.com/docker/cli/pull/4395)

### Packaging updates

* Upgrade Go to `go1.20.5`. [moby/moby#45745](https://github.com/moby/moby/pull/45745), [docker/cli#4351](https://github.com/docker/cli/pull/4351), [docker/docker-ce-packaging#904](https://github.com/docker/docker-ce-packaging/pull/904)
* Upgrade Compose to `v2.19.1`. [docker/docker-ce-packaging#916](https://github.com/docker/docker-ce-packaging/pull/916)
* Upgrade buildx to `v0.11.1`. [docker/docker-ce-packaging#918](https://github.com/docker/docker-ce-packaging/pull/918)


## 24.0.2

{{< release-date date="2023-05-26" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.2)
- [moby/moby, 24.0.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.2)

### Bug fixes and enhancements

* Fix a panic during build when referencing locally tagged images. [moby/buildkit#3899](https://github.com/moby/buildkit/pull/3899), [moby/moby#45582](https://github.com/moby/moby/pull/45582)
* Fix builds potentially failing with `exit code: 4294967295` when performing many concurrent build stages. [moby/moby#45620](https://github.com/moby/moby/pull/45620)
* Fix DNS resolution on Windows ignoring `etc/hosts` (`%WINDIR%\System32\Drivers\etc\hosts`), including resolution of `localhost`. [moby/moby#45562](https://github.com/moby/moby/pull/45562)
* Apply a workaround for a containerd bug that causes concurrent `docker exec` commands to take significantly longer than expected. [moby/moby#45625](https://github.com/moby/moby/pull/45625)
* containerd image store: Fix an issue where the image `Created` field would contain an incorrect value. [moby/moby#45623](https://github.com/moby/moby/pull/45623)
* containerd image store: Adjust the output of image pull progress so that the output has the same format regardless of whether the containerd image store is enabled. [moby/moby#45602](https://github.com/moby/moby/pull/45602)
* containerd image store: Switching between the default and containerd image store now requires a daemon restart. [moby/moby#45616](https://github.com/moby/moby/pull/45616)

### Packaging updates

* Upgrade Buildx to `v0.10.5`. [docker/docker-ce-packaging#900](https://github.com/docker/docker-ce-packaging/pull/900)


## 24.0.1

{{< release-date date="2023-05-19" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.1)
- [moby/moby, 24.0.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.1)

### Removed

* Remove CLI completions for storage drivers removed in the 24.0 major release. [docker/cli#4302](https://github.com/docker/cli/pull/4302)

### Bug fixes and enhancements

* Fix an issue where DNS query NXDOMAIN replies from external servers were forwarded to the client as SERVFAIL. [moby/moby#45573](https://github.com/moby/moby/pull/45573)
* Fix an issue where `docker pull --platform` would report `No such image` regarding another tag pointing to the same image. [moby/moby#45562](https://github.com/moby/moby/pull/45562)
* Fix an issue where insecure registry configuration would be forgotten during config reload. [moby/moby#45571](https://github.com/moby/moby/pull/45571)
* containerd image store: Fix an issue where images which have no layers would not be listed in `docker images -a` [moby/moby#45588](https://github.com/moby/moby/pull/45588)
* API: Fix an issue where `GET /images/{id}/json` would return `null` instead of empty `RepoTags` and `RepoDigests`. [moby/moby#45564](https://github.com/moby/moby/pull/45564)
* API: Fix an issue where `POST /commit` did not accept an empty request body. [moby/moby#45568](https://github.com/moby/moby/pull/45568)

### Packaging updates

* Upgrade Compose to `v2.18.1`. [docker/docker-ce-packaging#896](https://github.com/docker/docker-ce-packaging/pull/896)


## 24.0.0

{{< release-date date="2023-05-16" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 24.0.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A24.0.0)
- [moby/moby, 24.0.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A24.0.0)

### New

* Introduce experimental support for containerd as the content store (replacing the existing storage drivers). [moby/moby#43735](https://github.com/moby/moby/pull/43735), [other moby/moby pull requests](https://github.com/moby/moby/pulls?q=is%3Apr+is%3Amerged+milestone%3A24.0.0+-label%3Aprocess%2Fcherry-picked+label%3Acontainerd-integration+)
* The `--host` CLI flag now supports a path component in a `ssh://` host address, allowing use of an alternate socket path without configuration on the remote host. [docker/cli#4073](https://github.com/docker/cli/pull/4073)
* The `docker info` CLI command now reports a version and platform field. [docker/cli#4180](https://github.com/docker/cli/pull/4180)
* Introduce the daemon flag `--default-network-opt` to configure options for newly created networks. [moby/moby#43197](https://github.com/moby/moby/pull/43197)
* Restrict access to `AF_VSOCK` in the `socket(2)` family of syscalls in the default seccomp profile. [moby/moby#44562](https://github.com/moby/moby/pull/44562)
* Introduce support for setting OCI runtime annotations on containers. [docker/cli#4156](https://github.com/docker/cli/pull/4156), [moby/moby#45025](https://github.com/moby/moby/pull/45025)
* Alternative runtimes can now be configured in `daemon.json`, enabling runtime names to be aliased and options to be passed. [moby/moby#45032](https://github.com/moby/moby/pull/45032)
* The `docker-init` binary will now be discovered in FHS-compliant libexec directories, in addition to the `PATH`. [moby/moby#45198](https://github.com/moby/moby/pull/45198)
* API: Surface the daemon-level `--no-new-privileges` in `GET /info`. [moby/moby#45320](https://github.com/moby/moby/pull/45320)

### Removed

* `docker info` no longer reports `IndexServiceAddress`. [docker/cli#4204](https://github.com/docker/cli/pull/4204)
* libnetwork: Remove fallback code for obsolete kernel versions. [moby/moby#44684](https://github.com/moby/moby/pull/44684), [moby/moby#44802](https://github.com/moby/moby/pull/44802)
* libnetwork: Remove unused code related to classic Swarm. [moby/moby#44965](https://github.com/moby/moby/pull/44965)
* libnetwork: Remove usage of the `xt_u32` kernel module from encrypted Swarm overlay networks. [moby/moby#45281](https://github.com/moby/moby/pull/45281)
* Remove support for BuildKit's deprecated `buildinfo` in favor of standard provenance attestations. [moby/moby#45097](https://github.com/moby/moby/pull/45097)
* Remove the deprecated AUFS and legacy `overlay` storage drivers. [moby/moby#45342](https://github.com/moby/moby/pull/45342), [moby/moby#45359](https://github.com/moby/moby/pull/45359)
* Remove the deprecated `overlay2.override_kernel_check` storage driver option. [moby/moby#45368](https://github.com/moby/moby/pull/45368)
* Remove workarounds for obsolete versions of `apparmor_parser` from the AppArmor profiles. [moby/moby#45500](https://github.com/moby/moby/pull/45500)
* API:  `GET /images/json` no longer represents empty RepoTags and RepoDigests as`<none>:<none>`/`<none>@<none>`. Empty arrays are returned instead on API >= 1.43. [moby/moby#45068](https://github.com/moby/moby/pull/45068)

### Deprecated

* Deprecate the `--oom-score-adjust` daemon option. [moby/moby#45315](https://github.com/moby/moby/pull/45315)
* API: Deprecate the `VirtualSize` field in `GET /images/json` and `GET /images/{id}/json`. [moby/moby#45346](https://github.com/moby/moby/pull/45346)

### Bug fixes and enhancements

* The `docker stack` command no longer validates the `build` section of Compose files. [docker/cli#4214](https://github.com/docker/cli/pull/4214)
* Fix lingering healthcheck processes after the timeout is reached. [moby/moby#43739](https://github.com/moby/moby/pull/43739)
* Reduce the overhead of container startup when using the `overlay2` storage driver. [moby/moby#44285](https://github.com/moby/moby/pull/44285)
* API: Handle multiple `before=` and `since=` filters in `GET /images`. [moby/moby#44503](https://github.com/moby/moby/pull/44503)
* Fix numerous bugs in the embedded DNS resolver implementation used by user-defined networks. [moby/moby#44664](https://github.com/moby/moby/pull/44664)
* Add `execDuration` field to the map of event attributes. [moby/moby#45494](https://github.com/moby/moby/pull/45494)
* Swarm-level networks can now be created with the Windows `internal`, `l2bridge`, and `nat` drivers. [moby/swarmkit#3121](https://github.com/moby/swarmkit/pull/3121), [moby/moby#45291](https://github.com/moby/moby/pull/45291)

### Packaging updates

* Update Go to `1.20.4`. [docker/cli#4253](https://github.com/docker/cli/pull/4253), [moby/moby#45456](https://github.com/moby/moby/pull/45456), [docker/docker-ce-packaging#888](https://github.com/docker/docker-ce-packaging/pull/888)
* Update `containerd` to [`v1.7.1`](https://github.com/containerd/containerd/releases/tag/v1.7.1). [moby/moby#45537](https://github.com/moby/moby/pull/45537)
* Update `buildkit` to [`v0.11.6`](https://github.com/moby/buildkit/releases/v0.11.6). [moby/moby#45367](https://github.com/moby/moby/pull/45367)


---

# Docker Engine 25.0 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 25.0.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 25.0.5

{{< release-date date="2024-03-19" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 25.0.5 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A25.0.5)
- [moby/moby, 25.0.5 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A25.0.5)

### Security

This release contains a security fix for [CVE-2024-29018], a potential data exfiltration from 'internal' networks via authoritative DNS servers.

### Bug fixes and enhancements

- [CVE-2024-29018]: Do not forward requests to external DNS servers for a container that is only connected to an 'internal' network. Previously, requests were forwarded if the host's DNS server was running on a loopback address, like systemd's 127.0.0.53. [moby/moby#47589](https://github.com/moby/moby/pull/47589)
- plugin: fix mounting /etc/hosts when running in UserNS. [moby/moby#47588](https://github.com/moby/moby/pull/47588)
- rootless: fix `open /etc/docker/plugins: permission denied`. [moby/moby#47587](https://github.com/moby/moby/pull/47587)
- Fix multiple parallel `docker build` runs leaking disk space. [moby/moby#47527](https://github.com/moby/moby/pull/47527)

  [CVE-2024-29018]: https://github.com/moby/moby/security/advisories/GHSA-mq39-4gv4-mvpx

## 25.0.4

{{< release-date date="2024-03-07" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 25.0.4 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A25.0.4)
- [moby/moby, 25.0.4 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A25.0.4)

### Bug fixes and enhancements

- Restore DNS names for containers in the default "nat" network on Windows. [moby/moby#47490](https://github.com/moby/moby/pull/47490)
- Fix `docker start` failing when used with `--checkpoint` [moby/moby#47466](https://github.com/moby/moby/pull/47466)
- Don't enforce new validation rules for existing swarm networks [moby/moby#47482](https://github.com/moby/moby/pull/47482)
- Restore IP connectivity between the host and containers on an internal bridge network. [moby/moby#47481](https://github.com/moby/moby/pull/47481)
- Fix a regression introduced in v25.0 that prevented the classic builder from adding tar archive with `xattrs` created on a non-Linux OS [moby/moby#47483](https://github.com/moby/moby/pull/47483)
- containerd image store: Fix image pull not emitting `Pulling fs layer status` [moby/moby#47484](https://github.com/moby/moby/pull/47484)
- API: To preserve backwards compatibility, make read-only mounts non-recursive by default when using older clients (API versions < v1.44). [moby/moby#47393](https://github.com/moby/moby/pull/47393)
- API: `GET /images/{id}/json` omits the `Created` field (previously it was `0001-01-01T00:00:00Z`) if the `Created` field was missing from the image config. [moby/moby#47451](https://github.com/moby/moby/pull/47451)
- API: Populate a missing `Created` field in `GET /images/{id}/json` with `0001-01-01T00:00:00Z` for API versions <= 1.43. [moby/moby#47387](https://github.com/moby/moby/pull/47387)
- API: Fix a regression that caused API socket connection failures to report an API version negotiation failure instead. [moby/moby#47470](https://github.com/moby/moby/pull/47470)
- API: Preserve supplied endpoint configuration in a container-create API request, when a container-wide MAC address is specified, but `NetworkMode` name or id is not the same as the name or id used in `NetworkSettings.Networks`. [moby/moby#47510](https://github.com/moby/moby/pull/47510)

### Packaging updates

- Upgrade Go runtime to 1.21.8. [moby/moby#47503](https://github.com/moby/moby/pull/47503)
- Upgrade RootlessKit to v2.0.2. [moby/moby#47508](https://github.com/moby/moby/pull/47508)
- Upgrade Compose to v2.24.7. [docker/docker-ce-packaging#998](https://github.com/moby/moby/pull/998)
- Upgrade Buildx to v0.13.0. [docker/docker-ce-packaging#997](https://github.com/moby/moby/pull/997)

## 25.0.3

{{< release-date date="2024-02-06" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 25.0.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A25.0.3)
- [moby/moby, 25.0.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A25.0.3)

### Bug fixes and enhancements

- containerd image store: Fix a bug where `docker image history` would fail if a manifest wasn't found in the content store. [moby/moby#47348](https://github.com/moby/moby/pull/47348)
- Ensure that a generated MAC address is not restored when a container is restarted, but a configured MAC address is preserved. [moby/moby#47304](https://github.com/moby/moby/pull/47304)

  > [!NOTE]
  >
  > - Containers created with Docker Engine version 25.0.0 may have duplicate MAC addresses.
  >   They must be re-created.
  > - Containers with user-defined MAC addresses created with Docker Engine versions 25.0.0 or 25.0.1
  >   receive new MAC addresses when started using Docker Engine version 25.0.2.
  >   They must also be re-created.

- Fix `docker save <image>@<digest>` producing an OCI archive with index without manifests. [moby/moby#47294](https://github.com/moby/moby/pull/47294)
- Fix a bug preventing bridge networks from being created with an MTU higher than 1500 on RHEL and CentOS 7. [moby/moby#47308](https://github.com/moby/moby/issues/47308), [moby/moby#47311](https://github.com/moby/moby/pull/47311)
- Fix a bug where containers are unable to communicate over an `internal` network. [moby/moby#47303](https://github.com/moby/moby/pull/47303)
- Fix a bug where the value of the `ipv6` daemon option was ignored. [moby/moby#47310](https://github.com/moby/moby/pull/47310)
- Fix a bug where trying to install a pulling using a digest revision would cause a panic. [moby/moby#47323](https://github.com/moby/moby/pull/47323)
- Fix a potential race condition in the managed containerd supervisor. [moby/moby#47313](https://github.com/moby/moby/pull/47313)
- Fix an issue with the `journald` log driver preventing container logs from being followed correctly with systemd version 255. [moby/moby#47243](https://github.com/moby/moby/pull/47243)
- seccomp: Update the builtin seccomp profile to include syscalls added in kernel v5.17 - v6.7 to align the profile with the profile used by containerd. [moby/moby#47341](https://github.com/moby/moby/pull/47341)
- Windows: Fix cache not being used when building images based on Windows versions older than the host's version. [moby/moby#47307](https://github.com/moby/moby/pull/47307), [moby/moby#47337](https://github.com/moby/moby/pull/47337)

### Packaging updates

- Removed support for Ubuntu Lunar (23.04). [docker/ce-packaging#986](https://github.com/docker/docker-ce-packaging/pull/986)

## 25.0.2

{{< release-date date="2024-01-31" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 25.0.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A25.0.2)
- [moby/moby, 25.0.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A25.0.2)

### Security

This release contains security fixes for the following CVEs
affecting Docker Engine and its components.

| CVE                                                         | Component     | Fix version | Severity         |
| ----------------------------------------------------------- | ------------- | ----------- | ---------------- |
| [CVE-2024-21626](https://scout.docker.com/v/CVE-2024-21626) | runc          | 1.1.12      | High, CVSS 8.6   |
| [CVE-2024-23651](https://scout.docker.com/v/CVE-2024-23651) | BuildKit      | 1.12.5      | High, CVSS 8.7   |
| [CVE-2024-23652](https://scout.docker.com/v/CVE-2024-23652) | BuildKit      | 1.12.5      | High, CVSS 8.7   |
| [CVE-2024-23653](https://scout.docker.com/v/CVE-2024-23653) | BuildKit      | 1.12.5      | High, CVSS 7.7   |
| [CVE-2024-23650](https://scout.docker.com/v/CVE-2024-23650) | BuildKit      | 1.12.5      | Medium, CVSS 5.5 |
| [CVE-2024-24557](https://scout.docker.com/v/CVE-2024-24557) | Docker Engine | 25.0.2      | Medium, CVSS 6.9 |

The potential impacts of the above vulnerabilities include:

- Unauthorized access to the host filesystem
- Compromising the integrity of the build cache
- In the case of CVE-2024-21626, a scenario that could lead to full container escape

For more information about the security issues addressed in this release,
refer to the [blog post](https://www.docker.com/blog/docker-security-advisory-multiple-vulnerabilities-in-runc-buildkit-and-moby/).
For details about each vulnerability, see the relevant security advisory:

- [CVE-2024-21626](https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv)
- [CVE-2024-23651](https://github.com/moby/buildkit/security/advisories/GHSA-m3r6-h7wv-7xxv)
- [CVE-2024-23652](https://github.com/moby/buildkit/security/advisories/GHSA-4v98-7qmw-rqr8)
- [CVE-2024-23653](https://github.com/moby/buildkit/security/advisories/GHSA-wr6v-9f75-vh2g)
- [CVE-2024-23650](https://github.com/moby/buildkit/security/advisories/GHSA-9p26-698r-w4hx)
- [CVE-2024-24557](https://github.com/moby/moby/security/advisories/GHSA-xw73-rw38-6vjc)

### Packaging updates

- Upgrade containerd to [v1.6.28](https://github.com/containerd/containerd/releases/tag/v1.6.28).
- Upgrade containerd to v1.7.13 (static binaries only). [moby/moby#47280](https://github.com/moby/moby/pull/47280)
- Upgrade runc to v1.1.12. [moby/moby#47269](https://github.com/moby/moby/pull/47269)
- Upgrade Compose to v2.24.5. [docker/docker-ce-packaging#985](https://github.com/docker/docker-ce-packaging/pull/985)
- Upgrade BuildKit to v0.12.5. [moby/moby#47273](https://github.com/moby/moby/pull/47273)

## 25.0.1

{{< release-date date="2024-01-23" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 25.0.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A25.0.1)
- [moby/moby, 25.0.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A25.0.1)

### Bug fixes and enhancements

- API: Fix incorrect HTTP status code for containers with an invalid network configuration created before upgrading to Docker Engine v25.0. [moby/moby#47159](https://github.com/moby/moby/pull/47159)
- Ensure that a MAC address based on a container's IP address is re-generated when the container is stopped and restarted, in case the generated IP/MAC addresses have been reused. [moby/moby#47171](https://github.com/moby/moby/pull/47171)
- Fix `host-gateway-ip` not working during build when not set through configuration. [moby/moby#47192](https://github.com/moby/moby/pull/47192)
- Fix a bug that prevented a container from being renamed twice. [moby/moby#47196](https://github.com/moby/moby/pull/47196)
- Fix an issue causing containers to have their short ID added to their network alias when inspecting them. [moby/moby#47182](https://github.com/moby/moby/pull/47182)
- Fix an issue in detecting whether a remote build context is a Git repository. [moby/moby#47136](https://github.com/moby/moby/pull/47136)
- Fix an issue with layers order in OCI manifests. [moby/moby#47150](https://github.com/moby/moby/issues/47150)
- Fix volume mount error when passing an `addr` or `ip` mount option. [moby/moby#47185](https://github.com/moby/moby/pull/47185)
- Improve error message related to extended attributes that can't be set due to improperly namespaced attribute names. [moby/moby#47178](https://github.com/moby/moby/pull/47178)
- Swarm: Fixed `start_interval` not being passed to the container config. [moby/moby#47163](https://github.com/moby/moby/pull/47163)

### Packaging updates

- Upgrade Compose to `2.24.2`. [docker/docker-ce-packaging#981](https://github.com/docker/docker-ce-packaging/pull/981)

## 25.0.0

{{< release-date date="2024-01-19" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 25.0.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A25.0.0)
- [moby/moby, 25.0.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A25.0.0)

> [!NOTE]
>
> In earlier versions of Docker Engine, recursive mounts (submounts) would
> always be mounted as writable, even when specifying a read-only mount. This
> behavior has changed in v25.0.0, for hosts running on kernel version 5.12 or
> later. Now, read-only bind mounts are **recursively read-only** by default.
>
> To get the same behavior as earlier releases, you can specify the
> `bind-recursive` option for the `--mount` flag.
>
> ```console
> $ docker run --mount type=bind,src=SRC,dst=DST,readonly,bind-recursive=writable IMAGE
> ```
>
> This option isn't supported with the `-v` or `--volume` flag.
> For more information, see
> [Recursive mounts](../storage/bind-mounts.md#recursive-mounts).

### New

- The daemon now uses systemd's default `LimitNOFILE`. In earlier versions of
  Docker Engine, this limit was set to `infinity`. This would cause issues with
  recent versions of systemd, where the hard limit was increased, causing
  programs that adjusted their behaviors based on ulimits to consume a high
  amount of memory. [moby/moby#45534](https://github.com/moby/moby/pull/45534)

  The new setting makes containers behave the same way as programs running on
  the host, but may cause programs that make incorrect assumptions based on the
  soft limit to misbehave. To get the previous behavior, you can set
  `LimitNOFILE=1048576`.

  This change currently only affects build containers created with `docker
  build` when using BuildKit with the `docker` driver. Starting with Docker
  Engine v29.0 (containerd v2.1.5), this limit applies to all containers, not
  only build containers.

  If you're experiencing issues with the higher ulimit in systemd v240 or later,
  consider adding a system `drop-in` or `override` file to configure the ulimit
  settings for your setup. The [Flatcar Container Linux documentation](https://www.flatcar.org/docs/latest/setup/systemd/drop-in-units/)
  has a great article covering this topic in detail.

- Add OpenTelemetry tracing. [moby/moby#45652](https://github.com/moby/moby/pull/45652), [moby/moby#45579](https://github.com/moby/moby/pull/45579)
- Add support for CDI devices under Linux. [moby/moby#45134](https://github.com/moby/moby/pull/45134), [docker/cli#4510](https://github.com/docker/cli/pull/4510), [moby/moby#46004](https://github.com/moby/moby/pull/46004)
- Add an additional interval to be used by healthchecks during the container start period. [moby/moby#40894](https://github.com/moby/moby/pull/40894), [docker/cli#4405](https://github.com/docker/cli/pull/4405), [moby/moby#45965](https://github.com/moby/moby/pull/45965)
- Add a `--log-format` flag to `dockerd` to control the logging format: text (default) or JSON. [moby/moby#45737](https://github.com/moby/moby/pull/45737)
- Add support for recursive read-only mounts. [moby/moby#45278](https://github.com/moby/moby/pull/45278), [moby/moby#46037](https://github.com/moby/moby/pull/46037)
- Add support for filtering images based on timestamp with `docker image ls --filter=until=<timestamp>`. [moby/moby#46577](https://github.com/moby/moby/pull/46577)

### Bug fixes and enhancements

- API: Fix error message for invalid policies at `ValidateRestartPolicy`. [moby/moby#46352](https://github.com/moby/moby/pull/46352)
- API: Update `/info` endpoint to use singleflight. [moby/moby#45847](https://github.com/moby/moby/pull/45847)
- Add an error message for when specifying a Dockerfile filename with `-f`, and also using `stdin`. [docker/cli#4346](https://github.com/docker/cli/pull/4346)
- Add support for `mac-address` and `link-local-ip` fields in `--network` long format. [docker/cli#4419](https://github.com/docker/cli/pull/4419)
- Add support for specifying multiple `--network` flags with `docker container create` and `docker run`. [moby/moby#45906](https://github.com/moby/moby/pull/45906)
- Automatically enable IPv6 on a network when an IPv6 subnet is specified. [moby/moby#46455](https://github.com/moby/moby/pull/46455)
- Add support for overlay networks over IPv6 transport. [moby/moby#46790](https://github.com/moby/moby/pull/46790)
- Configuration reloading is now more robust: if there's an error during the configuration reload process, no configuration changes are applied. [moby/moby#43980](https://github.com/moby/moby/pull/43980)
- Live restore: Containers with auto remove (`docker run --rm`) are no longer forcibly removed on engine restart. [moby/moby#46857](https://github.com/moby/moby/pull/46857)
- Live restore: containers that are live-restored will now be given another health-check start period when the daemon restarts. [moby/moby#47051](https://github.com/moby/moby/pull/47051)
- Container health status is flushed to disk less frequently, reducing wear on flash storage. [moby/moby#47044](https://github.com/moby/moby/pull/47044)
- Ensure network names are unique. [moby/moby#46251](https://github.com/moby/moby/pull/46251)
- Ensure that overlay2 layer metadata is correct. [moby/moby#46471](https://github.com/moby/moby/pull/46471)
- Fix `Downloading` progress message on image pull. [moby/moby#46515](https://github.com/moby/moby/pull/46515)
- Fix `NetworkConnect` and `ContainerCreate` with improved data validation, and return all validation errors at once. [moby/moby#46183](https://github.com/moby/moby/pull/46183)
- Fix `com.docker.network.host_ipv4` option when IPv6 and ip6tables are enabled. [moby/moby#46446](https://github.com/moby/moby/pull/46446)
- Fix daemon's `cleanupContainer` if containerd is stopped. [moby/moby#46213](https://github.com/moby/moby/pull/46213)
- Fix returning incorrect HTTP status codes for libnetwork errors. [moby/moby#46146](https://github.com/moby/moby/pull/46146)
- Fix various issues with images/json API filters and image list. [moby/moby#46034](https://github.com/moby/moby/pull/46034)
- CIFS volumes now resolves FQDN correctly. [moby/moby#46863](https://github.com/moby/moby/pull/46863)
- Improve validation of the `userland-proxy-path` daemon configuration option. Validation now happens during daemon startup, instead of producing an error when starting a container with port-mapping. [moby/moby#47000](https://github.com/moby/moby/pull/47000)
- Set the MAC address of container's interface when network mode is a short network ID. [moby/moby#46406](https://github.com/moby/moby/pull/46406)
- Sort unconsumed build arguments before display in build output. [moby/moby#45917](https://github.com/moby/moby/pull/45917)
- The `docker image save` tarball output is now OCI compliant. [moby/moby#44598](https://github.com/moby/moby/pull/44598)
- The daemon no longer appends `ACCEPT` rules to the end of the `INPUT` iptables chain for encrypted overlay networks. Depending on firewall configuration, a rule may be needed to permit incoming encrypted overlay network traffic. [moby/moby#45280](https://github.com/moby/moby/pull/45280)
- Unpacking layers with extended attributes onto an incompatible filesystem will now fail instead of silently discarding extended attributes. [moby/moby#45464](https://github.com/moby/moby/pull/45464)
- Update daemon MTU option to BridgeConfig and display warning on Windows. [moby/moby#45887](https://github.com/moby/moby/pull/45887)
- Validate IPAM config when creating a network. Automatically fix networks created prior to this release where `--ip-range` is larger than `--subnet`. [moby/moby#45759](https://github.com/moby/moby/pull/45759)
- Containers connected only to internal networks will now have no default route set, making the `connect` syscall fail-fast. [moby/moby#46603](https://github.com/moby/moby/pull/46603)
- containerd image store: Add image events for `push`, `pull`, and `save`. [moby/moby#46405](https://github.com/moby/moby/pull/46405)
- containerd image store: Add support for pulling legacy schema1 images. [moby/moby#46513](https://github.com/moby/moby/pull/46513)
- containerd image store: Add support for pushing all tags. [moby/moby#46485](https://github.com/moby/moby/pull/46485)
- containerd image store: Add support for registry token. [moby/moby#46475](https://github.com/moby/moby/pull/46475)
- containerd image store: Add support for showing the number of containers that use an image. [moby/moby#46511](https://github.com/moby/moby/pull/46511)
- containerd image store: Fix a bug related to the `ONBUILD`, `MAINTAINER`, and `HEALTHCHECK` Dockerfile instructions. [moby/moby#46313](https://github.com/moby/moby/pull/46313)
- containerd image store: Fix `Pulling from` progress message. [moby/moby#46494](https://github.com/moby/moby/pull/46494)
- containerd image store: Add support for referencing images via the truncated ID with `sha256:` prefix. [moby/moby#46435](https://github.com/moby/moby/pull/46435)
- containerd image store: Fix `docker images` showing intermediate layers by default. [moby/moby#46423](https://github.com/moby/moby/pull/46423)
- containerd image store: Fix checking if the specified platform exists when getting an image. [moby/moby#46495](https://github.com/moby/moby/pull/46495)
- containerd image store: Fix errors when multiple `ADD` or `COPY` instructions were used with the classic builder. [moby/moby#46383](https://github.com/moby/moby/pull/46383)
- containerd image store: Fix stack overflow errors when importing an image. [moby/moby#46418](https://github.com/moby/moby/pull/46418)
- containerd image store: Improve `docker pull` progress output. [moby/moby#46412](https://github.com/moby/moby/pull/46412)
- containerd image store: Print the tag, digest, and size after pushing an image. [moby/moby#46384](https://github.com/moby/moby/pull/46384)
- containerd image store: Remove panic from `UpdateConfig`. [moby/moby#46433](https://github.com/moby/moby/pull/46433)
- containerd image store: Return an error when an image tag resembles a digest. [moby/moby#46492](https://github.com/moby/moby/pull/46492)
- containerd image store: `docker image ls` now shows the correct image creation time and date. [moby/moby#46719](https://github.com/moby/moby/pull/46719)
- containerd image store: Fix an issue handling user namespace settings. [moby/moby#46375](https://github.com/moby/moby/pull/46375)
- containerd image store: Add support for pulling all tags (`docker pull -a`). [moby/moby#46618](https://github.com/moby/moby/pull/46618)
- containerd image store: Use the domain name in the image reference as the default registry authentication domain. [moby/moby#46779](https://github.com/moby/moby/pull/46779)

### Packaging updates

- Upgrade API to v1.44. [moby/moby#45468](https://github.com/moby/moby/pull/45468)
- Upgrade Compose to `2.24.1`. [docker/docker-ce-packaging#980](https://github.com/docker/docker-ce-packaging/pull/980)
- Upgrade containerd to v1.7.12 (static binaries only). [moby/moby#47070](https://github.com/moby/moby/pull/47070)
- Upgrade Go runtime to [1.21.6](https://go.dev/doc/devel/release#go1.21.minor). [moby/moby#47053](https://github.com/moby/moby/pull/47053)
- Upgrade runc to v1.1.11. [moby/moby#47007](https://github.com/moby/moby/pull/47007)
- Upgrade BuildKit to v0.12.4. [moby/moby#46882](https://github.com/moby/moby/pull/46882)
- Upgrade Buildx to v0.12.1. [docker/docker-ce-packaging#979](https://github.com/docker/docker-ce-packaging/pull/979)

### Removed

- API: Remove VirtualSize field for the `GET /images/json` and `GET /images/{id}/json` endpoints. [moby/moby#45469](https://github.com/moby/moby/pull/45469)
- Remove deprecated `devicemapper` storage driver. [moby/moby#43637](https://github.com/moby/moby/pull/43637)
- Remove deprecated orchestrator options. [docker/cli#4366](https://github.com/docker/cli/pull/4366)
- Remove support for Debian Upstart init system. [moby/moby#45548](https://github.com/moby/moby/pull/45548), [moby/moby#45551](https://github.com/moby/moby/pull/45551)
- Remove the `--oom-score-adjust` daemon option. [moby/moby#45484](https://github.com/moby/moby/pull/45484)
- Remove warning for deprecated `~/.dockercfg` file. [docker/cli#4281](https://github.com/docker/cli/pull/4281)
- Remove `logentries` logging driver. [moby/moby#46925](https://github.com/moby/moby/pull/46925)

### Deprecated

- Deprecate API versions older than 1.24. [Deprecation notice](../deprecated.md#deprecate-legacy-api-versions)
- Deprecate `IsAutomated` field and `is-automated` filter for `docker search`. [Deprecation notice](../deprecated.md#isautomated-field-and-is-automated-filter-on-docker-search)
- API: Deprecate `Container` and `ContainerConfig` properties for `/images/{id}/json` (`docker image inspect`). [moby/moby#46939](https://github.com/moby/moby/pull/46939)

### Known limitations

#### Extended attributes for tar files

In this release, the code that handles `tar` archives was changed to be more
strict and to produce an error when failing to write extended attributes
(`xattr`). The `tar` implementation for macOS generates additional extended
attributes by default when creating tar files. These attribute prefixes aren't
valid Linux `xattr` namespace prefixes, which causes an error when Docker
attempts to process these files. For example, if you try to use a tar file with
an `ADD` Dockerfile instruction, you might see an error message similar to the
following:

```text
failed to solve: lsetxattr /sftp_key.ppk: operation not supported
```

Error messages related to extended attribute validation were improved to
include more context in [v25.0.1](#2501), but the limitation in Docker being
unable to process the files remains. Tar files created with the macOS `tar`
using default arguments will produce an error when the tar file is used with
Docker.

As a workaround, if you need to use tar files with Docker generated on macOS,
you can either:

- Use the `--no-xattr` flag for the macOS `tar` command to strip **all** the
  extended attributes. If you want to preserve extended attributes, this isn't
  a recommended option.
- Install and use `gnu-tar` to create the tarballs on macOS instead of the
  default `tar` implementation. To install `gnu-tar` using Homebrew:

  ```console
  $ brew install gnu-tar
  ```

  After installing, add the `gnu-tar` binary to your `PATH`, for example by
  updating your `.zshrc` file:

  ```console
  $ echo 'PATH="/opt/homebrew/opt/gnu-tar/libexec/gnubin:$PATH"' >> ~/.zshrc
  $ source ~/.zshrc
  ```


---

# Docker Engine 26.0 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 26.0.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 26.0.2

{{< release-date date="2024-04-18" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.0.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.0.2)
- [moby/moby, 26.0.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.0.2)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.0.2/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.0.2/docs/api/version-history.md).

### Security

This release contains a security fix for [CVE-2024-32473], an unexpected configuration of IPv6 on IPv4-only interfaces.

### Bug fixes and enhancements

- [CVE-2024-32473]: Ensure IPv6 is disabled on interfaces only allocated an IPv4 address by the engine. [moby#GHSA-x84c-p2g9-rqv9](https://github.com/moby/moby/security/advisories/GHSA-x84c-p2g9-rqv9)

  [CVE-2024-32473]: https://github.com/moby/moby/security/advisories/GHSA-x84c-p2g9-rqv9

## 26.0.1

{{< release-date date="2024-04-11" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.0.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.0.1)
- [moby/moby, 26.0.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.0.1)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.0.1/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.0.1/docs/api/version-history.md).

### Bug fixes and enhancements

- Fix a regression that meant network interface specific `--sysctl` options prevented container startup. [moby/moby#47646](https://github.com/moby/moby/pull/47646)
- Remove erroneous `platform` from image `config` OCI descriptor in `docker save` output. [moby/moby#47694](https://github.com/moby/moby/pull/47694)
- containerd image store: OCI archives produced by `docker save` will now have a non-empty `mediaType` field in `index.json` [moby/moby#47701](https://github.com/moby/moby/pull/47701)
- Fix a regression that prevented the internal resolver from forwarding requests from IPvlan L3 networks to external resolvers. [moby/moby#47705](https://github.com/moby/moby/pull/47705)
- Prevent the use of external resolvers in IPvlan and Macvlan networks created with no parent interface specified. [moby/moby#47705](https://github.com/moby/moby/pull/47705)

### Packaging updates

- Update Go runtime to 1.21.9 [moby/moby#47671](https://github.com/moby/moby/pull/47671), [docker/cli#4987](https://github.com/docker/cli/pull/4987)
- Update Compose to [v1.26.1 ](https://github.com/docker/compose/releases/tag/v2.26.1), [docker/docker-ce-packaging#1009](https://github.com/docker/docker-ce-packaging/pull/1009)
- Update containerd to [v1.7.15](https://github.com/containerd/containerd/releases/tag/v1.7.15) (static binaries only) [moby/moby#47692](https://github.com/moby/moby/pull/47692)

## 26.0.0

{{< release-date date="2024-03-20" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.0.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.0.0)
- [moby/moby, 26.0.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.0.0)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.0.0/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.0.0/docs/api/version-history.md).

### Security

This release contains a security fix for [CVE-2024-29018], a potential data exfiltration from 'internal' networks via authoritative DNS servers.

### New

- Add `Subpath` field to the `VolumeOptions` making it possible to mount a subpath of a volume. [moby/moby#45687](https://github.com/moby/moby/pull/45687)
- Add `volume-subpath` support to the mount flag (`--mount type=volume,...,volume-subpath=<subpath>`). [docker/cli#4331](https://github.com/docker/cli/pull/4331)
- Accept `=` separators and `[ipv6]` in compose files for `docker stack deploy`. [docker/cli#4860](https://github.com/docker/cli/pull/4860)
- rootless: Add support for enabling host loopback by setting the `DOCKERD_ROOTLESS_ROOTLESSKIT_DISABLE_HOST_LOOPBACK` environment variable to `false` (defaults to `true`). This lets containers connect to the host by using IP address `10.0.2.2`. [moby/moby#47352](https://github.com/moby/moby/pull/47352)
- containerd image store: `docker image ls` no longer creates duplicates entries for multi-platform images. [moby/moby#45967](https://github.com/moby/moby/pull/45967)
- containerd image store: Send Prometheus metrics. [moby/moby#47555](https://github.com/moby/moby/pull/47555)

### Bug fixes and enhancements

- [CVE-2024-29018]: Do not forward requests to external DNS servers for a container that is only connected to an 'internal' network. Previously, requests were forwarded if the host's DNS server was running on a loopback address, like systemd's 127.0.0.53. [moby/moby#47589](https://github.com/moby/moby/pull/47589)
- Ensure that a generated MAC address is not restored when a container is restarted, but a configured MAC address is preserved. [moby/moby#47233](https://github.com/moby/moby/pull/47233)

  > [!WARNING]
  >
  > Containers created using Docker Engine 25.0.0 may have duplicate MAC addresses, they must be re-created.
  > Containers created using version 25.0.0 or 25.0.1 with user-defined MAC addresses will get generated MAC addresses when they are started using 25.0.2. They must also be re-created.

- Always attempt to enable IPv6 on a container's loopback interface, and only include IPv6 in `/etc/hosts` if successful. [moby/moby#47062](https://github.com/moby/moby/pull/47062)

  > [!NOTE]
  >
  > By default, IPv6 will remain enabled on a container's loopback interface when the container is not connected to an IPv6-enabled network.
  > For example, containers that are only connected to an IPv4-only network now have the `::1` address on their loopback interface.
  >
  > To disable IPv6 in a container,
  > use option `--sysctl net.ipv6.conf.all.disable_ipv6=1` in the `create` or `run` command,
  > or the equivalent `sysctls` option in the service configuration section of a Compose file.
  >
  > If IPv6 is not available in a container because it has been explicitly disabled for the container,
  > or the host's networking stack does not have IPv6 enabled (or for any other reason)
  > the container's `/etc/hosts` file will not include IPv6 entries.

- Fix `ADD` Dockerfile instruction failing with `lsetxattr <file>: operation not supported` when unpacking archive with xattrs onto a filesystem that doesn't support them. [moby/moby#47175](https://github.com/moby/moby/pull/47175)
- Fix `docker container start` failing when used with `--checkpoint`. [moby/moby#47456](https://github.com/moby/moby/pull/47456)
- Restore IP connectivity between the host and containers on an internal bridge network. [moby/moby#47356](https://github.com/moby/moby/pull/47356)
- Do not enforce new validation rules for existing swarm networks. [moby/moby#47361](https://github.com/moby/moby/pull/47361)
- Restore DNS names for containers in the default "nat" network on Windows. [moby/moby#47375](https://github.com/moby/moby/pull/47375)
- Print hint when invoking `docker image ls` with ambiguous argument. [docker/cli#4849](https://github.com/docker/cli/pull/4849)
- Cleanup `@docker_cli_[UUID]` files on OpenBSD. [docker/cli#4862](https://github.com/docker/cli/pull/4862)
- Add explicit [deprecation notice](https://github.com/docker/cli/blob/v26.0.0/docs/deprecated.md#unauthenticated-tcp-connections) message when using remote TCP connections without TLS. [docker/cli#4928](https://github.com/docker/cli/pull/4928), [moby/moby#47556](https://github.com/moby/moby/pull/47556)
- Use IPv6 nameservers from the host's `resolv.conf` as upstream resolvers for Docker Engine's internal DNS, rather than listing them in the container's `resolv.conf`. [moby/moby#47512](https://github.com/moby/moby/pull/47512)
- containerd image store: Isolate images with different containerd namespaces when `--userns-remap` option is used. [moby/moby#46786](https://github.com/moby/moby/pull/46786)
- containerd image store: Fix image pull not emitting `Pulling fs layer` status. [moby/moby#47432](https://github.com/moby/moby/pull/47432)

### API

- To preserve backwards compatibility, read-only mounts are not recursive by default when using older clients (API version < v1.44). [moby/moby#47391](https://github.com/moby/moby/pull/47391)
- `GET /images/{id}/json` omits the `Created` field (previously it was `0001-01-01T00:00:00Z`) if the `Created` field is missing from the image config. [moby/moby#47451](https://github.com/moby/moby/pull/47451)
- Populate a missing `Created` field in `GET /images/{id}/json` with `0001-01-01T00:00:00Z` for API version <= 1.43. [moby/moby#47387](https://github.com/moby/moby/pull/47387)
- The `is_automated` field in the `POST /images/search` endpoint results is always `false` now. Consequently, searching for `is-automated=true` will yield no results, while `is-automated=false` will be a no-op. [moby/moby#47465](https://github.com/moby/moby/pull/47465)
- Remove `Container` and `ContainerConfig` fields from the `GET /images/{name}/json` response. [moby/moby#47430](https://github.com/moby/moby/pull/47430)

### Packaging updates

- Update BuildKit to [v0.13.1](https://github.com/moby/buildkit/releases/tag/v0.13.1). [moby/moby#47582](https://github.com/moby/moby/pull/47582)
- Update Buildx to [v0.13.1](https://github.com/docker/buildx/releases/tag/v0.13.1). [docker/docker-ce-packaging#1000](https://github.com/docker/docker-ce-packaging/pull/1000)
- Update Compose to [v2.25.0](https://github.com/docker/compose/releases/tag/v2.25.0). [docker/docker-ce-packaging#1002](https://github.com/docker/docker-ce-packaging/pull/1002)
- Update Go runtime to [1.21.8](https://go.dev/doc/devel/release#go1.21.8). [moby/moby#47502](https://github.com/moby/moby/pull/47502)
- Update RootlessKit to [v2.0.2](https://github.com/rootless-containers/rootlesskit/releases/tag/v2.0.2).  [moby/moby#47508](https://github.com/moby/moby/pull/47504)
- Update containerd to v1.7.13 (static binaries only) [moby/moby#47278](https://github.com/moby/moby/pull/47278)
- Update runc binary to v1.1.12 [moby/moby#47268](https://github.com/moby/moby/pull/47268)
- Update OTel to v0.46.1 / v1.21.0 [moby/moby#47245](https://github.com/moby/moby/pull/47245)

### Removed

- Remove `Container` and `ContainerConfig` fields from the `GET /images/{name}/json` response. [moby/moby#47430](https://github.com/moby/moby/pull/47430)
- Deprecate the ability to accept remote TCP connections without TLS. [Deprecation notice](https://github.com/docker/cli/tree/v26.0.0/deprecation.md#unauthenticated-tcp-connections) [docker/cli#4928](https://github.com/docker/cli/pull/4928) [moby/moby#47556](https://github.com/moby/moby/pull/47556).
- Remove deprecated API versions (API < v1.24) [moby/moby#47155](https://github.com/moby/moby/pull/47155)
- Disable pulling of deprecated image formats by default. These image formats are deprecated, and support will be removed in a future version. [moby/moby#47459](https://github.com/moby/moby/pull/47459)
- image: remove deprecated IDFromDigest [moby/moby#47198](https://github.com/moby/moby/pull/47198)
- Remove the deprecated `github.com/docker/docker/pkg/loopback` package. [moby/moby#47128](https://github.com/moby/moby/pull/47128)
- pkg/system: remove deprecated `ErrNotSupportedOperatingSystem`, `IsOSSupported` [moby/moby#47129](https://github.com/moby/moby/pull/47129)
- pkg/homedir: remove deprecated Key() and GetShortcutString() [moby/moby#47130](https://github.com/moby/moby/pull/47130)
- pkg/containerfs: remove deprecated ResolveScopedPath [moby/moby#47131](https://github.com/moby/moby/pull/47131)
- The daemon flag `--oom-score-adjust` was deprecated in v24.0 and is now removed. [moby/moby#46113](https://github.com/moby/moby/pull/46113)
- Remove deprecated aliases from the api/types package. These types were deprecated in v25.0.0, which provided temporary aliases. [moby/moby#47148](https://github.com/moby/moby/pull/47148)
  These aliases are now removed: `types.Info`, `types.Commit`, `types.PluginsInfo`, `types.NetworkAddressPool`, `types.Runtime`, `types.SecurityOpt`, `types.KeyValue`, `types.DecodeSecurityOptions`, `types.CheckpointCreateOptions`, `types.CheckpointListOptions`, `types.CheckpointDeleteOptions`, `types.Checkpoint`, `types.ImageDeleteResponseItem`, `types.ImageSummary`, `types.ImageMetadata`, `types.ServiceUpdateResponse`, `types.ServiceCreateResponse`, `types.ResizeOptions`, `types.ContainerAttachOptions`, `types.ContainerCommitOptions`, `types.ContainerRemoveOptions`, `types.ContainerStartOptions`, `types.ContainerListOptions`, `types.ContainerLogsOptions`
- cli/command/container: remove deprecated `NewStartOptions()` [docker/cli#4811](https://github.com/docker/cli/pull/4811)
- cli/command: remove deprecated `DockerCliOption`, `InitializeOpt` [docker/cli#4810](https://github.com/docker/cli/pull/4810)

  [CVE-2024-29018]: https://github.com/moby/moby/security/advisories/GHSA-mq39-4gv4-mvpx


---

# Docker Engine 26.1 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 26.1.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 26.1.4

{{< release-date date="2024-06-05" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.1.4 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.1.4)
- [moby/moby, 26.1.4 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.1.4)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.1.4/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.1.4/docs/api/version-history.md).

### Security

This release updates the Go runtime to 1.21.11 which contains security fixes for:

- [CVE-2024-24789]
- [CVE-2024-24790]
- A symlink time of check to time of use race condition during directory removal reported by [Addison Crump](https://github.com/addisoncrump).

### Bug fixes and enhancements

- Fixed an issue where promoting a node immediately after another node was demoted could cause the promotion to fail. [moby/moby#47870](https://github.com/moby/moby/pull/47870)
- Prevent the daemon log from being spammed with `superfluous response.WriteHeader call ...` messages. [moby/moby#47843](https://github.com/moby/moby/pull/47843)
- Don't show empty hints when plugins return an empty hook message. [docker/cli#5083](https://github.com/docker/cli/pull/5083)
- Fix a compatibility issue with Visual Studio Container Tools. [docker/cli#5095](https://github.com/docker/cli/pull/5095)

### Packaging updates

- Update containerd (static binaries only) to [v1.7.17](https://github.com/containerd/containerd/releases/tag/v1.7.17). [moby/moby#47841](https://github.com/moby/moby/pull/47841)
- [CVE-2024-24789], [CVE-2024-24790]: Update Go runtime to 1.21.11. [moby/moby#47904](https://github.com/moby/moby/pull/47904)
- Update Compose to [v2.27.1](https://github.com/docker/compose/releases/tag/v2.27.1). [docker/docker-ce-packages#1022](https://github.com/docker/docker-ce-packaging/pull/1022)
- Update Buildx to [v0.14.1](https://github.com/docker/buildx/releases/tag/v0.14.1). [docker/docker-ce-packages#1021](https://github.com/docker/docker-ce-packaging/pull/1021)

[CVE-2024-24789]: https://github.com/golang/go/issues/66869
[CVE-2024-24790]: https://github.com/golang/go/issues/67680

## 26.1.3

{{< release-date date="2024-05-16" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.1.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.1.3)
- [moby/moby, 26.1.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.1.3)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.1.3/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.1.3/docs/api/version-history.md).

### Bug fixes and enhancements

- Fix a regression that prevented the use of DNS servers within a `--internal` network. [moby/moby#47832](https://github.com/moby/moby/pull/47832)
- When the internal DNS server's own address is supplied as an external server address, ignore it to avoid unproductive recursion. [moby/moby#47833](https://github.com/moby/moby/pull/47833)

### Packaging updates

- Allow runc to kill containers when confined to the runc profile in AppArmor version 4.0.0 and later. [moby/moby#47829](https://github.com/moby/moby/pull/47829)

## 26.1.2

{{< release-date date="2024-05-08" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.1.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.1.2)
- [moby/moby, 26.1.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.1.2)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.1.2/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.1.2/docs/api/version-history.md).

### Bug fixes and enhancements

- Fix an issue where the CLI process would sometimes hang when a container failed to start. [docker/cli#5062](https://github.com/docker/cli/pull/5062)

### Packaging updates

- Update Go runtime to 1.21.10. [moby/moby#47806](https://github.com/moby/moby/pull/47806)

## 26.1.1

{{< release-date date="2024-04-30" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.1.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.1.1)
- [moby/moby, 26.1.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.1.1)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.1.1/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.1.1/docs/api/version-history.md).

### Bug fixes and enhancements

- Fix `docker run -d` printing an `context canceled` spurious error when OpenTelemetry is configured. [docker/cli#5044](https://github.com/docker/cli/pull/5044)
- Experimental environment variable `DOCKER_BRIDGE_PRESERVE_KERNEL_LL=1` will prevent the daemon from removing the kernel-assigned link local address on a Linux bridge. [moby/moby#47775](https://github.com/moby/moby/pull/47775)
- Resolve an issue preventing container creation on hosts with a read-only `/proc/sys/net` filesystem. If IPv6 cannot be disabled on an interface due to this, either disable IPv6 by default on the host or ensure `/proc/sys/net` is read-write. To bypass the error, set the environment variable `DOCKER_ALLOW_IPV6_ON_IPV4_INTERFACE=1` before starting the Docker daemon. [moby/moby#47769](https://github.com/moby/moby/pull/47769)

> [!NOTE]
>
> The `DOCKER_ALLOW_IPV6_ON_IPV4_INTERFACE` is added as a temporary fix and will be phased out in a future major release, when the IPv6 enablement process has been improved.

### Packaging updates

- Update BuildKit to [v0.13.2](https://github.com/moby/buildkit/releases/tag/v0.13.2). [moby/moby#47762](https://github.com/moby/moby/pull/47762)
- Update Compose to [v2.27.0](https://github.com/docker/compose/releases/tag/v2.27.0). [docker/docker-ce-packages#1017](https://github.com/docker/docker-ce-packaging/pull/1017)


## 26.1.0

{{< release-date date="2024-04-22" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 26.1.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A26.1.0)
- [moby/moby, 26.1.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A26.1.0)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v26.1.0/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v26.1.0/docs/api/version-history.md).

### New

- Added configurable OpenTelemetry utilities and basic instrumentation to commands.
  For more information, see [OpenTelemetry for the Docker CLI](https://docs.docker.com/config/otel). [docker/cli#4889](https://github.com/docker/cli/pull/4889)

### Bug fixes and enhancements

- Native Windows containers are configured with an internal DNS server for container name resolution, and external DNS servers for other lookups.
  Not all resolvers, including `nslookup`, fall back to the external resolvers when they get a `SERVFAIL` answer from the internal server.
  So, the internal DNS server can now be configured to forward requests to the external resolvers, by setting a `feature` option in the `daemon.json` file:

  ```json
  {
    "features": {
      "windows-dns-proxy": true
    }
  }
  ```

  [moby/moby#47584](https://github.com/moby/moby/pull/47584)

  > [!NOTE]
  >
  > - This will be the new default behavior in Docker Engine 27.0.
  > - The `windows-dns-proxy` feature flag will be removed in a future release.

- Swarm: Fix `Subpath` not being passed to the container config. [moby/moby#47711](https://github.com/moby/moby/pull/47711)
- Classic builder: Fix cache miss on `WORKDIR <directory>/` build step (directory with a trailing slash). [moby/moby#47723](https://github.com/moby/moby/pull/47723)
- containerd image store: Fix `docker images` failing when any image in the store has unexpected target. [moby/moby#47738](https://github.com/moby/moby/pull/47738)


---

# Docker Engine version 27 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 27.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 27.5

Release notes for Docker Engine version 27.5 releases.

### 27.5.1

{{< release-date date="2025-01-22" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.5.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.5.1)
- [moby/moby, 27.5.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.5.1)


#### Bug fixes and enhancements

- Fix an issue that could persistently prevent daemon startup after failure to initialize the default bridge. [moby/moby#49307](https://github.com/moby/moby/pull/49307)
- Add a `DOCKER_IGNORE_BR_NETFILTER_ERROR` environment variable. Setting it to `1` allows running on hosts that cannot load `br_netfilter`. Some things won't work, including disabling inter-container communication in a bridge network. With the userland proxy disabled, it won't be possible to access one container's published ports from another container on the same network.  [moby/moby#49306](https://github.com/moby/moby/pull/49306)

#### Packaging updates

- Update Go runtime to 1.22.11 (fix CVE-2024-45341, CVE-2024-45336). [moby/moby#49312](https://github.com/moby/moby/pull/49312), [docker/docker-ce-packaging#1147](https://github.com/docker/docker-ce-packaging/pull/1147), [docker/cli#5762](https://github.com/docker/cli/pull/5762)
- Update RootlessKit to v2.3.2 to support `passt` >= 2024_10_30.ee7d0b6. [moby/moby#49304](https://github.com/moby/moby/pull/49304)
- Update Buildx to [v0.20.0](https://github.com/docker/buildx/releases/tag/v0.20.0). [docker/docker-ce-packaging#1149](https://github.com/docker/docker-ce-packaging/pull/1149)


### 27.5.0

{{< release-date date="2025-01-13" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.5.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.5.0)
- [moby/moby, 27.5.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.5.0)

#### Bugfixes and enhancements

- containerd image store: Fix passing a build context via tarball to the `/build` endpoint. [moby/moby#49194](https://github.com/moby/moby/pull/49194)
- Builder garbage collection policies without a `keepStorage` value now inherit the `defaultKeepStorage` limit as intended. [moby/moby#49137](https://github.com/moby/moby/pull/49137)
- Preserve network labels during daemon startup. [moby/moby#49200](https://github.com/moby/moby/pull/49200)
- Fix a potential race condition error when deleting a container. [moby/moby#49239](https://github.com/moby/moby/pull/49239)

#### Go SDK

- `pkg/sysinfo`: deprecate `NumCPU`. This utility has the same behavior as `runtime.NumCPU`. [moby/moby#49247](https://github.com/moby/moby/pull/49247)
- `pkg/fileutils`: deprecate `GetTotalUsedFds`: this function is only used internally and will be removed in the next release. [moby/moby#49209](https://github.com/moby/moby/pull/49209)
- `pkg/ioutils`: deprecate `BytesPipe`, `NewBytesPipe`, `ErrClosed`, `WriteCounter`, `NewWriteCounter`, `NewReaderErrWrapper`, `NopFlusher`, `NopWriter`, `NopWriteCloser`. They were only used internally and will be removed in the next release. [moby/moby#49246](https://github.com/moby/moby/pull/49246), [moby/moby#49255](https://github.com/moby/moby/pull/49255)
- `pkg/reexec`: This package is deprecated and moved to a separate module. Use `github.com/moby/sys/reexec` instead. [moby/moby#49135](https://github.com/moby/moby/pull/49135)

#### Packaging updates
- Update containerd to [v1.7.25](https://github.com/containerd/containerd/releases/tag/v1.7.25) [moby/moby#49253](https://github.com/moby/moby/pull/49253)
- Update `runc` to [v1.2.4](https://github.com/opencontainers/runc/releases/tag/v1.2.4) [moby/moby#49243](https://github.com/moby/moby/pull/49243)
- Update BuildKit to [v0.18.2](https://github.com/moby/buildkit/releases/tag/v0.18.2) [moby/moby#48949](https://github.com/moby/moby/pull/48949)
- Update Compose to [v2.32.2](https://github.com/docker/compose/releases/tag/v2.32.2) [docker/docker-ce-packaging#1140](https://github.com/docker/docker-ce-packaging/pull/1140)

## 27.4

Release notes for Docker Engine version 27.4 releases.

### 27.4.1

{{< release-date date="2024-12-18" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.4.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.4.1)
- [moby/moby, 27.4.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.4.1)

#### Bug fixes and enhancements

- Fix excessive memory allocations when OTel is not configured. [moby/moby#49079](https://github.com/moby/moby/pull/49079)
- The `docker info` command and the corresponding `GET /info` API endpoint no longer include warnings when `bridge-nf-call-iptables` or `bridge-nf-call-ip6tables` are disabled at the daemon is started. The `br_netfilter` kernel module is now attempted to be loaded when needed, which made those warnings inaccurate. [moby/moby#49090](https://github.com/moby/moby/pull/49090)
- Attempt to load kernel modules, including `ip6_tables` and `br_netfilter` when required, using a method that is likely to succeed inside a Docker-in-Docker container. [moby/moby#49043](https://github.com/moby/moby/pull/49043)
- Fix a bug that could result in an iptables `DOCKER FILTER` chain not being cleaned up on failure. [moby/moby#49110](https://github.com/moby/moby/pull/49110)

#### Packaging updates

- Update Compose to [v2.32.1](https://github.com/docker/compose/releases/tag/v2.32.1). [docker/docker-ce-packaging#1130](https://github.com/docker/docker-ce-packaging/pull/1130)
- Update Buildx to [v0.19.3](https://github.com/docker/buildx/releases/tag/v0.19.3). [docker/docker-ce-packaging#1132](https://github.com/docker/docker-ce-packaging/pull/1132)
- Update runc (static binaries only) to [v1.2.3](https://github.com/opencontainers/runc/releases/tag/v1.2.3) [moby/moby#49085](https://github.com/moby/moby/pull/49085)

### 27.4.0

{{< release-date date="2024-12-09" >}}


For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.4.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.4.0)
- [moby/moby, 27.4.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.4.0)

#### API

- `GET /images/json` with the `manifests` option enabled now preserves the original order in which manifests appeared in the manifest-index. [moby/moby#48712](https://github.com/moby/moby/pull/48712)

#### Bug fixes and enhancements

- When reading logs with the `jsonfile` or `local` log drivers, any errors while trying to read or parse underlying log files will cause the rest of the file to be skipped and move to the next log file (if one exists) rather than returning an error to the client and closing the stream. The errors are viewable in the Docker Daemon logs and exported to traces when tracing is configured. [moby/moby#48842](https://github.com/moby/moby/pull/48842)
- When reading log files, compressed log files are now only decompressed when needed rather than decompressing all files before starting the log stream. [moby/moby#48842](https://github.com/moby/moby/pull/48842)
- Fix an issue that meant published ports from one container on a bridge network were not accessible from another container on the same network with `userland-proxy` disabled, if the kernel's `br_netfilter` module was not loaded and enabled. The daemon will now attempt to load the module and enable `bridge-nf-call-iptables` or `bridge-nf-call-ip6tables` when creating a network with the userland proxy disabled. [moby/moby#48685](https://github.com/moby/moby/pull/48685)
- Fix loading of `bridge` and `br_netfilter` kernel modules. [moby/moby#48966](https://github.com/moby/moby/pull/48966)
- containerd image store: Fix Docker daemon failing to fully start with a "context deadline exceeded error" with containerd snapshotter and many builds/images. [moby/moby#48954](https://github.com/moby/moby/pull/48954)
- containerd image store: Fix partially pulled images not being garbage-collected. [moby#48910](https://github.com/moby/moby/pull/48910), [moby/moby#48957](https://github.com/moby/moby/pull/48957)
- containerd image store: Fix `docker image inspect` outputting duplicate references in `RepoDigests`. [moby/moby#48785](https://github.com/moby/moby/pull/48785)
- containerd image store: Fix not being able to connect to some insecure registries in cases where the HTTPS request failed due to a non-TLS related error. [moby/moby#48758](https://github.com/moby/moby/pull/48758)
- containerd image store: Remove a confusing warning log when tagging a non-dangling image. [moby/moby#49010](https://github.com/moby/moby/pull/49010)
- containerd image store: Do not underline names in `docker image ls --tree`. [docker/cli#5519](https://github.com/docker/cli/pull/5519)
- containerd image store: Change name of `USED` column in `docker image ls --tree` to `IN USE`. [docker/cli#5518](https://github.com/docker/cli/pull/5518)
- `dockerd-rootless-setuptool.sh install --force` now ignores RootlessKit errors [moby/moby#48695](https://github.com/moby/moby/pull/48695)
- Disable IPv6 Duplicate Address Detection (DAD) for addresses assigned to the bridges belonging to bridge networks. [moby/moby#48684](https://github.com/moby/moby/pull/48684)
- Remove BuildKit init timeout. [moby/moby#48963](https://github.com/moby/moby/pull/48963)
- Ignore "dataset does not exist" error when removing dataset on ZFS. [moby/moby#48968](https://github.com/moby/moby/pull/48968)
- Client: Prevent idle connections leaking FDs. [moby/moby#48764](https://github.com/moby/moby/pull/48764)
- Fix anonymous volumes being created through the `--mount` option not being marked as anonymous. [moby/moby#48755](https://github.com/moby/moby/pull/48755)
- After a daemon restart with live-restore, ensure an iptables jump to the `DOCKER-USER` chain is placed before other rules. [moby/moby#48714](https://github.com/moby/moby/pull/48714)
- Fix a possible memory leak caused by OTel meters. [moby/moby#48693](https://github.com/moby/moby/pull/48693)
- Create distinct build history db for each image store. [moby/moby#48688](https://github.com/moby/moby/pull/48688)
- Fix an issue that caused excessive memory usage when DNS resolution was made in a tight loop. [moby/moby#48840](https://github.com/moby/moby/pull/48840)
- Fix a bug preventing image pulls from being cancelled during `docker run`. [docker/cli#5654](https://github.com/docker/cli/pull/5654)
- The `docker login` and `docker logout` command no longer update the configuration file if the credentials didn't change. [docker/cli#5569](https://github.com/docker/cli/pull/5569)
- Optimize `docker stats` to reduce flickering issues. [docker/cli#5588](https://github.com/docker/cli/pull/5588), [docker/cli#5635](https://github.com/docker/cli/pull/5635)
- Fix inaccessible plugins paths preventing plugins from being detected. [docker/cli#5652](https://github.com/docker/cli/pull/5652)
- Add support for `events --filter` in cobra generated shell completions. [docker/cli#5614](https://github.com/docker/cli/pull/5614)
- Fix bash completion for `events --filter daemon=`. [docker/cli#5563](https://github.com/docker/cli/pull/5563)
- Improve shell completion of containers for `docker rm`. [docker/cli#5540](https://github.com/docker/cli/pull/5540)
- Add shell completion for `--platform` flags. [docker/cli#5540](https://github.com/docker/cli/pull/5540)
- rootless: Make `/etc/cdi` and `/var/run/cdi` accessible by the Container Device Interface (CDI) integration. [moby/moby#49027](https://github.com/moby/moby/pull/49027)

#### Removed

- Deprecate `Daemon.Exists()` and `Daemon.IsPaused()`. These functions are no longer used and will be removed in the next release. [moby/moby#48719](https://github.com/moby/moby/pull/48719)
- Deprecate `container.ErrNameReserved` and `container.ErrNameNotReserved`. [moby/moby#48697](https://github.com/moby/moby/pull/48697)
- Deprecate `pkg/platform` - this package is only used internally, and will be removed in the next release. [moby/moby#48863](https://github.com/moby/moby/pull/48863)
- Deprecate `RepositoryInfo.Class`. This field is no longer used, and will be removed in the next release. [moby/moby#49013](https://github.com/moby/moby/pull/49013)
- Go SDK: Fix deprecation of `cli/command.ConfigureAuth()`, which was deprecated since v27.2.1. [docker/cli#5552](https://github.com/docker/cli/pull/5552)
- Go SDK: Deprecate `cli.Errors` type in favour of Go's `errors.Join` [docker/cli#5548](https://github.com/docker/cli/pull/5548)

#### Packaging updates

- Update Go runtime to 1.22.10. [moby/moby#49026](https://github.com/moby/moby/pull/49026), [docker/cli#5669](https://github.com/docker/cli/pull/5669), [docker/docker-ce-packaging#1120](https://github.com/docker/docker-ce-packaging/pull/1120).
- Update Compose to [v2.31.0](https://github.com/docker/compose/releases/tag/v2.31.0). [docker/docker-ce-packaging#1100](https://github.com/docker/docker-ce-packaging/pull/1117)
- Update BuildKit to [v0.17.3](https://github.com/moby/buildkit/releases/tag/v0.17.3). [moby/moby#49024](https://github.com/moby/moby/pull/49024)
- Update Buildx to [v0.19.1](https://github.com/docker/buildx/releases/tag/v0.19.1). [docker/docker-ce-packaging#1115](https://github.com/docker/docker-ce-packaging/pull/1115)
- Update containerd to [v1.7.24](https://github.com/containerd/containerd/releases/tag/v1.7.24). [moby/moby#48934](https://github.com/moby/moby/pull/48934)
- Update containerd (static binaries only) to [v1.7.24](https://github.com/containerd/containerd/releases/tag/v1.7.24). [moby/moby#48919](https://github.com/moby/moby/pull/48919)
- Update runc to [v1.2.2](https://github.com/opencontainers/runc/releases/tag/v1.2.2). [moby/moby#48919](https://github.com/moby/moby/pull/48919)


## 27.3

Release notes for Docker Engine version 27.3 releases.

### 27.3.1

{{< release-date date="2024-09-20" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.3.1 milestone](https://github.com/docker/cli/issues?q=sort%3Aupdated-desc+is%3Aclosed+milestone%3A27.3.1)
- [moby/moby, 27.3.1 milestone](https://github.com/moby/moby/issues?q=sort%3Aupdated-desc+is%3Aclosed+milestone%3A27.3.1)

#### Bug fixes and enhancements

- CLI: Fix issue with command execution metrics not being exported correctly. [docker/cli#5457](https://github.com/docker/cli/pull/5457)

#### Packaging updates

- Update Compose to [v2.29.7](https://github.com/docker/compose/releases/tag/v2.29.7)

### 27.3.0

{{< release-date date="2024-09-19" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.3.0 milestone](https://github.com/docker/cli/issues?q=sort%3Aupdated-desc+is%3Aclosed+milestone%3A27.3.0)
- [moby/moby, 27.3.0 milestone](https://github.com/moby/moby/issues?q=sort%3Aupdated-desc+is%3Aclosed+milestone%3A27.3.0)

#### Bug fixes and enhancements

- containerd image store: Fix `docker image prune -a` untagging images used by containers started from images referenced by a digested reference. [moby/moby#48488](https://github.com/moby/moby/pull/48488)
- Add a `--feature` flag to the daemon options. [moby/moby#48487](https://github.com/moby/moby/pull/48487)
- Updated the handling of the `--gpus=0` flag to be consistent with the NVIDIA Container Runtime. [moby/moby#48483](https://github.com/moby/moby/pull/48483)
- Support WSL2 mirrored-mode networking's use of interface `loopback0` for packets from the Windows host. [moby/moby#48514](https://github.com/moby/moby/pull/48514)
- Fix an issue that prevented communication between containers on an IPv4 bridge network when running with `--iptables=false`, `--ip6tables=true` (the default), a firewall with a DROP rule for forwarded packets on hosts where the `br_netfilter` kernel module was not normally loaded. [moby/moby#48511](https://github.com/moby/moby/pull/48511)
- CLI: Fix issue where `docker volume update` command would cause the CLI to panic if no argument/volume was passed. [docker/cli#5426](https://github.com/docker/cli/pull/5426)
- CLI: Properly report metrics when run in WSL environment on Windows. [docker/cli#5432](https://github.com/docker/cli/pull/5432)

#### Packaging updates

- Update containerd (static binaries only) to [v1.7.22](https://github.com/containerd/containerd/releases/tag/v1.7.22)
[moby/moby#48468](https://github.com/moby/moby/pull/48468)
- Updated Buildkit to [v0.16.0](https://github.com/moby/buildkit/releases/tag/v0.16.0)
- Update Compose to [v2.29.6](https://github.com/docker/compose/releases/tag/v2.29.6)
- Update Buildx to [v0.17.1](https://github.com/docker/buildx/releases/tag/v0.17.1)

## 27.2

Release notes for Docker Engine version 27.2 releases.

### 27.2.1

{{< release-date date="2024-09-09" >}}

#### Bug fixes and enhancements

- containerd image store: Fix non-container images being hidden in the `docker image ls` output. [moby/moby#48402](https://github.com/moby/moby/pull/48402)
- containerd image store: Improve `docker pull` error message when the image platform doesn't match. [moby/moby#48415](https://github.com/moby/moby/pull/48415)
- CLI: Fix issue causing `docker login` to not remove repository names from passed in registry addresses, resulting in credentials being stored under the wrong key. [docker/cli#5385](https://github.com/docker/cli/pull/5385)
- CLI: Fix issue that will sometimes cause the browser-login flow to fail if the CLI process is suspended and then resumed while waiting for the user to authenticate. [docker/cli#5376](https://github.com/docker/cli/pull/5376)
- CLI: `docker login` now returns an error instead of hanging if called non-interactively with `--password` or `--password-stdin` but without `--user`. [docker/cli#5402](https://github.com/docker/cli/pull/5402)

#### Packaging updates

- Update runc to v1.1.14, which contains a fix for [CVE-2024-45310](https://github.com/opencontainers/runc/security/advisories/GHSA-jfvp-7x6p-h2pv). [moby/moby#48426](https://github.com/moby/moby/pull/48426)
- Update Go runtime to 1.22.7. [moby/moby#48433](https://github.com/moby/moby/pull/48433), [docker/cli#5411](https://github.com/docker/cli/pull/5411), [docker/docker-ce-packaging#1068](https://github.com/docker/docker-ce-packaging/pull/1068)

### 27.2.0

{{< release-date date="2024-08-27" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.2.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.2.0)
- [moby/moby, 27.2.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.2.0)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v27.2.0/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v27.2.0/docs/api/version-history.md).

#### New

The new features in this release are:

- [Device code login](#device-code-login)
- [Multi-platform support for `docker image ls`](#multi-platform-support-for-docker-image-ls)

##### Device code login

This release adds support for using device code login when authenticating to
Docker Hub.

You can still use the old method of logging in with a username and password or
access token, but device code login is more secure and doesn't require you to
enter your password in the CLI.

![device-code-login](https://i.imgur.com/GRGjSjV.gif "Device code login")

To use the old method, use `docker login -u <username>`.

##### Multi-platform support for `docker image ls`

{{< experimental >}}
This is experimental and may change at any time without any backward compatibility.
{{< /experimental >}}

With the containerd image store enabled, the `docker image ls` command (or
`docker images` shorthand) now supports a `--tree` flag that now shows
if an image is a multi-platform image.

<script src="https://asciinema.org/a/PyE57rUPdNh7LvOMhULtE0Ek2.js" id="asciicast-PyE57rUPdNh7LvOMhULtE0Ek2" async="true"></script>

#### API

- `GET /images/json` response now includes `Manifests` field, which contains information about the sub-manifests included in the image index. This includes things like platform-specific manifests and build attestations.

  The new field will only be populated if the request also sets the `manifests` query parameter to `true`.

  {{< experimental >}}
  This is experimental and may change at any time without any backward compatibility.
  {{< /experimental >}}

#### Bug fixes and enhancements

- CLI: Fix issue with remote contexts over SSH where the CLI would allocate a pseudo-TTY when connecting to the remote host, which causes issues in rare situations. [docker/cli#5351](https://github.com/docker/cli/pull/5351)
- Fix an issue that prevented network creation with a `--ip-range` ending on a 64-bit boundary. [moby/moby#48326](https://github.com/moby/moby/pull/48326)
- CLI: IPv6 addresses shown by `docker ps` in port bindings are now bracketed. [docker/cli#5365](https://github.com/docker/cli/pull/5365)
- containerd image store: Fix early error exit from `docker load` in cases where unpacking the image would fail. [moby/moby#48376](https://github.com/moby/moby/pull/48376)
- containerd image store: Fix the previous image not being persisted as dangling after `docker pull`. [moby/moby#48380](https://github.com/moby/moby/pull/48380)

#### Packaging updates

- Update BuildKit to [v0.15.2](https://github.com/moby/buildkit/releases/tag/v0.15.2). [moby/moby#48341](https://github.com/moby/moby/pull/48341)
- Update Compose to [v2.29.2](https://github.com/docker/compose/releases/tag/v2.29.2). [docker/docker-ce-packaging#1050](https://github.com/docker/docker-ce-packaging/pull/1050)
- Update containerd to [v1.7.21](https://github.com/containerd/containerd/releases/tag/v1.7.21). [moby/moby#48383](https://github.com/moby/moby/pull/48383), [docker/containerd-packaging#389](https://github.com/docker/containerd-packaging/pull/389)

### Known Issues

- There is a known issue when authenticating against a registry in the Docker CLI (`docker login [registry address]`) where, if the provided registry address includes a repository/image name (such as `docker login index.docker.io/docker/welcome-to-docker`), the repository part (`docker/welcome-to-docker`) is not normalized and results in credentials being stored incorrectly, which causes subsequent pulls from the registry (`docker pull index.docker.io/docker/welcome-to-docker`) to not be authenticated. To prevent this, don't include any extraneous suffix in the registry address when running `docker login`.
  > [!NOTE]
  > Using `docker login` with an address that includes URL path segments is not a documented use case and is considered unsupported. The recommended usage is to specify only a registry hostname, and optionally a port, as the address for `docker login`.

## 27.1

Release notes for Docker Engine version 27.1 releases.

### 27.1.2

{{< release-date date="2024-08-13" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.1.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.1.2)
- [moby/moby, 27.1.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.1.2)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v27.1.2/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v27.1.2/docs/api/version-history.md).


#### Bug fixes and enhancements

- Fix a regression that could result in a `ResourceExhausted desc = grpc: received message larger than max` error when building from a large Dockerfile. [moby/moby#48245](https://github.com/moby/moby/pull/48245)
- CLI: Fix `docker attach` printing a spurious `context cancelled` error message. [docker/cli#5296](https://github.com/docker/cli/pull/5296)
- CLI: Fix `docker attach` exiting on `SIGINT` instead of forwarding the signal to the container and waiting for it to exit. [docker/cli#5302](https://github.com/docker/cli/pull/5302)
- CLI: Fix `--device-read-bps` and `--device-write-bps` options not taking effect. [docker/cli#5339](https://github.com/docker/cli/pull/5339)
- CLI: Fix a panic happening in some cases while running a plugin. [docker/cli#5337](https://github.com/docker/cli/pull/5337)


#### Packaging updates

- Update BuildKit to [v0.15.1](https://github.com/moby/buildkit/releases/tag/v0.15.1). [moby/moby#48246](https://github.com/moby/moby/pull/48246)
- Update Buildx to [v0.16.2](https://github.com/docker/buildx/releases/tag/v0.16.2). [docker/docker-ce-packaging#1043](https://github.com/docker/docker-ce-packaging/pull/1043)
- Update Go runtime to 1.21.13. [moby/moby#48301](https://github.com/moby/moby/pull/48301), [docker/cli#5325](https://github.com/docker/cli/pull/5325), [docker/docker-ce-packaging#1046](https://github.com/docker/docker-ce-packaging/pull/1046)
- Remove unused `docker-proxy.exe` binary from Windows packages. [docker/docker-ce-packaging#1045](https://github.com/docker/docker-ce-packaging/pull/1045)

### 27.1.1

{{< release-date date="2024-07-23" >}}

#### Security

This release contains a fix for [CVE-2024-41110](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-41110) / [GHSA-v23v-6jw2-98fq](https://github.com/moby/moby/security/advisories/GHSA-v23v-6jw2-98fq)
that impacted setups using [authorization plugins (AuthZ)](https://docs.docker.com/engine/extend/plugins_authorization/)
for access control. No other changes are included in this release, and this
release is otherwise identical for users not using AuthZ plugins.

#### Packaging updates

- Update Compose to [v2.29.1](https://github.com/docker/compose/releases/tag/v2.29.1). [moby/docker-ce-packaging#1041](https://github.com/docker/docker-ce-packaging/pull/1041)


### 27.1.0

{{< release-date date="2024-07-22" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.1.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.1.0)
- [moby/moby, 27.1.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.1.0)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v27.1.0/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v27.1.0/docs/api/version-history.md).

#### Bug fixes and enhancements

- rootless: add `Requires=dbus.socket` to prevent errors when starting the daemon on a cgroup v2 host with systemd [moby/moby#48141](https://github.com/moby/moby/pull/48141)
- containerd integration: `image tag` event is now properly emitted when building images with BuildKit [moby/moby#48182](https://github.com/moby/moby/pull/48182)
- CLI: enable shell completion for `docker image rm`, `docker image history`, and `docker image inspect` [moby/moby#5261](https://github.com/moby/moby/pull/5261)
- CLI: add and improve shell completions for various flags [moby/moby#5261](https://github.com/moby/moby/pull/5261)
- CLI: add OOMScoreAdj to `docker service create` and `docker stack` [docker/cli#5274](https://github.com/docker/cli/pull/5274)
- CLI: add support for `DOCKER_CUSTOM_HEADERS` environment variable (experimental) [docker/cli#5271](https://github.com/docker/cli/pull/5271)
- CLI: containerd-integration: Fix `docker push` defaulting the `--platform` flag to a value of `DOCKER_DEFAULT_PLATFORM` environment variable on unsupported API versions [docker/cli#5248](https://github.com/docker/cli/pull/5248)
- CLI: fix: context cancellation on `login` prompt [docker/cli#5260](https://github.com/docker/cli/pull/5260)
- CLI: fix: wait for the container to exit before closing the stream when sending a termination request to the CLI while attached to a container [docker/cli#5250](https://github.com/docker/cli/pull/5250)

#### Deprecated

- The `pkg/rootless/specconv` package is deprecated, and will be removed in the next release [moby/moby#48185](https://github.com/moby/moby/pull/48185)
- The `pkg/containerfs` package is deprecated, and will be removed in the next release [moby/moby#48185](https://github.com/moby/moby/pull/48185)
- The `pkg/directory` package is deprecated, and will be removed in the next release [moby/moby#48185](https://github.com/moby/moby/pull/48185)
- `api/types/system`: remove deprecated `Info.ExecutionDriver` [moby/moby#48184](https://github.com/moby/moby/pull/48184)

#### Packaging updates

- Update Buildx to [v0.16.1](https://github.com/docker/buildx/releases/tag/v0.16.1). [moby/docker-ce-packaging#1039](https://github.com/docker/docker-ce-packaging/pull/1039)
- Update Compose to [v2.29.0](https://github.com/docker/compose/releases/tag/v2.29.0). [moby/docker-ce-packaging#1038](https://github.com/docker/docker-ce-packaging/pull/1038)
- Update Containerd (static binaries only) to [v1.7.20](https://github.com/containerd/containerd/releases/tag/v1.7.20). [moby/moby#48191](https://github.com/moby/moby/pull/48191)
- Update BuildKit to [v0.15.0](https://github.com/moby/buildkit/releases/tag/v0.15.0). [moby/moby#48175](https://github.com/moby/moby/pull/48175)
- Update Go runtime to 1.21.12, which contains security fixes for [CVE-2024-24791](https://github.com/advisories/GHSA-hw49-2p59-3mhj) [moby/moby#48120](https://github.com/moby/moby/pull/48120)

## 27.0

Release notes for Docker Engine 27.0.

### 27.0.3

{{< release-date date="2024-07-01" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.0.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.0.3)
- [moby/moby, 27.0.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.0.3)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v27.0.3/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v27.0.3/docs/api/version-history.md).

#### Bug fixes and enhancements

- Fix a regression that incorrectly reported a port mapping from a host IPv6 address to an IPv4-only container as an error. [moby/moby#48090](https://github.com/moby/moby/pull/48090)
- Fix a regression that caused duplicate subnet allocations when creating networks. [moby/moby#48089](https://github.com/moby/moby/pull/48089)
- Fix a regression resulting in `fail to register layer: failed to Lchown` errors when trying to pull an image with rootless enabled on a system that supports native overlay with user-namespaces. [moby/moby#48086](https://github.com/moby/moby/pull/48086)

### 27.0.2

{{< release-date date="2024-06-27" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.0.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.0.2)
- [moby/moby, 27.0.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.0.2)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v27.0.2/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v27.0.2/docs/api/version-history.md).

#### Bug fixes and enhancements

- Fix a regression that caused port numbers to be ignored when parsing a Docker registry URL. [docker/cli#5197](https://github.com/docker/cli/pull/5197), [docker/cli#5198](https://github.com/docker/cli/pull/5198)

#### Removed

- api/types: deprecate `ContainerJSONBase.Node` field and `ContainerNode` type. These definitions were used by the standalone ("classic") Swarm API, but never implemented in the Docker Engine itself. [moby/moby#48055](https://github.com/moby/moby/pull/48055)


### 27.0.1

{{< release-date date="2024-06-24" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 27.0.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A27.0.0)
- [moby/moby, 27.0.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A27.0.0)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v27.0.1/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v27.0.1/docs/api/version-history.md).

#### New

- containerd image store: Add `--platform` flag to `docker image push` and improve the default behavior when not all platforms of the multi-platform image are available locally. [docker/cli#4984](https://github.com/docker/cli/pull/4984), [moby/moby#47679](https://github.com/moby/moby/pull/47679)
- Add support to `docker stack deploy` for `driver_opts` in a service's networks. [docker/cli#5125](https://github.com/docker/cli/pull/5125)
- Consider additional `/usr/local/libexec` and `/usr/libexec` paths when looking up the userland proxy binaries by a name with a `docker-` prefix. [moby/moby#47804](https://github.com/moby/moby/pull/47804)

#### Bug fixes and enhancements

- `*client.Client` instances are now always safe for concurrent use by multiple goroutines. Previously, this could lead to data races when the `WithAPIVersionNegotiation()` option is used. [moby/moby#47961](https://github.com/moby/moby/pull/47961)
- Fix a bug causing the Docker CLI to leak Unix sockets in `$TMPDIR` in some cases. [docker/cli#5146](https://github.com/docker/cli/pull/5146)
- Don't ignore a custom seccomp profile when used in conjunction with `--privileged`. [moby/moby#47500](https://github.com/moby/moby/pull/47500)
- rootless: overlay2: support native overlay diff when using rootless-mode with Linux kernel version 5.11 and later. [moby/moby#47605](https://github.com/moby/moby/pull/47605)
- Fix the `StartInterval` default value of healthcheck to reflect the documented value of 5s. [moby/moby#47799](https://github.com/moby/moby/pull/47799)
- Fix `docker save` and `docker load` not ending on the daemon side when the operation was cancelled by the user, for example with <kbd>Ctrl+C</kbd>. [moby/moby#47629](https://github.com/moby/moby/pull/47629)
- The `StartedAt` property of containers is now recorded before container startup, guaranteeing that the `StartedAt` is always before `FinishedAt`. [moby/moby#47003](https://github.com/moby/moby/pull/47003)
- The internal DNS resolver used by Windows containers on Windows now forwards requests to external DNS servers by default. This enables `nslookup` to resolve external hostnames. This behaviour can be disabled via `daemon.json`, using `"features": { "windows-dns-proxy": false }`. The configuration option will be removed in a future release. [moby/moby#47826](https://github.com/moby/moby/pull/47826)
- Print a warning when the CLI does not have permissions to read the configuration file. [docker/cli#5077](https://github.com/docker/cli/pull/5077)
- Fix a goroutine and file-descriptor leak on container attach. [moby/moby#45052](https://github.com/moby/moby/pull/45052)
- Clear the networking state of all stopped or dead containers during daemon start-up. [moby/moby#47984](https://github.com/moby/moby/pull/47984)
- Write volume options JSON atomically to avoid "invalid JSON" errors after system crash. [moby/moby#48034](https://github.com/moby/moby/pull/48034)
- Allow multiple macvlan networks with the same parent. [moby/moby#47318](https://github.com/moby/moby/pull/47318)
- Allow BuildKit to be used on Windows daemons that advertise it. [docker/cli#5178](https://github.com/docker/cli/pull/5178)

#### Networking

- Allow sysctls to be set per-interface during container creation and network connection. [moby/moby#47686](https://github.com/moby/moby/pull/47686)
  * In a future release, this will be the only way to set per-interface sysctl options.
    For example, on the command line in a `docker run` command,`--network mynet --sysctl net.ipv4.conf.eth0.log_martians=1` will be rejected.
    Instead, you must use `--network name=mynet,driver-opt=com.docker.network.endpoint.sysctls=net.ipv4.conf.IFNAME.log_martians=1`.

##### IPv6

- `ip6tables` is no longer experimental. You may remove the `experimental` configuration option and continue to use IPv6, if it is not required by any other features.
- `ip6tables` is now enabled for Linux bridge networks by default. [moby/moby#47747](https://github.com/moby/moby/pull/47747)
  - This makes IPv4 and IPv6 behaviors consistent with each other, and reduces the risk that IPv6-enabled containers are inadvertently exposed to the network.
  - There is no impact if you are running Docker Engine with `ip6tables` enabled (new default).
  - If you are using an IPv6-enabled bridge network without `ip6tables`, this is likely a breaking change. Only published container ports (`-p` or `--publish`) are accessible from outside the Docker bridge network, and outgoing connections masquerade as the host.
  - To restore the behavior of earlier releases, no `ip6tables` at all, set `"ip6tables": false` in `daemon.json`, or use the CLI option `--ip6tables=false`. Alternatively, leave `ip6tables` enabled, publish ports, and enable direct routing.
  - With `ip6tables` enabled, if `ip6tables` is not functional on your host, Docker Engine will start but it will not be possible to create an IPv6-enabled network.

##### IPv6 network configuration improvements

- A Unique Local Address (ULA) base prefix is automatically added to `default-address-pools` if this parameter wasn't manually configured, or if it contains no IPv6 prefixes. [moby/moby#47853](https://github.com/moby/moby/pull/47853)
  - Prior to this release, to create an IPv6-enabled network it was necessary to use the `--subnet` option to specify an IPv6 subnet, or add IPv6 ranges to `default-address-pools` in `daemon.json`.
  - Starting in this release, when a bridge network is created with `--ipv6` and no IPv6 subnet is defined by those options, an IPv6 Unique Local Address (ULA) base prefix is used.
  - The ULA prefix is derived from the Engine host ID such that it's unique across hosts and over time.
- IPv6 address pools of any size can now be added to `default-address-pools`. [moby/moby#47768](https://github.com/moby/moby/pull/47768)
- IPv6 can now be enabled by default on all custom bridge networks using `"default-network-opts": { "bridge": {"com.docker.network.enable_ipv6": "true"}}` in `daemon.json`, or `dockerd --default-network-opt=bridge=com.docker.network.enable_ipv6=true`on the command line. [moby/moby#47867](https://github.com/moby/moby/pull/47867)
- Direct routing for IPv6 networks, with `ip6tables` enabled. [moby/moby#47871](https://github.com/moby/moby/pull/47871)
  - Added bridge driver option `com.docker.network.bridge.gateway_mode_ipv6=<nat|routed>`.
  - The default behavior, `nat`, is unchanged from previous releases running with `ip6tables` enabled. NAT and masquerading rules are set up for each published container port.
  - When set to `routed`, no NAT or masquerading rules are configured for published ports. This enables direct IPv6 access to the container, if the host's network can route packets for the container's address to the host. Published ports will be opened in the container's firewall.
  - When a port mapping only applies to `routed` mode, only addresses `0.0.0.0` or `::` are allowed and a host port must not be given.
  - Note that published container ports, in `nat` or `routed` mode, are accessible from any remote address if routing is set up in the network, unless the Docker host's firewall has additional restrictions. For example: `docker network create --ipv6 -o com.docker.network.bridge.gateway_mode_ipv6=routed mynet`.
  - The option `com.docker.network.bridge.gateway_mode_ipv4=<nat|routed>` is also available, with the same behavior but for IPv4.
- If firewalld is running on the host, Docker creates policy `docker-forwarding` to allow forwarding from any zone to the `docker` zone. This makes it possible to configure a bridge network with a routable IPv6 address, and no NAT or masquerading. [moby/moby#47745](https://github.com/moby/moby/pull/47745)
- When a port is published with no host port specified, or a host port range is given, the same port will be allocated for IPv4 and IPv6. [moby/moby#47871](https://github.com/moby/moby/pull/47871)
  - For example `-p 80` will result in the same ephemeral port being allocated for `0.0.0.0` and `::`, and `-p 8080-8083:80` will pick the same port from the range for both address families.
  - Similarly, ports published to specific addresses will be allocated the same port. For example, `-p 127.0.0.1::80 -p '[::1]::80'`.
  - If no port is available on all required addresses, container creation will fail.
- Environment variable `DOCKER_ALLOW_IPV6_ON_IPV4_INTERFACE`, introduced in release 26.1.1, no longer has any effect. [moby/moby#47963](https://github.com/moby/moby/pull/47963)
  - If IPv6 could not be disabled on an interface because of a read-only `/proc/sys/net`, the environment variable allowed the container to start anyway.
  - In this release, if IPv4 cannot be disabled for an interface, IPv6 can be explicitly enabled for the network simply by using `--ipv6` when creating it. Other workarounds are to configure the OS to disable IPv6 by default on new interfaces, mount `/proc/sys/net` read-write, or use a kernel with no IPv6 support.
- For IPv6-enabled bridge networks, do not attempt to replace the bridge's kernel-assigned link local address with `fe80::1`. [moby/moby#47787](https://github.com/moby/moby/pull/47787)

#### Removed

- Deprecate experimental GraphDriver plugins. [moby/moby#48050](https://github.com/moby/moby/pull/48050), [docker/cli#5172](https://github.com/docker/cli/pull/5172)
- pkg/archive: deprecate `NewTempArchive` and `TempArchive`. These types were only used in tests and will be removed in the next release. [moby/moby#48002](https://github.com/moby/moby/pull/48002)
- pkg/archive: deprecate `CanonicalTarNameForPath` [moby/moby#48001](https://github.com/moby/moby/pull/48001)
- Deprecate pkg/dmesg. This package was no longer used, and will be removed in the next release. [moby/moby#47999](https://github.com/moby/moby/pull/47999)
- Deprecate `pkg/stringid.ValidateID` and `pkg/stringid.IsShortID` [moby/moby#47995](https://github.com/moby/moby/pull/47995)
- runconfig: deprecate `SetDefaultNetModeIfBlank` and move `ContainerConfigWrapper` to `api/types/container` [moby/moby#48007](https://github.com/moby/moby/pull/48007)
- runconfig: deprecate `DefaultDaemonNetworkMode` and move to `daemon/network` [moby/moby#48008](https://github.com/moby/moby/pull/48008)
- runconfig: deprecate `opts.ConvertKVStringsToMap`. This utility is no longer used, and will be removed in the next release. [moby/moby#48016](https://github.com/moby/moby/pull/48016)
- runconfig: deprecate `IsPreDefinedNetwork`. [moby/moby#48011](https://github.com/moby/moby/pull/48011)

#### API

- containerd image store: `POST /images/{name}/push` now supports a `platform` parameter (JSON encoded OCI Platform type) that allows selecting a specific platform-manifest from the multi-platform image. This is experimental and may change in future API versions. [moby/moby#47679](https://github.com/moby/moby/pull/47679)
- `POST /services/create` and `POST /services/{id}/update` now support `OomScoreAdj`. [moby/moby#47950](https://github.com/moby/moby/pull/47950)
- `ContainerList` api returns container annotations. [moby/moby#47866](https://github.com/moby/moby/pull/47866)
- `POST /containers/create` and `POST /services/create` now take `Options` as part of `HostConfig.Mounts.TmpfsOptions` allowing to set options for tmpfs mounts. [moby/moby#46809](https://github.com/moby/moby/pull/46809)
- The `Healthcheck.StartInterval` property is now correctly ignored when updating a Swarm service using API versions less than v1.44. [moby/moby#47991](https://github.com/moby/moby/pull/47991)
- `GET /events` now supports image `create` event that is emitted when a new image is built regardless if it was tagged or not.  [moby/moby#47929](https://github.com/moby/moby/pull/47929)
- `GET /info` now includes a `Containerd` field containing information about the location of the containerd API socket and containerd namespaces used by the daemon to run containers and plugins. [moby/moby#47239](https://github.com/moby/moby/pull/47239)
- Deprecate non-standard (config) fields in image inspect output. The `Config` field returned by this endpoint (used for `docker image inspect`) returned additional fields that are not part of the image's configuration and not part of the [Docker Image Spec] and the [OCI Image Spec]. These fields are never set (and always return the default value for the type), but are not omitted in the response when left empty. As these fields were not intended to be part of the image configuration response, they are deprecated, and will be removed in the future API versions.
- Deprecate the daemon flag `--api-cors-header` and the corresponding `daemon.json` configuration option. These will be removed in the next major release. [moby/moby#45313](https://github.com/moby/moby/pull/45313)

The following deprecated fields are currently included in the API response, but are not part of the underlying image's `Config`: [moby/moby#47941](https://github.com/moby/moby/pull/47941)

- `Hostname`
- `Domainname`
- `AttachStdin`
- `AttachStdout`
- `AttachStderr`
- `Tty`
- `OpenStdin`
- `StdinOnce`
- `Image`
- `NetworkDisabled` (already omitted unless set)
- `MacAddress` (already omitted unless set)
- `StopTimeout` (already omitted unless set)

#### Go SDK changes

- Client API callback for the following functions now require a context parameter. [moby/moby#47536](https://github.com/moby/moby/pull/47536)
  - `client.RequestPrivilegeFunc`
  - `client.ImageSearchOptions.AcceptPermissionsFunc`
  - `image.ImportOptions.PrivilegeFunc`
- Remove deprecated aliases for Image types. [moby/moby#47900](https://github.com/moby/moby/pull/47900)
  - `ImageImportOptions`
  - `ImageCreateOptions`
  - `ImagePullOptions`
  - `ImagePushOptions`
  - `ImageListOptions`
  - `ImageRemoveOptions`
- Introduce `Ulimit` type alias for `github.com/docker/go-units.Ulimit`.
  The `Ulimit` type as used in the API is defined in a Go module that will transition to a new location in future.
  A type alias is added to reduce the friction that comes with moving the type to a new location.
  The alias makes sure that existing code continues to work, but its definition may change in future.
  Users are recommended to use this alias instead of the `units.Ulimit` directly. [moby/moby#48023](https://github.com/moby/moby/pull/48023)

Move and rename types, changing their import paths and exported names.
[moby/moby#47936](https://github.com/moby/moby/pull/47936),
[moby/moby#47873](https://github.com/moby/moby/pull/47873),
[moby/moby#47887](https://github.com/moby/moby/pull/47887),
[moby/moby#47882](https://github.com/moby/moby/pull/47882),
[moby/moby#47921](https://github.com/moby/moby/pull/47921),
[moby/moby#48040](https://github.com/moby/moby/pull/48040)

- Move the following types to `api/types/container`:
  - `BlkioStatEntry`
  - `BlkioStats`
  - `CPUStats`
  - `CPUUsage`
  - `ContainerExecInspect`
  - `ContainerPathStat`
  - `ContainerStats`
  - `ContainersPruneReport`
  - `CopyToContainerOptions`
  - `ExecConfig`
  - `ExecStartCheck`
  - `MemoryStats`
  - `NetworkStats`
  - `PidsStats`
  - `StatsJSON`
  - `Stats`
  - `StorageStats`
  - `ThrottlingData`
- Move the following types to `api/types/image`:
  - `ImagesPruneReport`
  - `ImageImportSource`
  - `ImageLoadResponse`
- Move the `ExecStartOptions` type to `api/types/backend`.
- Move the `VolumesPruneReport` type to `api/types/volume`.
- Move the `EventsOptions` type to `api/types/events`.
- Move the `ImageSearchOptions` type to `api/types/registry`. 
- Drop `Network` prefix and move the following types to `api/types/network`:
  - `NetworkCreateResponse`
  - `NetworkConnect`
  - `NetworkDisconnect`
  - `NetworkInspectOptions`
  - `EndpointResource`
  - `NetworkListOptions`
  - `NetworkCreateOptions`
  - `NetworkCreateRequest`
  - `NetworksPruneReport`
- Move `NetworkResource` to `api/types/network`.

#### Packaging updates

- Update Buildx to [v0.15.1](https://github.com/docker/buildx/releases/tag/v0.15.1). [docker/docker-ce-packaging#1029](https://github.com/docker/docker-ce-packaging/pull/1029)
- Update BuildKit to [v0.14.1](https://github.com/moby/buildkit/releases/tag/v0.14.1). [moby/moby#48028](https://github.com/moby/moby/pull/48028)
- Update runc to [v1.1.13](https://github.com/opencontainers/runc/releases/tag/v1.1.13) [moby/moby#47976](https://github.com/moby/moby/pull/47976)
- Update Compose to [v2.28.1](https://github.com/docker/compose/releases/tag/v2.28.1). [moby/docker-ce-packaging#1032](https://github.com/docker/docker-ce-packaging/pull/1032)

[Docker image spec]: https://github.com/moby/docker-image-spec/blob/v1.3.1/specs-go/v1/image.go#L19-L32
[OCI Image Spec]: https://github.com/opencontainers/image-spec/blob/v1.1.0/specs-go/v1/config.go#L24-L62

### 27.0.0

There's no 27.0.0 release due to a mistake during the pre-release of 27.0.0-rc.1 on GitHub which resulted in the v27.0.0 tag being created.
Unfortunately the tag was already picked up by the [Go Module Mirror](https://sum.golang.org) so it's not possible to cleanly change the v27.0.0.
To workaround this, the 27.0.1 will be the first release of the 27.0.


---

# Docker Engine version 28 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 28.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 28.5.2

{{< release-date date="2025-11-05" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.5.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.5.2)
- [moby/moby, 28.5.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.5.2)

> [!CAUTION]
> This release contains fixes for three high-severity security vulnerabilities in runc:
> - [CVE-2025-31133](https://github.com/opencontainers/runc/security/advisories/GHSA-9493-h29p-rfm2)
> - [CVE-2025-52565](https://github.com/opencontainers/runc/security/advisories/GHSA-qw9x-cqr3-wc7r)
> - [CVE-2025-52881](https://github.com/opencontainers/runc/security/advisories/GHSA-cgrx-mc8f-2prm)
> 
> All three vulnerabilities ultimately allow (through different methods) for full container breakouts by bypassing runc's restrictions for writing to arbitrary `/proc` files.

### Bug fixes and enhancements

- dockerd-rootless.sh: if slirp4netns is not installed, try using pasta (passt). [moby/moby#51162](https://github.com/moby/moby/pull/51162)

### Packaging updates

- Update BuildKit to [v0.25.2](https://github.com/moby/buildkit/releases/tag/v0.25.2). [moby/moby#51398](https://github.com/moby/moby/pull/51398)
- Update Go runtime to [1.24.9](https://go.dev/doc/devel/release#go1.24.9). [moby/moby#51387](https://github.com/moby/moby/pull/51387), [docker/cli#6613](https://github.com/docker/cli/pull/6613)
- Update runc to [v1.3.3](https://github.com/opencontainers/runc/releases/tag/v1.3.3). [moby/moby#51394](https://github.com/moby/moby/pull/51394)

### Deprecations

- Go-SDK: cli/command/image/build: deprecate `DefaultDockerfileName`, `DetectArchiveReader`, `WriteTempDockerfile`, `ResolveAndValidateContextPath`. These utilities were only used internally and will be removed in the next release. [docker/cli#6610](https://github.com/docker/cli/pull/6610)
- Go-SDK: cli/command/image/build: deprecate IsArchive utility. [docker/cli#6560](https://github.com/docker/cli/pull/6560)
- Go-SDK: opts: deprecate `ValidateMACAddress`. [docker/cli#6560](https://github.com/docker/cli/pull/6560)
- Go-SDK: opts: deprecate ListOpts.Delete(). [docker/cli#6560](https://github.com/docker/cli/pull/6560)

## 28.5.1

{{< release-date date="2025-10-08" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.5.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.5.1)
- [moby/moby, 28.5.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.5.1)

### Bug fixes and enhancements

- Update BuildKit to v0.25.1. [moby/moby#51137](https://github.com/moby/moby/pull/51137)
- Update Go runtime to [1.24.8](https://go.dev/doc/devel/release#go1.24.8). [moby/moby#51133](https://github.com/moby/moby/pull/51133), [docker/cli#6541](https://github.com/docker/cli/pull/6541)

### Deprecations

- api/types/image: InspectResponse: deprecate `Parent` and `DockerVersion` fields. [moby/moby#51105](https://github.com/moby/moby/pull/51105)
- api/types/plugin: deprecate `Config.DockerVersion` field. [moby/moby#51110](https://github.com/moby/moby/pull/51110)

## 28.5.0

{{< release-date date="2025-10-02" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.5.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.5.0)
- [moby/moby, 28.5.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.5.0)

> [!WARNING]
> **Raspberry Pi OS 32-bit (armhf) Deprecation**
>
> Docker Engine v28 will be the last major version to support Raspberry Pi OS 32-bit (armhf).
> Starting with Docker Engine v29, new major versions will **no longer provide packages** for Raspberry Pi OS 32-bit (armhf).
>
> #### Migration options
> - **64-bit ARM:** Install the Debian `arm64` packages (fully supported).
> - **32-bit ARM (v7):** Install the Debian `armhf` packages (targets ARMv7 CPUs).
>
> **Note:** Older devices based on the ARMv6 architecture are no longer supported by official packages, including:
> - Raspberry Pi 1 (Model A/B/A+/B+)
> - Raspberry Pi Zero and Zero W

### Bug fixes and enhancements

- Don't print warnings in `docker info` for broken symlinks in CLI-plugin directories. [docker/cli#6476](https://github.com/docker/cli/pull/6476)
- Fix a panic during `stats` on empty event `Actor.ID`. [docker/cli#6471](https://github.com/docker/cli/pull/6471)

### Packaging updates

- Remove support for legacy CBC cipher suites. [docker/cli#6474](https://github.com/docker/cli/pull/6474)
- Update Buildkit to [v0.25.0](https://github.com/moby/buildkit/releases/tag/v0.25.0). [moby/moby#51075](https://github.com/moby/moby/pull/51075)
- Update Dockerfile syntax to [v1.19.0](https://github.com/moby/buildkit/releases/tag/dockerfile%2F1.19.0). [moby/moby#51075](https://github.com/moby/moby/pull/51075)

### Networking

- Eliminated harmless warning about deletion of `endpoint_count` from the data store. [moby/moby#51064](https://github.com/moby/moby/pull/51064)
- Fix a bug causing IPAM plugins to not be loaded on Windows. [moby/moby#51035](https://github.com/moby/moby/pull/51035)

### API

- Deprecate support for kernel memory TCP accounting (`KernelMemoryTCP`). [moby/moby#51067](https://github.com/moby/moby/pull/51067)
- Fix `GET containers/{name}/checkpoints` returning `null` instead of empty JSON array when there are no checkpoints. [moby/moby#51052](https://github.com/moby/moby/pull/51052)

### Go SDK

- cli-plugins/plugin: Run: allow customizing the CLI. [docker/cli#6481](https://github.com/docker/cli/pull/6481)
- cli/command: add `WithUserAgent` option. [docker/cli#6477](https://github.com/docker/cli/pull/6477)

### Deprecations

- Go-SDK: cli/command: deprecate `DockerCli.Apply`. This method is no longer used and will be removed in the next release if there are no remaining uses. [docker/cli#6497](https://github.com/docker/cli/pull/6497)
- Go-SDK: cli/command: deprecate `DockerCli.ContentTrustEnabled`. This method is no longer used and will be removed in the next release. [docker/cli#6495](https://github.com/docker/cli/pull/6495)
- Go-SDK: cli/command: deprecate `DockerCli.DefaultVersion`. This method is no longer used and will be removed in the next release. [docker/cli#6491](https://github.com/docker/cli/pull/6491)
- Go-SDK: cli/command: deprecate `ResolveDefaultContext` utility. [docker/cli#6529](https://github.com/docker/cli/pull/6529)
- Go-SDK: cli/command: deprecate `WithContentTrustFromEnv`, `WithContentTrust` options. These options were used internally, and will be removed in the next release.. [docker/cli#6489](https://github.com/docker/cli/pull/6489)
- Go-SDK: cli/manifest/store: deprecate `IsNotFound()`. [docker/cli#6514](https://github.com/docker/cli/pull/6514)
- Go-SDK: templates: deprecate NewParse() function. [docker/cli#6469](https://github.com/docker/cli/pull/6469)

## 28.4.0

{{< release-date date="2025-09-03" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.4.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.4.0)
- [moby/moby, 28.4.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.4.0)

### New

- Allow Docker CLI to set the `GODEBUG` environment variable when the key-value pair (`"GODEBUG":"..."`) exists inside the docker context metadata. [docker/cli#6399](https://github.com/docker/cli/pull/6399)

### Bug fixes and enhancements

- Add shell completion for `docker pull` and `docker image pull`. [docker/cli#6420](https://github.com/docker/cli/pull/6420)
- Fix a regression in v28.3.3 that could cause a panic on `docker push` if the client did not send an `X-Registry-Auth` header. [moby/moby#50738](https://github.com/moby/moby/pull/50738)
- Windows: Potentially fix an issue with "access denied" error when pulling images. [moby/moby#50871](https://github.com/moby/moby/pull/50871)
- containerd image store: Fix `docker history` failing with `snapshot X does not exist` when calling on a non-native image that was built locally. [moby/moby#50875](https://github.com/moby/moby/pull/50875)
- containerd image store: Fix `docker image prune` to emit correct `untag` and `delete` events and list only the deleted images root digests instead of every blob. [moby/moby#50837](https://github.com/moby/moby/pull/50837)
- Remove interactive login prompt from `docker push` and `docker pull` after a failure caused by missing authentication. [docker/cli#6256](https://github.com/docker/cli/pull/6256)

### Packaging updates

- Update BuildKit to [v0.24.0](https://github.com/moby/buildkit/releases/tag/v0.24.0). [moby#50888](https://github.com/moby/moby/pull/50888)
- Update Go runtime to [1.24.7](https://go.dev/doc/devel/release#go1.24.6). [moby/moby#50889](https://github.com/moby/moby/pull/50889), [docker/cli#6422](https://github.com/docker/cli/pull/6422)
- Update `runc` to [v1.3.0](https://github.com/opencontainers/runc/releases/tag/v1.3.0). [moby/moby#50699](https://github.com/moby/moby/pull/50699)
- Update containerd (static binaries only) to [v1.7.28](https://github.com/containerd/containerd/releases/tag/v1.7.28). [moby/moby#50700](https://github.com/moby/moby/pull/50700)

### Networking

- Fix an issue that could cause slow container restart on live-restore. [moby/moby#50829](https://github.com/moby/moby/pull/50829)

### API

- Update deprecation message for `AuthConfig.Email` field. [moby/moby#50797](https://github.com/moby/moby/pull/50797)

### Go SDK

- Deprecate profiles package which got migrated to [github.com/moby/profiles](https://github.com/moby/profiles). [moby/moby#50513](https://github.com/moby/moby/pull/50513)

### Deprecations

- Deprecate special handling for quoted values for the `--tlscacert`, `--tlscert`, and `--tlskey` command-line flags. [docker/cli#6291](https://github.com/docker/cli/pull/6291)
- Mark legacy links environment variables (`DOCKER_KEEP_DEPRECATED_LEGACY_LINKS_ENV_VARS`) as deprecated in v28.4 and set for removal in v30.0. [docker/cli#6309](https://github.com/docker/cli/pull/6309)
- Go-SDK: Deprecate field `NetworkSettingsBase.Bridge`, struct `NetworkSettingsBase`, all the fields of `DefaultNetworkSettings`, and struct `DefaultNetworkSettings`. [moby/moby#50839](https://github.com/moby/moby/pull/50839)
- Go-SDK: api/types: `build.CacheDiskUsage`,  `container.DiskUsage`, `images.DiskUsage` and `volumes.DiskUsage` are now deprecated and will be removed in the next major release. [moby/moby#50768](https://github.com/moby/moby/pull/50768)
- Go-SDK: cli-plugins/manager: deprecate `ReexecEnvvar`. [docker/cli#6411](https://github.com/docker/cli/pull/6411)
- Go-SDK: cli-plugins/manager: deprecate annotation aliases (`CommandAnnotationPlugin`, `CommandAnnotationPluginVendor`, `CommandAnnotationPluginVersion`, `CommandAnnotationPluginInvalid`, `CommandAnnotationPluginCommandPath`) in favor of their equivalent in `cli-plugins/manager/metadata`. [docker/cli#6298](https://github.com/docker/cli/pull/6298)
- Go-SDK: cli-plugins/manager: deprecate metadata aliases (`NamePrefix`, `MetadataSubcommandName`, `HookSubcommandName`, `Metadata`, `ReexecEnvvar`) in favor of their equivalent in `cli-plugins/manager/metadata`. [docker/cli#6269](https://github.com/docker/cli/pull/6269)
- Go-SDK: cli-plugins/manager: remove `Candidate` interface, which was only for internal use. [docker/cli#6269](https://github.com/docker/cli/pull/6269)
- Go-SDK: cli-plugins/manager: remove `NewPluginError` function, which was only for internal use. [docker/cli#6269](https://github.com/docker/cli/pull/6269)
- Go-SDK: cli-plugins/manager: remove deprecated `ResourceAttributesEnvvar` const. [docker/cli#6269](https://github.com/docker/cli/pull/6269)
- Go-SDK: cli/command/builder: deprecate `NewBuilderCommand` and `NewBakeStubCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/builder: deprecate `NewPruneCommand`. [docker/cli#6343](https://github.com/docker/cli/pull/6343)
- Go-SDK: cli/command/checkpoint: deprecate `NewCheckpointCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/checkpoint: deprecate `NewFormat`, `FormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/completion: deprecate `NoComplete`. [docker/cli#6405](https://github.com/docker/cli/pull/6405)
- Go-SDK: cli/command/completion: remove deprecated `ValidArgsFn`. [docker/cli#6259](https://github.com/docker/cli/pull/6259)
- Go-SDK: cli/command/config: deprecate `NewConfigCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/config: deprecate `NewFormat`, `FormatWrite`, `InspectFormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/config: deprecate `RunConfigCreate`,  `CreateOptions`, `RunConfigInspect`, `InspectOptions`, `RunConfigList`, `ListOptions`, `RunConfigRemove`, and `RemoveOptions`. [docker/cli#6369](https://github.com/docker/cli/pull/6369)
- Go-SDK: cli/command/container: deprecate `NewBuildCommand`, `NewPullCommand`, `NewPushCommand`, `NewImagesCommand`, `NewImageCommand`, `NewHistoryCommand`, `NewImportCommand`, `NewLoadCommand`, `NewRemoveCommand`, `NewSaveCommand`, `NewTagCommand`, `NewPruneCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/container: deprecate `NewDiffFormat`, `DiffFormatWrite`. These functions were only used internally and will be removed in the next release. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/container: deprecate `NewRunCommand`, `NewExecCommand`, `NewPsCommand`, `NewContainerCommand`, `NewAttachCommand`, `NewCommitCommand`, `NewCopyCommand`, `NewCreateCommand`, `NewDiffCommand`, `NewExportCommand`, `NewKillCommand`, `NewLogsCommand`, `NewPauseCommand`, `NewPortCommand`, `NewRenameCommand`, `NewRestartCommand`, `NewRmCommand`, `NewStartCommand`, `NewStatsCommand`, `NewStopCommand`, `NewTopCommand`, `NewUnpauseCommand`, `NewUpdateCommand`, `NewWaitCommand`, `NewPruneCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/context: deprecate `NewContextCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/context: deprecate `RunCreate` and `CreateOptions`. [docker/cli#6403](https://github.com/docker/cli/pull/6403)
- Go-SDK: cli/command/context: deprecate `RunExport` and `ExportOptions`. [docker/cli#6403](https://github.com/docker/cli/pull/6403)
- Go-SDK: cli/command/context: deprecate `RunImport`. [docker/cli#6403](https://github.com/docker/cli/pull/6403)
- Go-SDK: cli/command/context: deprecate `RunRemove` and `RemoveOptions`. [docker/cli#6403](https://github.com/docker/cli/pull/6403)
- Go-SDK: cli/command/context: deprecate `RunUpdate` and `UpdateOptions`. [docker/cli#6403](https://github.com/docker/cli/pull/6403)
- Go-SDK: cli/command/context: deprecate `RunUse`. [docker/cli#6403](https://github.com/docker/cli/pull/6403)
- Go-SDK: cli/command/image: deprecate `AuthResolver` utility. [docker/cli#6357](https://github.com/docker/cli/pull/6357)
- Go-SDK: cli/command/image: deprecate `NewHistoryFormat`, `HistoryWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341), [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/manifest: deprecate `NewManifestCommand`. This functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/network: deprecate `NewFormat`, `FormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/network: deprecate `NewNetworkCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/node: deprecate `NewFormat`, `FormatWrite`, `InspectFormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/node: deprecate `NewNodeCommand`. This functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/plugin: deprecate `NewFormat`, `FormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/plugin: deprecate `NewPluginCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/registry: deprecate `NewLoginCommand`, `NewLogoutCommand`, `NewSearchCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/registry: deprecate `NewSearchFormat`, `SearchWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/registry: deprecate `OauthLoginEscapeHatchEnvVar` const. [docker/cli#6413](https://github.com/docker/cli/pull/6413)
- Go-SDK: cli/command/secret: deprecate `NewFormat`, `FormatWrite`, `InspectFormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/secret: deprecate `NewSecretCommand`. This functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/service: deprecate `NewFormat`, `InspectFormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/service: deprecate `NewServiceCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/stack: deprecate `NewStackCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/stack: deprecate `RunList`, `RunServices`. [docker/cli#6391](https://github.com/docker/cli/pull/6391)
- Go-SDK: cli/command/swarm: deprecate `NewSwarmCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/system: deprecate `NewVersionCommand`, `NewInfoCommand`, `NewSystemCommand`, `NewEventsCommand`, `NewInspectCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/task: deprecate `NewTaskFormat`, `FormatWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/trust: deprecate `NewTrustCommand`. This function will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command/trust: deprecate `SignedTagInfo`, `SignerInfo`, `NewTrustTagFormat`, `NewSignerInfoFormat`, `TagWrite`, `SignerInfoWrite`. [docker/cli#6341](https://github.com/docker/cli/pull/6341)
- Go-SDK: cli/command/volume: deprecate `NewVolumeCommand`, `NewPruneCommand`. These functions will be removed in the next release. [docker/cli#6312](https://github.com/docker/cli/pull/6312)
- Go-SDK: cli/command: remove `AddTrustSigningFlags`,  `AddTrustVerificationFlags`, and `AddPlatformFlag` utilities, which were only used internally. [docker/cli#6311](https://github.com/docker/cli/pull/6311)
- Go-SDK: cli/command: remove deprecated `ConfigureAuth` utility. [docker/cli#6257](https://github.com/docker/cli/pull/6257)
- Go-SDK: cli/command: remove deprecated `CopyToFile` utility. [docker/cli#6257](https://github.com/docker/cli/pull/6257)
- Go-SDK: cli/config/types: update deprecation message for `AuthConfig.Email` field. [docker/cli#6392](https://github.com/docker/cli/pull/6392)
- Go-SDK: cli: deprecate `VisitAll`, `DisableFlagsInUseLine` utilities. These utilities were only used internally and will be removed in the next release. [docker/cli#6276](https://github.com/docker/cli/pull/6276)
- Go-SDK: cli: remove `HasCompletionArg` utility. This utility was only used internally. [docker/cli#6276](https://github.com/docker/cli/pull/6276)
- Go-SDK: deprecate `cli/command.RegistryAuthenticationPrivilegedFunc`. [docker/cli#6256](https://github.com/docker/cli/pull/6256)
- Go-SDK: deprecate cli/command/stack/formatter. [docker/cli#6391](https://github.com/docker/cli/pull/6391)
- Go-SDK: deprecate cli/command/stack/loader. [docker/cli#6391](https://github.com/docker/cli/pull/6391)
- Go-SDK: deprecate cli/command/stack/options. [docker/cli#6391](https://github.com/docker/cli/pull/6391)
- Go-SDK: deprecate cli/command/stack/swarm. [docker/cli#6391](https://github.com/docker/cli/pull/6391)
- Go-SDK: opts: deprecate `NewNamedListOptsRef`, `NewNamedMapOpts`, `NamedListOpts`, `NamedMapOpts`, and `NamedOption`. These types and functions are no longer used and will be removed in the next release. [docker/cli#6292](https://github.com/docker/cli/pull/6292)
- Go-SDK: opts: deprecate `ParseEnvFile` in favor of `kvfile.Parse`. [docker/cli#6381](https://github.com/docker/cli/pull/6381)
- Go-SDK: opts: deprecate `QuotedString`. This utility is no longer used, and will be removed in the next release. [docker/cli#6275](https://github.com/docker/cli/pull/6275)
- Go-SDK: opts: deprecate `ValidateHost` utility. This function is no longer used, and will be removed in the next release. [docker/cli#6280](https://github.com/docker/cli/pull/6280)
- Go-SDK: pkg/jsonmessage: deprecate the `JSONMessage.From`, `JSONMessage.Time`, and `JSONMessage.TimeNano` fields, as they are no longer returned by the API for progress messages. Use the `events.Message` type instead to unmarshal the `/events` response. [moby/moby#50762](https://github.com/moby/moby/pull/50762)
- Go-SDK: the cli/registry/client package is deprecated and will be removed in the next release. [docker/cli#6313](https://github.com/docker/cli/pull/6313)

## 28.3.3

{{< release-date date="2025-07-29" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.3.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.3.3)
- [moby/moby, 28.3.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.3.3)

### Security

This release fixes an issue where, after a firewalld reload, published container ports could be accessed directly from the local network, even when they were intended to be accessible only via a loopback address. [CVE-2025-54388](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-54388) /  [GHSA-x4rx-4gw3-53p4](https://github.com/moby/moby/security/advisories/GHSA-x4rx-4gw3-53p4) / [moby/moby#50506](https://github.com/moby/moby/pull/50506).

### Packaging updates

- Update Buildx to [v0.26.1](https://github.com/docker/buildx/releases/tag/v0.26.1). [docker/docker-ce-packaging#1230](https://github.com/docker/docker-ce-packaging/pull/1230)
- Update Compose to [v2.39.1](https://github.com/docker/compose/releases/tag/v2.39.1). [docker/docker-ce-packaging#1234](https://github.com/docker/docker-ce-packaging/pull/1234)
- Update Docker Model CLI plugin to [v0.1.36](https://github.com/docker/model-cli/releases/tag/v0.1.36). [docker/docker-ce-packaging#1233](https://github.com/docker/docker-ce-packaging/pull/1233)

## 28.3.2

{{< release-date date="2025-07-09" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.3.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.3.2)
- [moby/moby, 28.3.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.3.2)

### Bug fixes and enhancements

- Fix `--use-api-socket` not working correctly when targeting a remote daemon. [docker/cli#6157](https://github.com/docker/cli/pull/6157)
- Fix stray "otel error" logs being printed if debug logging is enabled. [docker/cli#6160](https://github.com/docker/cli/pull/6160)
- Quote SSH arguments when connecting to a remote daemon over an SSH connection to avoid unexpected expansion. [docker/cli#6147](https://github.com/docker/cli/pull/6147)
- Warn when `DOCKER_AUTH_CONFIG` is set during `docker login` and `docker logout`. [docker/cli#6163](https://github.com/docker/cli/pull/6163)

### Packaging updates

- Update Compose to [v2.38.2](https://github.com/docker/compose/releases/tag/v2.38.2). [docker/docker-ce-packaging#1225](https://github.com/docker/docker-ce-packaging/pull/1225)
- Update Docker Model CLI plugin to [v0.1.33](https://github.com/docker/model-cli/releases/tag/v0.1.33). [docker/docker-ce-packaging#1227](https://github.com/docker/docker-ce-packaging/pull/1227)
- Update Go runtime to 1.24.5. [moby/moby#50354](https://github.com/moby/moby/pull/50354)

## 28.3.1

{{< release-date date="2025-07-02" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.3.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.3.1)
- [moby/moby, 28.3.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.3.1)

### Packaging updates

- Update BuildKit to [v0.23.2](https://github.com/moby/buildkit/releases/tag/v0.23.2). [moby/moby#50309](https://github.com/moby/moby/pull/50309)
- Update Compose to [v2.38.1](https://github.com/docker/compose/releases/tag/v2.38.1). [docker/docker-ce-packaging#1221](https://github.com/docker/docker-ce-packaging/pull/1221)
- Update Model to v0.1.32 which adds the support for the new top-level `models:` key in Docker Compose. [docker/docker-ce-packaging#1222](https://github.com/docker/docker-ce-packaging/pull/1222)

## 28.3.0

{{< release-date date="2025-06-24" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.3.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.3.0)
- [moby/moby, 28.3.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.3.0)

### New

- Add support for AMD GPUs in `docker run --gpus`. [moby/moby#49952](https://github.com/moby/moby/pull/49952)
- Use `DOCKER_AUTH_CONFIG` as a credential store. [docker/cli#6008](https://github.com/docker/cli/pull/6008)

### Bug fixes and enhancements

- Ensure that the state of the container in the daemon database (used by [/containers/json](https://docs.docker.com/reference/api/engine/version/v1.49/#tag/Container/operation/ContainerList) API) is up to date when the container is stopped using the [/containers/{id}/stop](https://docs.docker.com/reference/api/engine/version/v1.49/#tag/Container/operation/ContainerStop) API (before response of API). [moby/moby#50136](https://github.com/moby/moby/pull/50136)
- Fix `docker image inspect inspect` omitting empty fields. [moby/moby#50135](https://github.com/moby/moby/pull/50135)
- Fix `docker images --tree` not marking images as in-use when the containerd image store is disabled. [docker/cli#6140](https://github.com/docker/cli/pull/6140)
- Fix `docker pull/push` hang in non-interactive when authentication is required caused by prompting for login credentials. [docker/cli#6141](https://github.com/docker/cli/pull/6141)
- Fix a potential resource leak when a node leaves a Swarm. [moby/moby#50115](https://github.com/moby/moby/pull/50115)
- Fix a regression where a login prompt on `docker pull` would show Docker Hub-specific hints when logging in on other registries. [docker/cli#6135](https://github.com/docker/cli/pull/6135)
- Fix an issue where all new tasks in the Swarm could get stuck in the PENDING state forever after scaling up a service with placement preferences. [moby/moby#50211](https://github.com/moby/moby/pull/50211)
- Remove an undocumented, hidden, top-level `docker remove` command that was accidentally introduced in Docker 23.0. [docker/cli#6144](https://github.com/docker/cli/pull/6144)
- Validate registry-mirrors configuration as part of `dockerd --validate` and improve error messages for invalid mirrors. [moby/moby#50240](https://github.com/moby/moby/pull/50240)
- `dockerd-rootless-setuptool.sh`: Fix the script from silently returning with no error message when subuid/subgid system requirements are not satisfied. [moby/moby#50059](https://github.com/moby/moby/pull/50059)
- containerd image store: Fix `docker push` not creating a tag on the remote repository. [moby/moby#50199](https://github.com/moby/moby/pull/50199)
- containerd image store: Improve handling of errors returned by the token server during `docker pull/push`. [moby/moby#50176](https://github.com/moby/moby/pull/50176)

### Packaging updates

- Allow customizing containerd service name for OpenRC. [moby/moby#50156](https://github.com/moby/moby/pull/50156)
- Update BuildKit to [v0.23.1](https://github.com/moby/buildkit/releases/tag/v0.23.1). [moby/moby#50243](https://github.com/moby/moby/pull/50243)
- Update Buildx to [v0.25.0](https://github.com/docker/buildx/releases/tag/v0.25.0). [docker/docker-ce-packaging#1217](https://github.com/docker/docker-ce-packaging/pull/1217)
- Update Compose to [v2.37.2](https://github.com/docker/compose/releases/tag/v2.37.2). [docker/docker-ce-packaging#1219](https://github.com/docker/docker-ce-packaging/pull/1219)
- Update Docker Model CLI plugin to [v0.1.30](https://github.com/docker/model-cli/releases/tag/v0.1.30). [docker/docker-ce-packaging#1218](https://github.com/docker/docker-ce-packaging/pull/1218)
- Update Go runtime to [1.24.4](https://go.dev/doc/devel/release#go1.24.4). [docker/docker-ce-packaging#1213](https://github.com/docker/docker-ce-packaging/pull/1213), [moby/moby#50153](https://github.com/moby/moby/pull/50153), [docker/cli#6124](https://github.com/docker/cli/pull/6124)

### Networking

- Revert Swarm related changes added in 28.2.x builds, due to a regression reported in https://github.com/moby/moby/issues/50129. [moby/moby#50169](https://github.com/moby/moby/pull/50169)
  * Revert: Fix an issue where `docker network inspect --verbose` could sometimes crash the daemon (https://github.com/moby/moby/pull/49937). 
  * Revert: Fix an issue where the load-balancer IP address for an overlay network would not be released in certain cases if the Swarm was lacking an ingress network (https://github.com/moby/moby/pull/49948). 
  * Revert: Improve the reliability of NetworkDB in busy clusters and lossy networks (https://github.com/moby/moby/pull/49932). 
  * Revert: Improvements to the reliability and convergence speed of NetworkDB (https://github.com/moby/moby/pull/49939). 
- Fix an issue that could cause container startup to fail, or lead to failed UDP port mappings, when some container ports are mapped to `0.0.0.0` and others are mapped to specific host addresses. [moby/moby#50054](https://github.com/moby/moby/pull/50054)
- The `network inspect` response for an overlay network now reports that `EnableIPv4` is true. [moby/moby#50147](https://github.com/moby/moby/pull/50147)
- Windows: Improve daemon startup time in cases where the host has networks of type `"Mirrored"`. [moby/moby#50155](https://github.com/moby/moby/pull/50155)
- Windows: Make sure `docker system prune` and `docker network prune` only remove networks created by Docker. [moby/moby#50154](https://github.com/moby/moby/pull/50154)

### API

- Update API version to 1.51. [moby/moby#50145](https://github.com/moby/moby/pull/50145)
- `GET /images/json` now sets the value of the `Containers` field for all images to the count of containers using the image. [moby/moby#50146](https://github.com/moby/moby/pull/50146)

### Deprecations

- Empty/nil image config fields in the `GET /images/{name}/json` response are now deprecated and will be removed in v29.0. [docker/cli#6129](https://github.com/docker/cli/pull/6129)
- api/types/container: deprecate `ExecOptions.Detach`. This field is not used, and will be removed in a future release. [moby/moby#50219](https://github.com/moby/moby/pull/50219)
- pkg/idtools: deprecate `IdentityMapping` and `Identity.Chown`. [moby/moby#50210](https://github.com/moby/moby/pull/50210)

## 28.2.2

{{< release-date date="2025-05-30" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.2.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.2.2)
- [moby/moby, 28.2.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.2.2)

### Bug fixes and enhancements

- containerd image store: Fix a regression causing `docker build --push` to fail. This reverts [the fix](https://github.com/moby/moby/pull/49702) for `docker build` not persisting overridden images as dangling. [moby/moby#50105](https://github.com/moby/moby/pull/50105)

### Networking

- When creating the iptables `DOCKER-USER` chain, do not add an explicit `RETURN` rule, allowing users to append as well as insert their own rules. Existing rules are not removed on upgrade, but it won't be replaced after a reboot. [moby/moby#50098](https://github.com/moby/moby/pull/50098)

## 28.2.1

{{< release-date date="2025-05-29" >}}

### Packaging updates

- Fix packaging regression in [v28.2.0](https://github.com/moby/moby/releases/tag/v28.2.0) which broke creating the `docker` group/user on fresh installations. [docker-ce-packaging#1209](https://github.com/docker/docker-ce-packaging/issues/1209)

## 28.2.0

{{< release-date date="2025-05-28" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.2.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.2.0)
- [moby/moby, 28.2.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.2.0)

> [!NOTE]
> RHEL packages are currently not available and will be released later.

### New

- Add `{{.Platform}}` as formatting option for `docker ps` to show the platform of the image the container is running. [docker/cli#6042](https://github.com/docker/cli/pull/6042)
- Add support for relative parent paths (`../`) on bind mount sources when using `docker run/create` with `-v/--volume` or `--mount type=bind` options. [docker/cli#4966](https://github.com/docker/cli/pull/4966)
- CDI is now enabled by default. [moby/moby#49963](https://github.com/moby/moby/pull/49963)
- Show discovered CDI devices in `docker info`. [docker/cli#6078](https://github.com/docker/cli/pull/6078)
- `docker image rm`: add `--platform` option to remove a variant from multi-platform images. [docker/cli#6109](https://github.com/docker/cli/pull/6109)
- containerd image store: Initial BuildKit support for building Windows container images on Windows (requires an opt-in with `DOCKER_BUILDKIT=1`). [moby/moby#49740](https://github.com/moby/moby/pull/49740)

### Bug fixes and enhancements

- Add a new log option for fluentd log driver (`fluentd-write-timeout`), which enables specifying write timeouts for fluentd connections. [moby/moby#49911](https://github.com/moby/moby/pull/49911)
- Add support for `DOCKER_AUTH_CONFIG` for the experimental `--use-api-socket` option. [docker/cli#6019](https://github.com/docker/cli/pull/6019)
- Fix `docker exec` waiting for 10 seconds if a non-existing user or group was specified. [moby/moby#49868](https://github.com/moby/moby/pull/49868)
- Fix `docker swarm init` ignoring `cacert` option of `--external-ca`. [docker/cli#5995](https://github.com/docker/cli/pull/5995)
- Fix an issue where the CLI would not correctly save the configuration file (`~/.docker/config.json`) if it was a relative symbolic link. [docker/cli#5282](https://github.com/docker/cli/pull/5282)
- Fix containers with `--restart always` policy using CDI devices failing to start on daemon restart. [moby/moby#49990](https://github.com/moby/moby/pull/49990)
- Fix shell-completion to only complete some flags once, even though they can be set multiple times. [docker/cli#6030](https://github.com/docker/cli/pull/6030)
- Fix the `plugin does not implement PluginAddr interface` error for Swarm CSI drivers. [moby/moby#49961](https://github.com/moby/moby/pull/49961)
- Improve `docker login` error messages for invalid options. [docker/cli#6036](https://github.com/docker/cli/pull/6036)
- Make sure the terminal state is restored if the CLI is forcefully terminated. [docker/cli#6058](https://github.com/docker/cli/pull/6058)
- Update the default seccomp profile to match the libseccomp v2.6.0. The new syscalls are: `listmount`, `statmount`, `lsm_get_self_attr`, `lsm_list_modules`, `lsm_set_self_attr`, `mseal`, `uretprobe`, `riscv_hwprobe`, `getxattrat`, `listxattrat`, `removexattrat`, and `setxattrat`. This prevents containers from receiving EPERM errors when using them. [moby/moby#50077](https://github.com/moby/moby/pull/50077)
- `docker inspect`: add shell completion, improve flag-description for `--type` and improve validation. [docker/cli#6052](https://github.com/docker/cli/pull/6052)
- containerd image store: Enable BuildKit garbage collector by default. [moby/moby#49899](https://github.com/moby/moby/pull/49899)
- containerd image store: Fix `docker build` not persisting overridden images as dangling. [moby/moby#49702](https://github.com/moby/moby/pull/49702)
- containerd image store: Fix `docker system df` reporting a negative reclaimable space amount. [moby/moby#49707](https://github.com/moby/moby/pull/49707)
- containerd image store: Fix duplicate `PUT` requests when pushing a multi-platform image. [moby/moby#49949](https://github.com/moby/moby/pull/49949)

### Packaging updates

- Drop Ubuntu 20.04 "Focal" packages as it reached end of life. [docker/docker-ce-packaging#1200](https://github.com/docker/docker-ce-packaging/pull/1200)
- Fix install location for RPM-based `docker-ce` man-pages. [docker/docker-ce-packaging#1203](https://github.com/docker/docker-ce-packaging/pull/1203)
- Update BuildKit to [v0.22.0](https://github.com/moby/buildkit/releases/tag/v0.22.0). [moby/moby#50046](https://github.com/moby/moby/pull/50046)
- Update Buildx to [v0.24.0](https://github.com/docker/buildx/releases/tag/v0.24.0). [docker/docker-ce-packaging#1205](https://github.com/docker/docker-ce-packaging/pull/1205)
- Update Compose to [v2.36.2](https://github.com/docker/compose/releases/tag/v2.36.2). [docker/docker-ce-packaging#1208](https://github.com/docker/docker-ce-packaging/pull/1208)
- Update Go runtime to [1.24.3](https://go.dev/doc/devel/release#go1.24.3). [docker/docker-ce-packaging#1192](https://github.com/docker/docker-ce-packaging/pull/1192), [docker/cli#6060](https://github.com/docker/cli/pull/6060), [moby/moby#49174](https://github.com/moby/moby/pull/49174)

### Networking

- Add bridge network option `"com.docker.network.bridge.trusted_host_interfaces"`, accepting a colon-separated list of interface names. These interfaces have direct access to published ports on container IP addresses. [moby/moby#49832](https://github.com/moby/moby/pull/49832)
- Add daemon option `"allow-direct-routing"` to disable filtering of packets from outside the host addressed directly to containers. [moby/moby#49832](https://github.com/moby/moby/pull/49832)
- Do not display network options `com.docker.network.enable_ipv4` or `com.docker.network.enable_ipv6` in inspect output if they have been overridden by `EnableIPv4` or `EnableIPv6` in the network create request. [moby/moby#49866](https://github.com/moby/moby/pull/49866)
- Fix an issue that could cause network deletion to fail after a daemon restart, with error "has active endpoints" listing empty endpoint names. [moby/moby#49901](https://github.com/moby/moby/pull/49901)
- Fix an issue where `docker network inspect --verbose` could sometimes crash the daemon. [moby/moby#49937](https://github.com/moby/moby/pull/49937)
- Fix an issue where the load-balancer IP address for an overlay network would not be released in certain cases if the Swarm was lacking an ingress network. [moby/moby#49948](https://github.com/moby/moby/pull/49948)
- Improve the reliability of NetworkDB in busy clusters and lossy networks. [moby/moby#49932](https://github.com/moby/moby/pull/49932)
- Improvements to the reliability and convergence speed of NetworkDB. [moby/moby#49939](https://github.com/moby/moby/pull/49939)

### API

- `DELETE /images/{name}` now supports a `platforms` query parameter. It accepts an array of JSON-encoded OCI Platform objects, allowing for selecting a specific platforms to delete content for. [moby/moby#49982](https://github.com/moby/moby/pull/49982)
- `GET /info` now includes a `DiscoveredDevices` field. This is an array of `DeviceInfo` objects, each providing details about a device discovered by a device driver. [moby/moby#49980](https://github.com/moby/moby/pull/49980)

### Go SDK

- `api/types/container`: add `ContainerState` and constants for container state. [moby/moby#49965](https://github.com/moby/moby/pull/49965)
- `api/types/container`: change `Summary.State` to a `ContainerState`. [moby/moby#49991](https://github.com/moby/moby/pull/49991)
- `api/types/container`: define `HealthStatus` type for health-status constants. [moby/moby#49876](https://github.com/moby/moby/pull/49876)
- `api/types`: deprecate `BuildResult`, `ImageBuildOptions`, `ImageBuildOutput`, `ImageBuildResponse`, `BuilderVersion`, `BuilderV1`, and `BuilderBuildKi` which were moved to `api/types/build`. [moby/moby#50025](https://github.com/moby/moby/pull/50025)

### Deprecations

- API: Deprecated: `GET /images/{name}/json` no longer returns the following fields: `Config`, `Hostname`, `Domainname`, `AttachStdin`, `AttachStdout`, `AttachStderr`, `Tty`, `OpenStdin`, `StdinOnce`, `Image`, `NetworkDisabled` (already omitted unless set), `MacAddress` (already omitted unless set), `StopTimeout` (already omitted unless set). These additional fields were included in the response due to an implementation detail but not part of the image's Configuration, were marked deprecated in API v1.46, and are now omitted. [moby/moby#48457](https://github.com/moby/moby/pull/48457)
- Go-SDK: Deprecate builder/remotecontext.Rel(). This function was needed on older versions of Go, but can now be replaced by `filepath.Rel()`. [moby/moby#49843](https://github.com/moby/moby/pull/49843)
- Go-SDK: api/types: deprecate `BuildCachePruneOptions` in favor of `api/types/builder.CachePruneOptions`. [moby/moby#50015](https://github.com/moby/moby/pull/50015)
- Go-SDK: api/types: deprecate `BuildCachePruneReport` in favor of `api/types/builder.CachePruneReport`. [moby/moby#50015](https://github.com/moby/moby/pull/50015)
- Go-SDK: api/types: deprecate `NodeListOptions`, `NodeRemoveOptions`, `ServiceCreateOptions`, `ServiceUpdateOptions`, `RegistryAuthFromSpec`, `RegistryAuthFromPreviousSpec`, `ServiceListOptions`, `ServiceInspectOptions`, and `SwarmUnlockKeyResponse` which were moved to `api/types/swarm`. [moby/moby#50027](https://github.com/moby/moby/pull/50027)
- Go-SDK: api/types: deprecate `SecretCreateResponse`, `SecretListOptions`, `ConfigCreateResponse`, `ConfigListOptions` which were moved to api/types/swarm. [moby/moby#50024](https://github.com/moby/moby/pull/50024)
- Go-SDK: client: deprecate `IsErrNotFound`. [moby/moby#50012](https://github.com/moby/moby/pull/50012)
- Go-SDK: container: deprecate `IsValidHealthString` in favor of `api/types/container.ValidateHealthStatus`. [moby/moby#49893](https://github.com/moby/moby/pull/49893)
- Go-SDK: container: deprecate `StateStatus`, `WaitCondition`, and the related  `WaitConditionNotRunning`, `WaitConditionNextExit`, and `WaitConditionRemoved` consts in favor of their equivalents in `api/types/container`. [moby/moby#49874](https://github.com/moby/moby/pull/49874)
- Go-SDK: opts: deprecate `ListOpts.GetAll` in favor of `ListOpts.GetSlice`. [docker/cli#6032](https://github.com/docker/cli/pull/6032)
- Remove deprecated `IsAutomated` formatting placeholder from `docker search`. [docker/cli#6091](https://github.com/docker/cli/pull/6091)
- Remove fallback for pulling images from non-OCI-compliant `docker.pkg.github.com` registry. [moby/moby#50094](https://github.com/moby/moby/pull/50094)
- Remove support for pulling legacy v2, schema 1 images and remove `DOCKER_ENABLE_DEPRECATED_PULL_SCHEMA_1_IMAGE` environment-variable. [moby/moby#50036](https://github.com/moby/moby/pull/50036), [moby/moby#42300](https://github.com/moby/moby/pull/42300)
- The `BridgeNfIptables` and `BridgeNfIp6tables` fields in the `GET /info` response were deprecated in API v1.48, and are now omitted in API v1.50. [moby/moby#49904](https://github.com/moby/moby/pull/49904)
- errdefs: Deprecate `errdefs.FromStatusCode`. Use containerd's `errhttp.ToNative` instead. [moby/moby#50030](https://github.com/moby/moby/pull/50030)

## 28.1.1

{{< release-date date="2025-04-18" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.1.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.1.1)
- [moby/moby, 28.1.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.1.1)

### Bug fixes and enhancements

- Fix `dockerd-rootless-setuptool.sh` incorrectly reporting missing `iptables`. [moby/moby#49833](https://github.com/moby/moby/pull/49833)
- containerd image store: Fix a potential daemon crash when using `docker load` with archives containing zero-size tar headers. [moby/moby#49837](https://github.com/moby/moby/pull/49837)

### Packaging updates

- Update Buildx to [v0.23.0](https://github.com/docker/buildx/releases/tag/v0.23.0). [docker/docker-ce-packaging#1185](https://github.com/docker/docker-ce-packaging/pull/1185)
- Update Compose to [v2.35.1](https://github.com/docker/compose/releases/tag/v2.35.1). [docker/docker-ce-packaging#1188](https://github.com/docker/docker-ce-packaging/pull/1188)

### Networking

- Add a warning to a container's `/etc/resolv.conf` when no upstream DNS servers were found. [moby/moby#49827](https://github.com/moby/moby/pull/49827)

## 28.1.0

{{< release-date date="2025-04-17" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.1.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.1.0)
- [moby/moby, 28.1.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.1.0)

### New

- Add `docker bake` sub-command as alias for `docker buildx bake`. [docker/cli#5947](https://github.com/docker/cli/pull/5947)
- Experimental: add a new `--use-api-socket` flag on `docker run` and `docker create` to enable access to Docker socket from inside a container and to share credentials from the host with the container. [docker/cli#5858](https://github.com/docker/cli/pull/5858)
- `docker image inspect` now supports a `--platform` flag to inspect a specific platform of a multi-platform image. [docker/cli#5934](https://github.com/docker/cli/pull/5934)

### Bug fixes and enhancements

- Add CLI shell-completion for context names. [docker/cli#6016](https://github.com/docker/cli/pull/6016)
- Fix `docker images --tree` not including non-container images content size in the total image content size. [docker/cli#6000](https://github.com/docker/cli/pull/6000)
- Fix `docker load` not preserving replaced images. [moby/moby#49650](https://github.com/moby/moby/pull/49650)
- Fix `docker login` hints when logging in to a custom registry. [docker/cli#6015](https://github.com/docker/cli/pull/6015)
- Fix `docker stats` not working properly on machines with high CPU core count. [moby/moby#49734](https://github.com/moby/moby/pull/49734)
- Fix a regression causing `docker pull/push` to fail when interacting with a private repository. [docker/cli#5964](https://github.com/docker/cli/pull/5964)
- Fix an issue preventing rootless Docker setup on a host with no `ip_tables` kernel module. [moby/moby#49727](https://github.com/moby/moby/pull/49727)
- Fix an issue that could lead to unwanted iptables rules being restored and never deleted following a firewalld reload. [moby/moby#49728](https://github.com/moby/moby/pull/49728)
- Improve CLI completion of `docker service scale`. [docker/cli#5968](https://github.com/docker/cli/pull/5968)
- `docker images --tree` now hides both untagged and dangling images by default. [docker/cli#5924](https://github.com/docker/cli/pull/5924)
- `docker system info` will provide an exit code if a connection cannot be established to the Docker daemon. [docker/cli#5918](https://github.com/docker/cli/pull/5918)
- containerd image store: Fix `image tag` event not being emitted when building with BuildKit. [moby/moby#49678](https://github.com/moby/moby/pull/49678)
- containerd image store: Improve `docker push/pull` handling of remote registry errors. [moby/moby#49770](https://github.com/moby/moby/pull/49770)
- containerd image store: Show pull progress for non-layer image blobs. [moby/moby#49746](https://github.com/moby/moby/pull/49746)

### Packaging updates

- Add Debian "Trixie" packages. [docker/docker-ce-packaging#1181](https://github.com/docker/docker-ce-packaging/pull/1181)
- Add Fedora 42 packages. [docker/containerd-packaging#418](https://github.com/docker/containerd-packaging/pull/418), [docker/docker-ce-packaging#1169](https://github.com/docker/docker-ce-packaging/pull/1169)
- Add Ubuntu 25.04 "Plucky Puffin" packages. [docker/containerd-packaging#419](https://github.com/docker/containerd-packaging/pull/419), [docker/docker-ce-packaging#1177](https://github.com/docker/docker-ce-packaging/pull/1177)
- Update BuildKit to [v0.21.0](https://github.com/moby/buildkit/releases/tag/v0.21.0). [moby/moby#49809](https://github.com/moby/moby/pull/49809)
- Update Compose to [v2.35.0](https://github.com/docker/compose/releases/tag/v2.35.0). [docker/docker-ce-packaging#1183](https://github.com/docker/docker-ce-packaging/pull/1183)
- Update Go runtime to [1.23.8](https://go.dev/doc/devel/release#go1.23.8). [docker/cli#5986](https://github.com/docker/cli/pull/5986), [docker/docker-ce-packaging#1180](https://github.com/docker/docker-ce-packaging/pull/1180), [moby/moby#49737](https://github.com/moby/moby/pull/49737)

### Networking

- Fix a bug causing host port-mappings on Swarm containers to be duplicated on `docker ps` and `docker inspect`. [moby/moby#49724](https://github.com/moby/moby/pull/49724)
- Fix an issue that caused container network attachment to fail with error "Bridge port not forwarding". [moby/moby#49705](https://github.com/moby/moby/pull/49705)
- Fix an issue with removal of a `--link` from a container in the default bridge network. [moby/moby#49778](https://github.com/moby/moby/pull/49778)
- Improve how network-endpoint relationships are tracked to reduce the chance of the "has active endpoints" error to be wrongfully returned. [moby/moby#49736](https://github.com/moby/moby/pull/49736)
- Improve the "has active endpoints" error message by including the name of endpoints still connected to the network being deleted. [moby/moby#49773](https://github.com/moby/moby/pull/49773)

### API

- Update API version to [v1.49](https://docs.docker.com/engine/api/v1.49/). [moby/moby#49718](https://github.com/moby/moby/pull/49718)
- `GET /image/{name}/json` now supports a `platform` parameter allowing to specify which platform variant of a multi-platform image to inspect. [moby/moby#49586](https://github.com/moby/moby/pull/49586)
- `GET /info` now returns a `FirewallBackend` containing information about the daemon's firewalling configuration. [moby/moby#49761](https://github.com/moby/moby/pull/49761)

### Go SDK

- Update minimum required Go version to go1.23. [docker/cli#5868](https://github.com/docker/cli/pull/5868)
- cli/command/context: remove temporary `ContextType` field from JSON output. [docker/cli#5981](https://github.com/docker/cli/pull/5981)
- client: Keep image references in canonical format where possible. [moby/moby#49609](https://github.com/moby/moby/pull/49609)

### Deprecations

- API: Deprecated `AllowNondistributableArtifactsCIDRs` and `AllowNondistributableArtifactsHostnames` fields in the `RegistryConfig` struct in the `GET /info` response are omitted in API v1.49. [moby/moby#49749](https://github.com/moby/moby/pull/49749)
- API: Deprecated: The `ContainerdCommit.Expected`, `RuncCommit.Expected`, and `InitCommit.Expected` fields in the `GET /info` endpoint were deprecated in API v1.48, and are now omitted in API v1.49. [moby/moby#48556](https://github.com/moby/moby/pull/48556)
- Go-SDK: cli/command/image: Deprecate `RunPull`: this function was only used internally and will be removed in the next release. [docker/cli#5975](https://github.com/docker/cli/pull/5975)
- Go-SDK: cli/config/configfile: deprecate `ConfigFile.Experimental` field. Experimental CLI features are always enabled since version v20.10 and this field is no longer used. Use `ConfigFile.Features` instead for optional features. This field will be removed in a future release. [docker/cli#5977](https://github.com/docker/cli/pull/5977)
- Go-SDK: deprecate `pkg/archive`, which was migrated to `github.com/moby/go-archive`. [moby/moby#49743](https://github.com/moby/moby/pull/49743)
- Go-SDK: deprecate `pkg/atomicwriter`, which was migrated to `github.com/moby/sys/atomicwriter`. [moby/moby#49748](https://github.com/moby/moby/pull/49748)
- Go-SDK: opts: remove deprecated `PortOpt`, `ConfigOpt`, `SecretOpt` aliases. [docker/cli#5953](https://github.com/docker/cli/pull/5953)
- Go-SDK: registry: deprecate `APIEndpoint.Official` field. [moby/moby#49706](https://github.com/moby/moby/pull/49706)

## 28.0.4

{{< release-date date="2025-03-25" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.0.4 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.0.4)
- [moby/moby, 28.0.4 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.0.4)

### Bug fixes and enhancements

- Fix a regression causing `docker pull/push` to fail when interacting with a private repository. [docker/cli#5964](https://github.com/docker/cli/pull/5964)


## 28.0.3

{{< release-date date="2025-03-25" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.0.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.0.3)
- [moby/moby, 28.0.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.0.3)

### Bug fixes and enhancements

- Fix `docker run` truncating the `STDOUT`/`STDERR` prematurely when the container exits before the data is consumed. [docker/cli#5957](https://github.com/docker/cli/pull/5957)

### Packaging updates

- Update BuildKit to [v0.20.2](https://github.com/moby/buildkit/releases/tag/v0.20.2). [moby/moby#49698](https://github.com/moby/moby/pull/49698)
- Update `runc` to [v1.2.6](https://github.com/opencontainers/runc/releases/tag/v1.2.6). [moby/moby#49682](https://github.com/moby/moby/pull/49682)
- Update containerd to [v1.7.26](https://github.com/containerd/containerd/releases/tag/v1.7.26). [docker/containerd-packaging#409](https://github.com/docker/containerd-packaging/pull/409)

## 28.0.2

{{< release-date date="2025-03-19" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.0.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.0.2)
- [moby/moby, 28.0.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.0.2)

### Bug fixes and enhancements

- Fix CLI-specific attributes (`docker.cli.*`) being unintentionally passed to downstream OTel services. [docker/cli#5842](https://github.com/docker/cli/pull/5842)
- Fix an issue where user-specified `OTEL_RESOURCE_ATTRIBUTES` were being overridden by CLI's internal telemetry attributes. The CLI now properly merges user-specified attributes with internal ones, allowing both to coexist. [docker/cli#5842](https://github.com/docker/cli/pull/5842)
- Fix the daemon failing to start on Windows when a container created before v28.0.0 was present. [moby/moby#49626](https://github.com/moby/moby/pull/49626)
- Fix possible error on `docker buildx prune` with `--min-free-space`. [moby/moby#49623](https://github.com/moby/moby/pull/49623)
- Fix spurious `io: read/write on closed pipe` error in the daemon log when closing a container. [moby/moby#49590](https://github.com/moby/moby/pull/49590)
- Fix the Docker daemon failing too early if the containerd socket isn't immediately available. [moby/moby#49603](https://github.com/moby/moby/pull/49603)
- Mask Linux thermal interrupt info in a container's `/proc` and `/sys` by default. [moby/moby#49560](https://github.com/moby/moby/pull/49560)
- Update `contrib/check-config.sh` to check for more kernel modules related to iptables. [moby/moby#49622](https://github.com/moby/moby/pull/49622)
- containerd image store: Fix integer overflow in User ID handling passed via `--user`. [moby/moby#49652](https://github.com/moby/moby/pull/49652)
- containerd image store: Fix spurious `reference for unknown type: application/vnd.in-toto+json` warning being logged to the daemon's log. [moby/moby#49652](https://github.com/moby/moby/pull/49652)
- containerd image store: Improve performance of `docker ps` when running a large number of containers. [moby/moby#49365](https://github.com/moby/moby/pull/49365)

### Packaging updates

- Update BuildKit to [v0.20.1](https://github.com/moby/buildkit/releases/tag/v0.20.1). [moby/moby#49587](https://github.com/moby/moby/pull/49587)
- Update Buildx to [v0.22.0](https://github.com/docker/buildx/releases/tag/v0.22.0). [docker/docker-ce-packaging#1175](https://github.com/docker/docker-ce-packaging/pull/1175)
- Update Compose to [v2.34.0](https://github.com/docker/compose/releases/tag/v2.34.0). [docker/docker-ce-packaging#1172](https://github.com/docker/docker-ce-packaging/pull/1172)
- Update Go runtime to [1.23.7](https://go.dev/doc/devel/release#go1.23.7). [docker/cli#5890](https://github.com/docker/cli/pull/5890), [docker/docker-ce-packaging#1171](https://github.com/docker/docker-ce-packaging/pull/1171), [moby/moby#49580](https://github.com/moby/moby/pull/49580)
- Update RootlessKit to [v2.3.4](https://github.com/rootless-containers/rootlesskit/releases/tag/v2.3.4). [moby/moby#49614](https://github.com/moby/moby/pull/49614)
- Update containerd (static binaries only) to [v1.7.27](https://www.github.com/containerd/containerd/releases/tag/v1.7.27). [moby/moby#49656](https://github.com/moby/moby/pull/49656)

### Networking

- Add the environment variable `DOCKER_INSECURE_NO_IPTABLES_RAW=1` to allow Docker to run on systems where the Linux kernel can't provide `CONFIG_IP_NF_RAW` support. When enabled, Docker will not create rules in the iptables `raw` table. Warning: This is not recommended for production environments as it reduces security by allowing other hosts on the local network to route to ports published to host addresses, even when they are published to `127.0.0.1.` This option bypasses some of the security hardening introduced in Docker Engine 28.0.0. [moby/moby#49621](https://github.com/moby/moby/pull/49621)
- Allow container startup when an endpoint is attached to a macvlan network driver where the parent interface is down. [moby/moby#49630](https://github.com/moby/moby/pull/49630)
- Do not skip DNAT for packets originating in a `gateway_mode=routed` network. [moby/moby#49577](https://github.com/moby/moby/pull/49577)
- Fix a bug causing `docker ps` to inconsistently report dual-stack port mappings. [moby/moby#49657](https://github.com/moby/moby/pull/49657)
- Fix a bug that could cause `docker-proxy` to stop forwarding UDP datagrams to containers. [moby/moby#49649](https://github.com/moby/moby/pull/49649)
- Fix a bug that was causing `docker-proxy` to close UDP connections to containers eagerly and resulting in the source address to change needlessly. [moby/moby#49649](https://github.com/moby/moby/pull/49649)

### Go SDK

- Move various types and consts from `cli-plugins/manager` to a separate package. [docker/cli#5902](https://github.com/docker/cli/pull/5902)
- Update minimum required Go version to go1.23. [moby/moby#49541](https://github.com/moby/moby/pull/49541)
- `cli/command`: Move `PrettyPrint` utility to `cli/command/formatter`. [docker/cli#5916](https://github.com/docker/cli/pull/5916)
- runconfig/errors: split `ErrConflictHostNetwork` into `ErrConflictConnectToHostNetwork` and `ErrConflictDisconnectFromHostNetwork`. [moby/moby#49605](https://github.com/moby/moby/pull/49605)

### Deprecations

- Go-SDK: Deprecate `cli-plugins/manager.ResourceAttributesEnvvar` constant. It was used internally, but holds the `OTEL_RESOURCE_ATTRIBUTES` name, which is part of the OpenTelemetry specification. Users of this constant should define their own. It will be removed in the next release. [docker/cli#5881](https://github.com/docker/cli/pull/5881)
- Go-SDK: Deprecate `opts.PortOpt`, `opts.ConfigOpt` and `opts.SecretOpt`. These types were moved to the `opts/swarmopts` package. [docker/cli#5907](https://github.com/docker/cli/pull/5907)
- Go-SDK: Remove `service/logs` package. [docker/cli#5910](https://github.com/docker/cli/pull/5910)
- Go-SDK: `cli/command/image`: Deprecate `PushTrustedReference` and move to `cli/trust`. [docker/cli#5894](https://github.com/docker/cli/pull/5894)
- Go-SDK: `cli/command/image`: Deprecate and internalize `TrustedPush`. [docker/cli#5894](https://github.com/docker/cli/pull/5894)
- Go-SDK: `cli/command`: deprecate `Cli.NotaryClient`: use [`trust.GetNotaryRepository`](https://pkg.go.dev/github.com/docker/cli@v28.0.1+incompatible/cli/trust#GetNotaryRepository) instead. This method is no longer used and will be removed in the next release. [docker/cli#5885](https://github.com/docker/cli/pull/5885)
- Go-SDK: `cli/command`: deprecate `Cli.RegistryClient`. This method was only used internally and will be removed in the next release. Use [`client.NewRegistryClient`](https://pkg.go.dev/github.com/docker/cli@v28.0.1+incompatible/cli/registry/client#NewRegistryClient) instead. [docker/cli#5889](https://github.com/docker/cli/pull/5889), [docker/cli#5889](https://github.com/docker/cli/pull/5889)
- Go-SDK: `registry`: Deprecate `RepositoryInfo.Official` field. [moby/moby#49567](https://github.com/moby/moby/pull/49567)
- Go-SDK: `registry`: deprecate `HostCertsDir`: this function was only used internally and will be removed in the next release. [moby/moby#49612](https://github.com/moby/moby/pull/49612)
- Go-SDK: `registry`: deprecate `SetCertsDir`: the cert-directory is now automatically selected when running with RootlessKit, and should no longer be set manually. [moby/moby#49612](https://github.com/moby/moby/pull/49612)

## 28.0.1

{{< release-date date="2025-02-26" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.0.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.0.1)
- [moby/moby, 28.0.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.0.1)

### Networking

- Remove dependency on kernel modules `ip_set`, `ip_set_hash_net` and `netfilter_xt_set`.
  * The dependency was introduced in release 28.0.0 but proved too disruptive. The iptables rules using these modules have been replaced. [moby/moby#49530](https://github.com/moby/moby/pull/49530)
- Allow daemon startup on a host with IPv6 disabled without requiring `--ip6tables=false`. [moby/moby#49525](https://github.com/moby/moby/pull/49525)
- Fix a bug that was causing containers with `--restart=always` and a published port already in use to restart in a tight loop. [moby/moby#49507](https://github.com/moby/moby/pull/49507)
- Fix an issue with Swarm ingress, caused by incorrect ordering of iptables rules. [moby/moby#49538](https://github.com/moby/moby/pull/49538)
- Fix creation of a swarm-scoped network from a `--config-only` network. [moby/moby#49521](https://github.com/moby/moby/pull/49521)
- Fix `docker network inspect` reporting an IPv6 gateway with CIDR suffix for a newly created network with no specific IPAM config, until a daemon restart. [moby/moby#49520](https://github.com/moby/moby/pull/49520)
- Improve the error reported when kernel modules `ip_set`, `ip_set_hash_net` and `netilter_xt_set` are not available. [moby/moby#49524](https://github.com/moby/moby/pull/49524)
- Move most of Docker's iptables rules out of the filter-FORWARD chain, so that other applications are free to append rules that must follow Docker's rules. [moby/moby#49518](https://github.com/moby/moby/pull/49518)
- Update `--help` output and man page lo state which options only apply to the default bridge network. [moby/moby#49522](https://github.com/moby/moby/pull/49522)


### Bug fixes and enhancements

- Fix `docker context create` always returning an error when using the `"skip-tls-verify"` option. [docker/cli#5850](https://github.com/docker/cli/pull/5850)
- Fix shell completion suggesting IDs instead of names for services and nodes. [docker/cli#5848](https://github.com/docker/cli/pull/5848)
- Fix unintentionally printing exit status to standard error output when `docker exec/run` returns a non-zero status. [docker/cli#5854](https://github.com/docker/cli/pull/5854)
- Fix regression `protocol "tcp" is not supported by the RootlessKit port driver "slirp4netns"`. [moby/moby#49514](https://github.com/moby/moby/pull/49514)
- containerd image store: Fix `docker inspect` not being able to show multi-platform images with missing layers for all platforms. [moby/moby#49533](https://github.com/moby/moby/pull/49533)
- containerd image store: Fix `docker images --tree` reporting wrong content size. [moby/moby#49535](https://github.com/moby/moby/pull/49535)
- Fix compilation on i386 [moby/moby#49526](https://github.com/moby/moby/pull/49526)

### Packaging updates

- Update `github.com/go-jose/go-jose/v4` to v4.0.5 to address [GHSA-c6gw-w398-hv78](https://github.com/go-jose/go-jose/security/advisories/GHSA-c6gw-w398-hv78) / [CVE-2025-27144](https://www.cve.org/CVERecord?id=CVE-2025-27144). [docker/cli#5867](https://github.com/docker/cli/pull/5867)
- Update Buildx to [v0.21.1](https://github.com/docker/buildx/releases/tag/v0.21.1). [docker/docker-ce-packaging#1167](https://github.com/docker/docker-ce-packaging/pull/1167)
- Update Compose to [v2.33.1](https://github.com/docker/compose/releases/tag/v2.33.1). [docker/docker-ce-packaging#1168](https://github.com/docker/docker-ce-packaging/pull/1168)

### API

- containerd image store: Fix `GET /images/json?manifests=1` not filling `Manifests` for index-only images [moby/moby#49533](https://github.com/moby/moby/pull/49533)
- containerd image store: Fix `GET /images/json and /images/<name>/json` `Size.Content` field including the size of content that's not available locally [moby/moby#49535](https://github.com/moby/moby/pull/49535)


## 28.0.0

{{< release-date date="2025-02-19" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 28.0.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A28.0.0)
- [moby/moby, 28.0.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A28.0.0)
- Deprecated and removed features, see [Deprecated Features](https://github.com/docker/cli/blob/v28.0.0/docs/deprecated.md).
- Changes to the Engine API, see [API version history](https://github.com/moby/moby/blob/v28.0.0/docs/api/version-history.md).

### New

- Add ability to mount an image inside a container via `--mount type=image`. [moby/moby#48798](https://github.com/moby/moby/pull/48798)
  * You can also specify `--mount type=image,image-subpath=[subpath],...` option to mount a specific path from the image. [docker/cli#5755](https://github.com/docker/cli/pull/5755)
- `docker images --tree` now shows metadata badges [docker/cli#5744](https://github.com/docker/cli/pull/5744)
- `docker load`, `docker save`, and `docker history` now support a `--platform` flag allowing you to choose a specific platform for single-platform operations on multi-platform images. [docker/cli#5331](https://github.com/docker/cli/pull/5331)
- Add `OOMScoreAdj` to `docker service create` and `docker stack`. [docker/cli#5145](https://github.com/docker/cli/pull/5145)
- `docker buildx prune` now supports `reserved-space`, `max-used-space`, `min-free-space` and `keep-bytes` filters. [moby/moby#48720](https://github.com/moby/moby/pull/48720)
- Windows: Add support for running containerd as a child process of the daemon, instead of using a system-installed containerd. [moby/moby#47955](https://github.com/moby/moby/pull/47955)


### Networking

- The `docker-proxy` binary has been updated, older versions will not work with the updated `dockerd`. [moby/moby#48132](https://github.com/moby/moby/pull/48132)
    - Close a window in which the userland proxy (`docker-proxy`) could accept TCP connections, that would then fail after `iptables` NAT rules were set up.
    - The executable `rootlesskit-docker-proxy` is no longer used, it has been removed from the build and distribution.
- DNS nameservers read from the host's `/etc/resolv.conf` are now always accessed from the host's network namespace. [moby/moby#48290](https://github.com/moby/moby/pull/48290)
    - When the host's `/etc/resolv.conf` contains no nameservers and there are no `--dns` overrides, Google's DNS servers are no longer used, apart from by the default bridge network and in build containers.
- Container interfaces in bridge and macvlan networks now use randomly generated MAC addresses. [moby/moby#48808](https://github.com/moby/moby/pull/48808)
    - Gratuitous ARP / Neighbour Advertisement messages will be sent when the interfaces are started so that, when IP addresses are reused, they're associated with the newly generated MAC address.
    - IPv6 addresses in the default bridge network are now IPAM-assigned, rather than being derived from the MAC address.
- The deprecated OCI `prestart` hook is now only used by build containers. For other containers, network interfaces are added to the network namespace after task creation is complete, before the container task is started. [moby/moby#47406](https://github.com/moby/moby/pull/47406)
- Add a new `gw-priority` option to `docker run`, `docker container create`, and `docker network connect`. This option will be used by the Engine to determine which network provides the default gateway for a container. On `docker run`, this option is only available through the extended `--network` syntax. [docker/cli#5664](https://github.com/docker/cli/pull/5664)
- Add a new netlabel `com.docker.network.endpoint.ifname` to customize the interface name used when connecting a container to a network. It's supported by all built-in network drivers on Linux. [moby/moby#49155](https://github.com/moby/moby/pull/49155)
  - When a container is created with multiple networks specified, there's no guarantee on the order networks will be connected to the container. So, if a custom interface name uses the same prefix as the auto-generated names, for example `eth`, the container might fail to start.
  - The recommended practice is to use a different prefix, for example `en0`, or a numerical suffix high enough to never collide, for example `eth100`.
  - This label can be specified on `docker network connect` via the `--driver-opt` flag, for example `docker network connect --driver-opt=com.docker.network.endpoint.ifname=foobar …`.
  - Or via the long-form `--network` flag on `docker run`, for example `docker run --network=name=bridge,driver-opt=com.docker.network.endpoint.ifname=foobar …`
- If a custom network driver reports capability `GwAllocChecker` then, before a network is created, it will get a `GwAllocCheckerRequest` with the network's options. The custom driver may then reply that no gateway IP address should be allocated. [moby/moby#49372](https://github.com/moby/moby/pull/49372)

#### Port publishing in bridge networks

- `dockerd` now requires `ipset` support in the Linux kernel. [moby/moby#48596](https://github.com/moby/moby/pull/48596)
  - The `iptables` and `ip6tables` rules used to implement port publishing and network isolation have been extensively modified. This enables some of the following functional changes, and is a first step in refactoring to enable native `nftables` support in a future release. [moby/moby#48815](https://github.com/moby/moby/issues/48815)
  - If it becomes necessary to downgrade to an earlier version of the daemon, some manual cleanup of the new rules will be necessary. The simplest and surest approach is to reboot the host, or use `iptables -F` and `ip6tables -F` to flush all existing `iptables` rules from the `filter` table before starting the older version of the daemon. When that is not possible, run the following commands as root:
    - `iptables -D FORWARD -m set --match-set docker-ext-bridges-v4 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; ip6tables -D FORWARD -m set --match-set docker-ext-bridges-v6 dst -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT`
    - `iptables -D FORWARD -m set --match-set docker-ext-bridges-v4 dst -j DOCKER; ip6tables -D FORWARD -m set --match-set docker-ext-bridges-v6 dst -j DOCKER`
    - If you were previously running with the iptables filter-FORWARD policy set to `ACCEPT` and need to restore access to unpublished ports, also delete per-bridge-network rules from the `DOCKER` chains. For example, `iptables -D DOCKER ! -i docker0 -o docker0 -j DROP`.
- Fix a security issue that was allowing remote hosts to connect directly to a container on its published ports. [moby/moby#49325](https://github.com/moby/moby/pull/49325)
- Fix a security issue that was allowing neighbor hosts to connect to ports mapped on a loopback address. [moby/moby#49325](https://github.com/moby/moby/pull/49325)
- Fix an issue that prevented port publishing to link-local addresses. [moby/moby#48570](https://github.com/moby/moby/pull/48570)
- UDP ports published by a container are now reliably accessible by containers on other networks, via the host's public IP address. [moby/moby#48571](https://github.com/moby/moby/pull/48571)
- Docker will now only set the `ip6tables` policy for the `FORWARD` chain in the `filter` table to `DROP` if it enables IP forwarding on the host itself (sysctls `net.ipv6.conf.all.forwarding` and `net.ipv6.conf.default.forwarding`). This is now aligned with existing IPv4 behaviour. [moby/moby#48594](https://github.com/moby/moby/pull/48594)
    - If IPv6 forwarding is enabled on your host, but you were depending on Docker to set the ip6tables filter-FORWARD policy to `DROP`, you may need to update your host's configuration to make sure it is secure.
- Direct routed access to container ports that are not exposed using `p`/`-publish` is now blocked in the `DOCKER` iptables chain. [moby/moby#48724](https://github.com/moby/moby/pull/48724)
    - If the default iptables filter-FORWARD policy was previously left at `ACCEPT` on your host, and direct routed access to a container's unpublished ports from a remote host is still required, options are:
      - Publish the ports you need.
      - Use the new `gateway_mode_ipv[46]=nat-unprotected`, described below.
    - Container ports published to host addresses will continue to be accessible via those host addresses, using NAT or the userland proxy.
    - Unpublished container ports continue to be directly accessible from the Docker host via the container's IP address.
- Networks created with `gateway_mode_ipv[46]=routed` are now accessible from other bridge networks running on the same Docker host, as well as from outside the host. [moby/moby#48596](https://github.com/moby/moby/pull/48596)
- Bridge driver options `com.docker.network.bridge.gateway_mode_ipv4` and `com.docker.network.bridge.gateway_mode_ipv6` now accept mode `nat-unprotected`. [moby/moby#48597](https://github.com/moby/moby/pull/48597)
    - `nat-unprotected` is similar to the default `nat` mode, but no per port/protocol rules are set up. This means any port on a container can be accessed by direct-routing from a remote host.
- Bridge driver options `com.docker.network.bridge.gateway_mode_ipv4` and `com.docker.network.bridge.gateway_mode_ipv6` now accept mode `isolated`, when the network is also `internal`. [moby/moby#49262](https://github.com/moby/moby/pull/49262)
  - An address is normally assigned to the bridge device in an `internal` network. So, processes on the Docker host can access the network, and containers in the network can access host services listening on that bridge address (including services listening on "any" host address, `0.0.0.0` or `::`).
  - An `internal` bridge network created with gateway mode `isolated` does not have an address on the Docker host.
- When a port mapping includes a host IP address or port number that cannot be used because NAT from the host is disabled using `--gateway_mode_ipv[46]`, container creation will no longer fail. The unused fields may be needed if the gateway endpoint changes when networks are connected or disconnected. A message about the unused fields will be logged. [moby/moby#48575](https://github.com/moby/moby/pull/48575)
- Do not create iptables nat-POSTROUTING masquerade rules for a container's own published ports, when the userland proxy is enabled. [moby/moby#48854](https://github.com/moby/moby/pull/48854)

#### IPv6

- Add `docker network create` option `--ipv4`. To disable IPv4 address assignment for a network, use `docker network create --ipv4=false [...]`. [docker/cli#5599](https://github.com/docker/cli/pull/5599)
- Daemon option `--ipv6` (`"ipv6": true` in `daemon.json`) can now be used without `fixed-cidr-v6`. [moby/moby#48319](https://github.com/moby/moby/pull/48319)
- IPAM now handles subnets bigger than "/64". [moby/moby#49223](https://github.com/moby/moby/pull/49223)
- Duplicate address detection (DAD) is now disabled for addresses assigned to the bridges belonging to bridge networks. [moby/moby#48609](https://github.com/moby/moby/pull/48609)
- Modifications to `host-gateway`, for compatibility with IPv6-only networks. [moby/moby#48807](https://github.com/moby/moby/pull/48807)
  - When special value `host-gateway` is used in an `--add-host` option in place of an address, it's replaced by an address on the Docker host to make it possible to refer to the host by name. The address used belongs to the default bridge (normally `docker0`). Until now it's always been an IPv4 address, because all containers on bridge networks had IPv4 addresses.
  - Now, if IPv6 is enabled on the default bridge network, `/etc/hosts` entries will be created for IPv4 and IPv6 addresses. So, a container that's only connected to IPv6-only networks can access the host by name.
  - The `--host-gateway-ip` option overrides the address used to replace `host-gateway`. Two of these options are now allowed on the command line, for one IPv4 gateway and one IPv6.
  - In the `daemon.json` file, to provide two addresses, use `"host-gateway-ips"`. For example, `"host-gateway-ips": ["192.0.2.1", "2001:db8::1111"]`.


### Bug fixes and enhancements

- Add IPv6 loopback address as an insecure registry by default. [moby/moby#48540](https://github.com/moby/moby/pull/48540)
- Add support for Cobra-generated completion scripts for `dockerd`. [moby/moby#49339](https://github.com/moby/moby/pull/49339)
- Fix DNS queries failing when containers are launched via `systemd` auto-start on boot [moby/moby#48812](https://github.com/moby/moby/pull/48812)
- Fix Docker Swarm mode ignoring `volume.subpath` [docker/cli#5833](https://github.com/docker/cli/pull/5833)
- Fix `docker export` continuing the export after the operation is canceled. [moby/moby#49265](https://github.com/moby/moby/pull/49265)
- Fix `docker export` not releasing the container's writable layer after a failure. [moby/moby#48517](https://github.com/moby/moby/pull/48517)
- Fix `docker images --tree` unnecessary truncating long image names when multiple names are available [docker/cli#5757](https://github.com/docker/cli/pull/5757)
- Fix a bug where a container with a name matching another container's ID is not restored on daemon startup. [moby/moby#48669](https://github.com/moby/moby/pull/48669)
- Fix an issue preventing some IPv6 addresses shown by `docker ps` to be properly bracketed [docker/cli#5468](https://github.com/docker/cli/pull/5468)
- Fix bug preventing image pulls from being cancelled during `docker run`. [docker/cli#5645](https://github.com/docker/cli/pull/5645)
- Fix error-handling when running the daemon as a Windows service to prevent unclean exits. [moby/moby#48518](https://github.com/moby/moby/pull/48518)
- Fix issue causing output of `docker run` to be inconsistent when using `--attach stdout` or `--attach stderr` versus `stdin`.  `docker run --attach stdin` now exits if the container exits. [docker/cli#5662](https://github.com/docker/cli/pull/5662)
- Fix rootless Docker setup with `subid` backed by NSS modules. [moby/moby#49036](https://github.com/moby/moby/pull/49036)
- Generated completion scripts from the CLI now show descriptions next to each command/flag suggestion. [docker/cli#5756](https://github.com/docker/cli/pull/5756)
- IPv6 addresses shown by `docker ps` in port bindings are now bracketed [docker/cli#5363](https://github.com/docker/cli/pull/5363)
- Implement the ports validation method for Compose [docker/cli#5524](https://github.com/docker/cli/pull/5524)
- Improve error-output for invalid flags on the command line. [docker/cli#5233](https://github.com/docker/cli/pull/5233)
- Improve errors when failing to start a container using anther container's network namespace. [moby/moby#49367](https://github.com/moby/moby/pull/49367)
- Improve handling of invalid API errors that could result in an empty error message being shown. [moby/moby#49373](https://github.com/moby/moby/pull/49373)
- Improve output and consistency for unknown (sub)commands and invalid arguments [docker/cli#5234](https://github.com/docker/cli/pull/5234)
- Improve validation of `exec-opts` in daemon configuration. [moby/moby#48979](https://github.com/moby/moby/pull/48979)
- Update the handling of the `--gpus=0` flag to be consistent with the NVIDIA Container Runtime. [moby/moby#48482](https://github.com/moby/moby/pull/48482)
- `client.ContainerCreate` now normalizes `CapAdd` and `CapDrop` fields in `HostConfig` to their canonical form. [moby/moby#48551](https://github.com/moby/moby/pull/48551)
- `docker image save` now produces stable timestamps. [moby/moby#48611](https://github.com/moby/moby/pull/48611)
- `docker inspect` now lets you inspect Swarm configs [docker/cli#5573](https://github.com/docker/cli/pull/5573)
- containerd image store: Add support for `Extracting` layer status in `docker pull`. [moby/moby#49064](https://github.com/moby/moby/pull/49064)
- containerd image store: Fix `commit`, `import`, and `build` not preserving a replaced image as a dangling image. [moby/moby#48316](https://github.com/moby/moby/pull/48316)
- containerd image store: Make `docker load --platform` return an error when the requested platform isn't loaded. [moby/moby#48718](https://github.com/moby/moby/pull/48718)
- Fix validation of `--link` option. [docker/cli#5739](https://github.com/docker/cli/pull/5739)
- Add validation of network-diagnostic-port daemon configuration option. [moby/moby#49305](https://github.com/moby/moby/pull/49305)
- Unless explicitly configured, an IP address is no longer reserved for a gateway in cases where it is not required. Namely, “internal” bridge networks with option `com.docker.network.bridge.inhibit_ipv4`, `ipvlan` or `macvlan` networks with no parent interface, and L3 IPvlan modes. [moby/moby#49261](https://github.com/moby/moby/pull/49261)
- If a custom network driver reports capability `GwAllocChecker` then, before a network is created, it will get a `GwAllocCheckerRequest` with the network's options. The custom driver may then reply that no gateway IP address should be allocated. [moby/moby#49372](https://github.com/moby/moby/pull/49372)
- Fixed an issue that meant a container could not be attached to an L3 IPvlan at the same time as other network types. [moby/moby#49130](https://github.com/moby/moby/pull/49130)
- Remove the correct `/etc/hosts` entries when disconnecting a container from a network. [moby/moby#48857](https://github.com/moby/moby/pull/48857)
- Fix duplicate network disconnect events. [moby/moby#48800](https://github.com/moby/moby/pull/48800)
- Resolve issues related to changing `fixed-cidr` for `docker0`, and inferring configuration from a user-managed default bridge (`--bridge`). [moby/moby#48319](https://github.com/moby/moby/pull/48319)
- Remove feature flag `windows-dns-proxy`, introduced in release 26.1.0 to control forwarding to external DNS resolvers from Windows containers, to make `nslookup` work. It was enabled by default in release 27.0.0. [moby/moby#48738](https://github.com/moby/moby/pull/48738)
- Remove an `iptables` mangle rule for checksumming SCTP. The rule can be re-enabled by setting `DOCKER_IPTABLES_SCTP_CHECKSUM=1` in the daemon's environment. This override will be removed in a future release. [moby/moby#48149](https://github.com/moby/moby/pull/48149)
- Faster connection to bridge networks, in most cases. [moby/moby#49302](https://github.com/moby/moby/pull/49302)


### Packaging updates

- Update Go runtime to [1.23.6](https://go.dev/doc/devel/release#go1.23.6). [docker/cli#5795](https://github.com/docker/cli/pull/5795), [moby/moby#49393](https://github.com/moby/moby/pull/49393), [docker/docker-ce-packaging#1161](https://github.com/docker/docker-ce-packaging/pull/1161)
- Update `runc` to [v1.2.5](https://github.com/opencontainers/runc/releases/tag/v1.2.5) (static binaries only). [moby/moby#49464](https://github.com/moby/moby/pull/49464)
- Update containerd to [v1.7.25](https://github.com/containerd/containerd/releases/tag/v1.7.25). [moby/moby#49252](https://github.com/moby/moby/pull/49252)
- Update BuildKit to [v0.20.0](https://github.com/moby/buildkit/releases/tag/v0.20.0). [moby/moby#49495](https://github.com/moby/moby/pull/49495)
- Update Buildx to [v0.21.0](https://github.com/docker/buildx/releases/tag/v0.21.0). [docker/docker-ce-packaging#1166](https://github.com/docker/docker-ce-packaging/pull/1166)
- Update Compose to [v2.32.4](https://github.com/docker/compose/releases/tag/v2.32.3). [docker/docker-ce-packaging#1143](https://github.com/docker/docker-ce-packaging/pull/1143)
- The canonical source for the `dockerd(8)` man page has been moved back to the `moby/moby` repository itself. [moby/moby#48298](https://github.com/moby/moby/pull/48298)

### Go SDK

- Improve validation of empty object IDs. The client now returns an "Invalid Parameter" error when trying to use an empty ID or name. This changes the error returned by some "Inspect" functions from a "Not found" error to an "Invalid Parameter". [moby/moby#49381](https://github.com/moby/moby/pull/49381)
- `Client.ImageBuild()` now omits default values from the API request's query string. [moby/moby#48651](https://github.com/moby/moby/pull/48651)
- `api/types/container`: Merge `Stats` and `StatsResponse` [moby/moby#49287](https://github.com/moby/moby/pull/49287)
- `client.WithVersion`: Strip v-prefix when setting API version [moby/moby#49352](https://github.com/moby/moby/pull/49352)
- `client`: Add `WithTraceOptions` allowing to specify custom OTe1 trace options. [moby/moby#49415](https://github.com/moby/moby/pull/49415)
- `client`: Add `HijackDialer` interface. [moby/moby#49388](https://github.com/moby/moby/pull/49388)
- `client`: Add `SwarmManagementAPIClient` interface to describe all API client methods related to Swarm-specific objects. [moby/moby#49388](https://github.com/moby/moby/pull/49388)
- `client`: Add `WithTraceOptions` allowing to specify custom OTel trace options. [moby/moby#49415](https://github.com/moby/moby/pull/49415)
- `client`: `ImageHistory`, `ImageLoad` and `ImageSave` now use variadic functional options [moby/moby#49466](https://github.com/moby/moby/pull/49466)
- `pkg/containerfs`: Move to internal [moby/moby#48097](https://github.com/moby/moby/pull/48097)
- `pkg/reexec`: Can now be used on platforms other than Linux, Windows, macOS and FreeBSD [moby/moby#49118](https://github.com/moby/moby/pull/49118)
- `api/types/container`: introduce `CommitResponse` type. This is currently an alias for `IDResponse`, but may become a distinct type in a future release. [moby/moby#49444](https://github.com/moby/moby/pull/49444)
- `api/types/container`: introduce `ExecCreateResponse` type. This is currently an alias for `IDResponse`, but may become a distinct type in a future release. [moby/moby#49444](https://github.com/moby/moby/pull/49444)

### API

- Update API version to [v1.48](https://docs.docker.com/engine/api/v1.48/) [moby/moby#48476](https://github.com/moby/moby/pull/48476)
- `GET /images/{name}/json` response now returns the `Manifests` field containing information about the sub-manifests contained in the image index. This includes things like platform-specific manifests and build attestations. [moby/moby#48264](https://github.com/moby/moby/pull/48264)
- `POST /containers/create` now supports `Mount` of type `image` for mounting an image inside a container. [moby/moby#48798](https://github.com/moby/moby/pull/48798)
- `GET /images/{name}/history` now supports a `platform` parameter (JSON encoded OCI Platform type) that lets you specify a platform to show the history of. [moby/moby#48295](https://github.com/moby/moby/pull/48295)
- `POST /images/{name}/load` and `GET /images/{name}/get` now supports a `platform` parameter (JSON encoded OCI Platform type) that lets you specify a platform to load/save. Not passing this parameter results in loading/saving the full multi-platform image. [moby/moby#48295](https://github.com/moby/moby/pull/48295)
- Improve errors for invalid width/height on container resize and exec resize [moby/moby#48679](https://github.com/moby/moby/pull/48679)
- The `POST /containers/create` endpoint now includes a warning in the response when setting the container-wide `VolumeDriver` option in combination with volumes defined through `Mounts` because the `VolumeDriver` option has no effect on those volumes. This warning was previously generated by the CLI. [moby/moby#48789](https://github.com/moby/moby/pull/48789)
- containerd image store: `GET /images/json` and `GET /images/{name}/json` responses now includes `Descriptor` field, which contains an OCI descriptor of the image target. The new field is only populated if the daemon provides a multi-platform image store. [moby/moby#48894](https://github.com/moby/moby/pull/48894)
- containerd image store: `GET /containers/{name}/json` now returns an `ImageManifestDescriptor` field containing the OCI descriptor of the platform-specific image manifest of the image that was used to create the container. [moby/moby#48855](https://github.com/moby/moby/pull/48855)
- Add debug endpoints (`GET /debug/vars`, `GET /debug/pprof/`, `GET /debug/pprof/cmdline`, `GET /debug/pprof/profile`, `GET /debug/pprof/symbol`, `GET /debug/pprof/trace`, `GET /debug/pprof/{name}`) are now also accessible through the versioned-API paths (`/v<API-version>/<endpoint>`). [moby/moby#49051](https://github.com/moby/moby/pull/49051)
- Fix API returning a `500` status code instead of `400` for validation errors. [moby/moby#49217](https://github.com/moby/moby/pull/49217)
- Fix status codes for archive endpoints `HEAD /containers/{name:.*}/archive`, `GET /containers/{name:.*}/archive`, `PUT /containers/{name:.*}/archive` returning a `500` status instead of a `400` status. [moby/moby#49219](https://github.com/moby/moby/pull/49219)
- `POST /containers/create` now accepts a `writable-cgroups=true` option in `HostConfig.SecurityOpt` to mount the container's cgroups writable. This provides a more granular approach than `HostConfig.Privileged`. [moby/moby#48828](https://github.com/moby/moby/pull/48828)
- `POST /build/prune` renames `keep-bytes` to `reserved-space` and now supports additional prune parameters `max-used-space` and `min-free-space`. [moby/moby#48720](https://github.com/moby/moby/pull/48720)
- `POST /networks/create` now has an `EnableIPv4` field. Setting it to `false` disables IPv4 IPAM for the network. [moby/moby#48271](https://github.com/moby/moby/pull/48271)
  - `GET /networks/{id}` now returns an `EnableIPv4` field showing whether the network has IPv4 IPAM enabled. [moby/moby#48271](https://github.com/moby/moby/pull/48271)
  - User-defined bridge networks require either IPv4 or IPv6 address assignment to be enabled. IPv4 cannot be disabled for the default bridge network (`docker0`). [moby/moby#48323](https://github.com/moby/moby/pull/48323)
  - `macvlan` and `ipvlan` networks can be created with address assignment disabled for IPv4, IPv6, or both address families. [moby/moby#48299](https://github.com/moby/moby/pull/48299)
  - IPv4 cannot be disabled for Windows or Swarm networks. [moby/moby#48278](https://github.com/moby/moby/pull/48278)
- Add a way to specify which network should provide the default gateway for a container. [moby/moby#48936](https://github.com/moby/moby/pull/48936)
  - `POST /networks/{id}/connect` and `POST /containers/create` now accept a `GwPriority` field in `EndpointsConfig`. This value is used to determine which network endpoint provides the default gateway for the container. The endpoint with the highest priority is selected. If multiple endpoints have the same priority, endpoints are sorted lexicographically by their network name, and the one that sorts first is picked. [moby/moby#48746](https://github.com/moby/moby/pull/48746)
  - `GET /containers/json` now returns a `GwPriority` field in `NetworkSettings` for each network endpoint. The `GwPriority` field is used by the CLI’s new `gw-priority` option for `docker run` and `docker network connect`. [moby/moby#48746](https://github.com/moby/moby/pull/48746)
- Settings for `eth0` in `--sysctl` options are no longer automatically migrated to the network endpoint. [moby/moby#48746](https://github.com/moby/moby/pull/48746)
    - For example, in the Docker CLI, `docker run --network mynet --sysctl net.ipv4.conf.eth0.log_martians=1 ...` is rejected. Instead, you must use `docker run --network name=mynet,driver-opt=com.docker.network.endpoint.sysctls=net.ipv4.conf.IFNAME.log_martians=1 ...`
- `GET /containers/json` now returns an `ImageManifestDescriptor` field matching the same field in `/containers/{name}/json`. This field is only populated if the daemon provides a multi-platform image store. [moby/moby#49407](https://github.com/moby/moby/pull/49407)


### Removed

- The Fluent logger option `fluentd-async-connect` has been deprecated in v20.10 and is now removed. [moby/moby#46114](https://github.com/moby/moby/pull/46114)
- The `--time` option on `docker stop` and `docker restart` is deprecated and renamed to `--timeout`. [docker/cli#5485](https://github.com/docker/cli/pull/5485)
- Go-SDK: `pkg/ioutils`: Remove `NewReaderErrWrapper` as it was never used. [moby/moby#49258](https://github.com/moby/moby/pull/49258)
- Go-SDK: `pkg/ioutils`: Remove deprecated `BytesPipe`, `NewBytesPipe`, `ErrClosed`, `WriteCounter`, `NewWriteCounter`, `NewReaderErrWrapper`, `NopFlusher`. [moby/moby#49245](https://github.com/moby/moby/pull/49245)
- Go-SDK: `pkg/ioutils`: Remove deprecated `NopWriter` and `NopWriteCloser`. [moby/moby#49256](https://github.com/moby/moby/pull/49256)
- Go-SDK: `pkg/sysinfo`: Remove deprecated NumCPU. [moby/moby#49242](https://github.com/moby/moby/pull/49242)
- Go-SDK: Remove `pkg/broadcaster`, as it was only used internally [moby/moby#49172](https://github.com/moby/moby/pull/49172)
- Go-SDK: Remove deprecated `cli.Errors` type [docker/cli#5549](https://github.com/docker/cli/pull/5549)
- Remove `pkg/ioutils.ReadCloserWrapper`, as it was only used in tests. [moby/moby#49237](https://github.com/moby/moby/pull/49237)
- Remove deprecated `api-cors-header` config parameter and the `dockerd` `--api-cors-header` option [moby/moby#48209](https://github.com/moby/moby/pull/48209)
- Remove deprecated `APIEndpoint.Version` field, `APIVersion` type, and `APIVersion1` and `APIVersion2` consts. [moby/moby#49004](https://github.com/moby/moby/pull/49004)
- Remove deprecated `api-cors-header` config parameter and the Docker daemon's `--api-cors-header` option. [docker/cli#5437](https://github.com/docker/cli/pull/5437)
- Remove deprecated `pkg/directory` package [moby/moby#48779](https://github.com/moby/moby/pull/48779)
- Remove deprecated `pkg/dmsg.Dmesg()` [moby/moby#48109](https://github.com/moby/moby/pull/48109)
- Remove deprecated image/spec package, which was moved to a separate module (`github.com/moby/docker-image-spec`) [moby/moby#48460](https://github.com/moby/moby/pull/48460)
- Remove migration code and errors for the deprecated `logentries` logging driver. [moby/moby#48891](https://github.com/moby/moby/pull/48891)
- Remove support for deprecated external graph-driver plugins. [moby/moby#48072](https://github.com/moby/moby/pull/48072)
- `api/types`: Remove deprecated `container.ContainerNode` and `ContainerJSONBase.Node` field. [moby/moby#48107](https://github.com/moby/moby/pull/48107)
- `api/types`: Remove deprecated aliases: `ImagesPruneReport`, `VolumesPruneReport`, `NetworkCreateRequest`, `NetworkCreate`, `NetworkListOptions`, `NetworkCreateResponse`, `NetworkInspectOptions`, `NetworkConnect`, `NetworkDisconnect`, `EndpointResource`, `NetworkResource`, `NetworksPruneReport`, `ExecConfig`, `ExecStartCheck`, `ContainerExecInspect`, `ContainersPruneReport`, `ContainerPathStat`, `CopyToContainerOptions`, `ContainerStats`, `ImageSearchOptions`, `ImageImportSource`, `ImageLoadResponse`, `ContainerNode`. [moby/moby#48107](https://github.com/moby/moby/pull/48107)
- `libnetwork/iptables`: Remove deprecated `IPV`, `Iptables`, `IP6Tables` and `Passthrough()`. [moby/moby#49121](https://github.com/moby/moby/pull/49121)
- `pkg/archive`: Remove deprecated `CanonicalTarNameForPath`, `NewTempArchive`, `TempArchive` [moby/moby#48708](https://github.com/moby/moby/pull/48708)
- `pkg/fileutils`: Remove deprecated `GetTotalUsedFds` [moby/moby#49210](https://github.com/moby/moby/pull/49210)
- `pkg/ioutils`: Remove `OnEOFReader`, which was only used internally [moby/moby#49170](https://github.com/moby/moby/pull/49170)
- `pkg/longpath`: Remove deprecated `Prefix` constant. [moby/moby#48779](https://github.com/moby/moby/pull/48779)
- `pkg/stringid`: Remove deprecated `IsShortID` and  `ValidateID` functions [moby/moby#48705](https://github.com/moby/moby/pull/48705)
- `runconfig/opts`: Remove deprecated `ConvertKVStringsToMap` [moby/moby#48102](https://github.com/moby/moby/pull/48102)
- `runconfig`: Remove deprecated `ContainerConfigWrapper`, `SetDefaultNetModeIfBlank`, `DefaultDaemonNetworkMode`, `IsPreDefinedNetwork` [moby/moby#48102](https://github.com/moby/moby/pull/48102)
- `container`: Remove deprecated `ErrNameReserved`, `ErrNameNotReserved`. [moby/moby#48728](https://github.com/moby/moby/pull/48728)
- Remove `Daemon.ContainerInspectCurrent()` method and change `Daemon.ContainerInspect()` signature to accept a `backend.ContainerInspectOptions` struct [moby/moby#48672](https://github.com/moby/moby/pull/48672)
- Remove deprecated `Daemon.Exists()` and `Daemon.IsPaused()` methods. [moby/moby#48723](https://github.com/moby/moby/pull/48723)

### Deprecations

- API: The `BridgeNfIptables` and `BridgeNfIp6tables` fields in the `GET /info` response are now always be `false` and will be omitted in API v1.49. The netfilter module is now loaded on-demand, and no longer during daemon startup, making these fields obsolete. [moby/moby#49114](https://github.com/moby/moby/pull/49114)
- API: The `error` and `progress` fields in streaming responses for endpoints that return a JSON progress response, such as `POST /images/create`, `POST /images/{name}/push`, and `POST /build` are deprecated.  [moby/moby#49447](https://github.com/moby/moby/pull/49447)
  - Users should use the information in the `errorDetail` and `progressDetail` fields instead.
  - These fields were marked deprecated in API v1.4 (docker v0.6.0) and API v1.8 (docker v0.7.1) respectively, but still returned.
  - These fields will be left empty or will be omitted in a future API version.
- Deprecate `Daemon.Register()`. This function is unused and will be removed in the next release. [moby/moby#48702](https://github.com/moby/moby/pull/48702)
- Deprecate `client.ImageInspectWithRaw` function in favor of the new `client.ImageInspect`. [moby/moby#48264](https://github.com/moby/moby/pull/48264)
- Deprecate `daemon/config.Config.ValidatePlatformConfig()`. This method was used as helper for `config.Validate`, which should be used instead. [moby/moby#48985](https://github.com/moby/moby/pull/48985)
- Deprecate `pkg/reexec`. This package is deprecated and moved to a separate module. Use `github.com/moby/sys/reexec` instead. [moby/moby#49129](https://github.com/moby/moby/pull/49129)
- Deprecate configuration for pushing non-distributable artifacts [docker/cli#5724](https://github.com/docker/cli/pull/5724)
- Deprecate the `--allow-nondistributable-artifacts` daemon flag and corresponding `allow-nondistributable-artifacts` field in `daemon.json`. Setting either option will no longer take an effect, but a deprecation warning log is added. [moby/moby#49065](https://github.com/moby/moby/pull/49065)
- Deprecate the `RegistryConfig.AllowNondistributableArtifactsCIDRs` and `RegistryConfig.AllowNondistributableArtifactsHostnames` fields in the `GET /info` API response. For API version v1.48 and older, the fields are still included in the response, but always `null`. In API version v1.49 and later, the field will be omitted entirely. [moby/moby#49065](https://github.com/moby/moby/pull/49065)
- Go-SDK: Deprecate `registry.ServiceOptions.AllowNondistributableArtifacts` field. [moby/moby#49065](https://github.com/moby/moby/pull/49065)
- Go-SDK: The `BridgeNfIptables`, `BridgeNfIp6tables` fields in `api/types/system.Info` and `BridgeNFCallIPTablesDisabled`, `BridgeNFCallIP6TablesDisabled` fields in `pkg/sysinfo.SysInfo` are deprecated and will be removed in the next release. [moby/moby#49114](https://github.com/moby/moby/pull/49114)
- Go-SDK: `client`: Deprecate `CommonAPIClient` interface in favor of the `APIClient` interface. The `CommonAPIClient` will be changed to an alias for `APIClient` in the next release, and removed in the release after. [moby/moby#49388](https://github.com/moby/moby/pull/49388)
- Go-SDK: `client`: Deprecate `ErrorConnectionFailed` helper. This function was only used internally, and will be removed in the next release. [moby/moby#49389](https://github.com/moby/moby/pull/49389)
- Go-SDK: `pkg/ioutils`: Deprecate `NewAtomicFileWriter`, `AtomicWriteFile`, `AtomicWriteSet`, `NewAtomicWriteSet` in favor of `pkg/atomicwriter` equivalents. [moby/moby#49171](https://github.com/moby/moby/pull/49171)
- Go-SDK: `pkg/sysinfo`: Deprecate `NumCPU`. This utility has the same behavior as `runtime.NumCPU`. [moby/moby#49241](https://github.com/moby/moby/pull/49241)
- Go-SDK: `pkg/system`: Deprecate `MkdirAll`. This function provided custom handling for Windows GUID volume paths. Handling for such paths is now supported by Go standard library in go1.22 and newer, and this function is now an alias for `os.MkdirAll`, which should be used instead. This alias will be removed in the next release. [moby/moby#49162](https://github.com/moby/moby/pull/49162)
- Go-SDK: Deprecate `pkg/parsers.ParseKeyValueOpt`. [moby/moby#49177](https://github.com/moby/moby/pull/49177)
- Go-SDK: Deprecate `pkg/parsers.ParseUintListMaximum`, `pkg/parsers.ParseUintList`. These utilities were only used internally and will be removed in the next release. [moby/moby#49222](https://github.com/moby/moby/pull/49222)
- Go-SDK: Deprecate `api/type.IDResponse` in favor of `container.CommitResponse` and `container.ExecCreateResponse`, which are currently an alias, but may become distinct types in a future release. This type will be removed in the next release. [moby/moby#49446](https://github.com/moby/moby/pull/49446)
- Go-SDK: Deprecate `api/types/container.ContainerUpdateOKBody` in favor of `UpdateResponse`. This type will be removed in the next release. [moby/moby#49442](https://github.com/moby/moby/pull/49442)
- Go-SDK: Deprecate `api/types/container.ContainerTopOKBody` in favor of `TopResponse`. This type will be removed in the next release. [moby/moby#49442](https://github.com/moby/moby/pull/49442)
- Go-SDK: `pkg/jsonmessage`: Fix deprecation of `ProgressMessage`, `ErrorMessage`, which were deprecated in Docker v0.6.0 and v0.7.1 respectively. [moby/moby#49447](https://github.com/moby/moby/pull/49447)
- Move `GraphDriverData` from `api/types` to `api/types/storage`. The old type is deprecated and will be removed in the next release. [moby/moby#48108](https://github.com/moby/moby/pull/48108)
- Move `RequestPrivilegeFunc` from `api/types` to `api/types/registry`. The old type is deprecated and will be removed in the next release. [moby/moby#48119](https://github.com/moby/moby/pull/48119)
- Move from `api/types` to `api/types/container` - `NetworkSettings`, `NetworkSettingsBase`, `DefaultNetworkSettings`, `SummaryNetworkSettings`, `Health`, `HealthcheckResult`, `NoHealthcheck`, `Starting`, `Healthy`, and `Unhealthy` constants, `MountPoint`, `Port`, `ContainerState`, `Container`, `ContainerJSONBase`, `ContainerJSON`, `ContainerNode`. The old types are deprecated and will be removed in the next release. [moby/moby#48108](https://github.com/moby/moby/pull/48108)
- Move from `api/types` to `api/types/image` - `ImageInspect`, `RootFS`. The old types are deprecated and will be removed in the next release. [moby/moby#48108](https://github.com/moby/moby/pull/48108)
- `ContainerdCommit.Expected`, `RuncCommit.Expected`, and `InitCommit.Expected` fields in the `GET /info` endpoint are deprecated and will be omitted in API v1.49. [moby/moby#48478](https://github.com/moby/moby/pull/48478)
- `api/types/registry`: Deprecate `ServiceConfig.AllowNondistributableArtifactsCIDRs` and `ServiceConfig.AllowNondistributableArtifactsHostnames` fields. These fields will be removed in the next release. [moby/moby#49065](https://github.com/moby/moby/pull/49065)
- `api/types/system/Commit.Expected` field is deprecated and should no longer be used. [moby/moby#48478](https://github.com/moby/moby/pull/48478)
- `daemon/graphdriver`: Deprecate `GetDriver()` [moby/moby#48079](https://github.com/moby/moby/pull/48079)
- `libnetwork/iptables`: Deprecate `Passthrough`. This function was only used internally, and will be removed in the next release. [moby/moby#49115](https://github.com/moby/moby/pull/49115)
- `pkg/directory.Size()` function is deprecated, and will be removed in the next release. [moby/moby#48057](https://github.com/moby/moby/pull/48057)
- `registry`: Deprecate `APIEndpoint.TrimHostName`; hostname is now trimmed unconditionally for remote names. This field will be removed in the next release. [moby/moby#49005](https://github.com/moby/moby/pull/49005)
- `allow-nondistributable-artifacts` field in `daemon.json`. Setting either option will no longer take effect, but a deprecation warning log is added to raise awareness about the deprecation. This warning is planned to become an error in the next release. [moby/moby#49065](https://github.com/moby/moby/pull/49065)


---

# Docker Engine version 29 release notes

*Sección: Engine*

This page describes the latest changes, additions, known issues, and fixes for Docker Engine version 29.

For more information about:

- Deprecated and removed features, see [Deprecated Engine Features](../deprecated.md).
- Changes to the Engine API, see [Engine API version history](/reference/api/engine/version-history/).

## 29.8.0

{{< release-date date="2026-09-03" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.8.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.8.0)
- [moby/moby, 29.8.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.8.0)

### New

- Add `HostConfig.Umask` option and a corresponding `--umask <octal>` flag to `docker create`/`docker run` to set the umask for a container's main process, execs, and healthchecks. [moby/moby#53463](https://github.com/moby/moby/pull/53463), [docker/cli#7108](https://github.com/docker/cli/pull/7108)
- Add support for attaching service names, environments, and custom CloudWatch entity attributes to logs from the `awslogs` logging driver. [moby/moby#52632](https://github.com/moby/moby/pull/52632)

### Security

- Add daemon support for configuring the default container AppArmor profile template. [moby/moby#52771](https://github.com/moby/moby/pull/52771)
  - See https://docker.docker.com/engine/security/apparmor/#customize-the-default-profile
- Prevent containers from using the 32-bit `socketcall(2)` path to create `AF_VSOCK` sockets and communicate with host virtual machines by adding AppArmor and SELinux policy rules. [moby/moby#53551](https://github.com/moby/moby/pull/53551)

### Networking

- Fix `docker network inspect` failing to find a healthy Swarm network when another Swarm network could not be allocated. [moby/moby#53325](https://github.com/moby/moby/pull/53325)
- Fix a node gossiping a superseded value for a Swarm service discovery entry after concurrent updates to the same key. [moby/moby#53479](https://github.com/moby/moby/pull/53479)
- Fix Swarm service names failing to resolve on a node indefinitely after it misses a network membership announcement. [moby/moby#53437](https://github.com/moby/moby/pull/53437)
- Fix Swarm service names failing to resolve on healthy nodes after a transient node failure. [moby/moby#53142](https://github.com/moby/moby/pull/53142)
- Prevent dockerd from hanging when the nft command produces enough stderr output to fill its pipe. [moby/moby#53517](https://github.com/moby/moby/pull/53517)
- Reduce gossip traffic generated by a node that repeatedly disconnects and rejoins the cluster. [moby/moby#53479](https://github.com/moby/moby/pull/53479)
- Remote network-driver plugins can now set the container-side interface name via the `DstName` field in their `Join` response. [moby/moby#52866](https://github.com/moby/moby/pull/52866)
- Reserve network names "container" and "container:" to prevent creation of unusable networks. [moby/moby#51973](https://github.com/moby/moby/pull/51973)
- Spread the daemon's periodic Swarm overlay network gossip and synchronization work over time, avoiding recurring bursts of CPU and network usage. [moby/moby#53475](https://github.com/moby/moby/pull/53475)
- Swarm service-mesh published ports now use the same infrastructure as published ports for local containers. [moby/moby#53118](https://github.com/moby/moby/pull/53118)

### Rootless

- Fix `--disable-host-loopback` not being enforced for the `pasta` network driver in rootless mode. [moby/moby#53358](https://github.com/moby/moby/pull/53358)
- Update RootlessKit to v3.1.0, adding support for the `pesto` port driver in rootless mode. Set `DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=pesto` to use it; it requires the `pasta` network driver and supports IPv4 only. [moby/moby#53358](https://github.com/moby/moby/pull/53358)

### Go SDK

- Update minimum supported Go version to 1.26. [docker/cli#7258](https://github.com/docker/cli/pull/7258)
### Bug fixes and enhancements

- Add `annotation` filter to container listings (`docker ps`, `GET /containers/json`) allowing to filter containers by their annotations. [moby/moby#53538](https://github.com/moby/moby/pull/53538)
- containerd image store: Fix `docker image inspect` reporting a smaller image size than `docker image ls`. [moby/moby#53426](https://github.com/moby/moby/pull/53426)
- containerd image store: Fix slower image pulls caused by repeated registry authentication within a single pull. [moby/moby#53497](https://github.com/moby/moby/pull/53497)
- Do not log expected image signature identity misses as errors for containerd image store images. [moby/moby#53495](https://github.com/moby/moby/pull/53495)
- dockerd now uses the embedded containerd if no system containerd service is configured and containerd is not installed. [moby/moby#53388](https://github.com/moby/moby/pull/53388)
- Fix `GET /images/{name}/json` not including unpacked snapshot usage in `Size` when using the containerd image store. [moby/moby#53426](https://github.com/moby/moby/pull/53426)
- Fix classic-builder cache for Dockerfile stages that select a non-host platform with `FROM --platform`. [moby/moby#53503](https://github.com/moby/moby/pull/53503)
- Fix CLI panic when `DOCKER_HOST` or `-H` specifies an invalid host. [docker/cli#7280](https://github.com/docker/cli/pull/7280)
- Fix health checks being delayed for too long when the start interval is longer than the start period. [moby/moby#52317](https://github.com/moby/moby/pull/52317)
- Fix inconsistent mount ordering in `docker inspect` output (`GET /containers/{id}/json`) and container listings (`docker ps`, `GET /containers/json`). [moby/moby#53534](https://github.com/moby/moby/pull/53534)
- Fix NRI container metadata so `Container.Args` includes the resolved executable as `argv[0]`, matching the process launched in the container instead of only the Docker `Cmd`. [moby/moby#53423](https://github.com/moby/moby/pull/53423)
- Fix Swarm service creation failing when an automatically generated name is already in use. [moby/moby#53468](https://github.com/moby/moby/pull/53468)
- Fix the container root directory `/` being world-writable when using the `btrfs` storage driver. [moby/moby#53500](https://github.com/moby/moby/pull/53500)
- Fixed `docker ps` sorting published ports lexicographically instead of numerically. [docker/cli#7144](https://github.com/docker/cli/pull/7144)
- Preserve service mount order during forced updates to avoid an unnecessary rollout on the next stack deploy. [docker/cli#7227](https://github.com/docker/cli/pull/7227)
- Prevent containerd's v2 CRI plugins from loading when CRI is disabled. [moby/moby#53564](https://github.com/moby/moby/pull/53564)
- Print plugin hook output (e.g. the "What's next:" hint) after the command's error message instead of before it. [docker/cli#6976](https://github.com/docker/cli/pull/6976)
- Reject checkpoint IDs containing path separators to prevent access outside the container checkpoint directory. [moby/moby#53377](https://github.com/moby/moby/pull/53377)

### Packaging updates

- Update BuildKit to [v0.33.0](https://github.com/moby/buildkit/releases/tag/v0.33.0). [moby/moby#53554](https://github.com/moby/moby/pull/53554)
- Update containerd (static binaries) to [v2.3.4](https://github.com/containerd/containerd/releases/tag/v2.3.4). [moby/moby#53409](https://github.com/moby/moby/pull/53409)
- Update Go runtime to [1.26.8](https://go.dev/doc/devel/release#go1.26.8). [moby/moby#53550](https://github.com/moby/moby/pull/53550), [docker/cli#7274](https://github.com/docker/cli/pull/7274)
- Update runc (in static binaries) to [v1.5.1](https://github.com/opencontainers/runc/releases/tag/v1.5.1). [moby/moby#52306](https://github.com/moby/moby/pull/52306)

## 29.7.2

{{< release-date date="2026-08-05" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.7.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.7.2)
- [moby/moby, 29.7.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.7.2)

### Bug fixes and enhancements

- Fix `docker service create` and `docker service update` panicking when the same environment variable is passed more than once. [docker/cli#7145](https://github.com/docker/cli/pull/7145)
- Fix a regression introduced in Docker Engine 29.7.0 that caused image pulls to reject images containing absolute hardlink targets, as produced by some image builders. [moby/moby#53305](https://github.com/moby/moby/pull/53305)
- Fix a regression introduced in Docker Engine 29.7.0 that could cause image pulls and `docker cp` to fail on older Linux kernels when applying file permissions, including for device nodes. [moby/moby#53305](https://github.com/moby/moby/pull/53305)

### Packaging updates

- Update BuildKit to [v0.32.2](https://github.com/moby/buildkit/releases/tag/v0.32.2). [moby/moby#53300](https://github.com/moby/moby/pull/53300)

### Networking

- Improve compatibility with more nftables releases by terminating base-chain policies with a semicolon. [moby/moby#53303](https://github.com/moby/moby/pull/53303)

## 29.7.1

{{< release-date date="2026-07-31" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.7.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.7.1)
- [moby/moby, 29.7.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.7.1)

### Bug fixes and enhancements

- Fix a regression that prevented pulling images whose layers contain directories without explicit parent directory entries. [moby/moby#53260](https://github.com/moby/moby/pull/53260)
- Fix a regression where the `CopyToContainer` rejects container paths that traverse absolute symlinks, such as `/var/run` -> `/run`. [moby/moby#53261](https://github.com/moby/moby/pull/53261)

## 29.7.0

{{< release-date date="2026-07-30" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.7.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.7.0)
- [moby/moby, 29.7.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.7.0)

### New

- Add an experimental `embedded-containerd` feature that runs containerd inside the daemon process instead of as a separate managed process. [moby/moby#52898](https://github.com/moby/moby/pull/52898)
- Mount type `image` is no longer experimental. [moby/moby#52998](https://github.com/moby/moby/pull/52998)
- Add the `default-stop-timeout` daemon option to configure the stop timeout assigned to containers without an explicit timeout. [moby/moby#53146](https://github.com/moby/moby/pull/53146)

### Security

This release includes a fix for a security vulnerability affecting Docker Engine and related components.

- Update github.com/moby/go-archive to v0.3.0 to fix [CVE-2026-17106](https://www.cve.org/CVERecord?id=CVE-2026-17106) / [GHSA-hfg8-hc9c-6c3h](https://github.com/moby/go-archive/security/advisories/GHSA-hfg8-hc9c-6c3h). [moby/moby#53247](https://github.com/moby/moby/pull/53247), [docker/cli#7139](https://github.com/docker/cli/pull/7139)

### Networking

- Fix a daemon panic when cleanup of a container's network interface fails while the container is being disconnected from a network. [moby/moby#53237](https://github.com/moby/moby/pull/53237)
- Fix a daemon panic when removing swarm ingress ports after failing to bind an ingress proxy listener. [moby/moby#53022](https://github.com/moby/moby/pull/53022)

### Rootless

- Keep the cgroup mount for containers with `--net=host`. [moby/moby#52318](https://github.com/moby/moby/pull/52318)

### Bug fixes and enhancements


- Add shell completion for `--filter` names and known values to `docker service ls`, `docker service ps`, and `docker node ps`. [docker/cli#7124](https://github.com/docker/cli/pull/7124)
- containerd image store: Fix daemon-wide concurrent download and upload limits for pulls and pushes not being honored. [moby/moby#53081](https://github.com/moby/moby/pull/53081)
  - To preserve the previous unlimited startup behavior, configure "max-concurrent-downloads" and "max-concurrent-uploads" to 0
- Fix `docker cp -a` using the wrong file owner when copying files into containers with user namespace remapping enabled. [moby/moby#53084](https://github.com/moby/moby/pull/53084)
- Fix `docker cp` from a Windows container silently returning a file instead of an error when the source path ends with a separator but is not a directory. [moby/moby#53123](https://github.com/moby/moby/pull/53123)
- Fix `docker stats` reporting all zeros for running Windows containers when using the containerd runtime. [moby/moby#53101](https://github.com/moby/moby/pull/53101)
- Fix `docker stats` reporting empty network stats for running Windows containers when using the containerd runtime. [moby/moby#53219](https://github.com/moby/moby/pull/53219)
- Fix a typo in the `docker create --pull` flag description. [docker/cli#7103](https://github.com/docker/cli/pull/7103)
- Fix Swarm service updates failing due to "file exists" errors when a VIP IP alias already exists on the LB endpoint interface. [moby/moby#51657](https://github.com/moby/moby/pull/51657)
- Fix Swarm tasks being rejected when their image could not be pulled from the registry but was already present on the node. [moby/moby#53212](https://github.com/moby/moby/pull/53212)
- Improve the error returned when a container hostname exceeds Linux's 64-byte limit. [moby/moby#53121](https://github.com/moby/moby/pull/53121)
- Prevent live-restored volumes from retaining active mount references when containers exit during daemon startup. [moby/moby#53115](https://github.com/moby/moby/pull/53115)
- Suppress the “No such container” error when `docker rm --force` succeeds for a nonexistent container. [docker/cli#7110](https://github.com/docker/cli/pull/7110)

### Packaging updates

- Update Go runtime to [1.26.5](https://go.dev/doc/devel/release#go1.26.5). [docker/cli#7087](https://github.com/docker/cli/pull/7087)
- Update BuildKit to [v0.32.0](https://github.com/moby/buildkit/releases/tag/v0.32.0). [moby/moby#53234](https://github.com/moby/moby/pull/53234)
- Update containerd (static binaries) to [v2.3.3](https://github.com/containerd/containerd/releases/tag/v2.3.3). [moby/moby#53050](https://github.com/moby/moby/pull/53050)
- Update runc (in static binaries) to [v1.4.3](https://github.com/opencontainers/runc/releases/tag/v1.4.3). [moby/moby#50960](https://github.com/moby/moby/pull/50960)

## 29.6.2

{{< release-date date="2026-07-16" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.6.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.6.2)
- [moby/moby, 29.6.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.6.2)

### Security

This release includes fixes for multiple security vulnerabilities affecting Docker Engine.

- **CVE-2026-15793**: Git source checkout from a bundle file could lead to command injection. [GHSA-hw3h-2gp9-cxpv](https://github.com/moby/buildkit/security/advisories/GHSA-hw3h-2gp9-cxpv)
- **CVE-2026-15792**: Incorrect parameters sent from a frontend could cause a panic. [GHSA-qx3x-mv6r-52p6](https://github.com/moby/buildkit/security/advisories/GHSA-qx3x-mv6r-52p6)
- **CVE-2026-15791**: An LLB file operation could be tricked into removing the contents of the `/tmp` directory. [GHSA-32pv-7hq5-qhwq](https://github.com/moby/buildkit/security/advisories/GHSA-32pv-7hq5-qhwq)
- **CVE-2026-15789**: A malicious client could bypass destination directory validation when uploading local sources. [GHSA-g2h8-426c-7976](https://github.com/moby/buildkit/security/advisories/GHSA-g2h8-426c-7976)
- **CVE-2026-15788**: A WCOW cache mount source selector could resolve NTFS junctions outside of the cache root. [GHSA-388v-wmr2-g2v2](https://github.com/moby/buildkit/security/advisories/GHSA-388v-wmr2-g2v2)

### Packaging updates

- Update containerd (static binaries) to [v2.2.6](https://github.com/containerd/containerd/releases/tag/v2.2.6). [moby/moby#53051](https://github.com/moby/moby/pull/53051)
- Update Go runtime to [1.26.5](https://go.dev/doc/devel/release#go1.26.5). [moby/moby#53027](https://github.com/moby/moby/pull/53027)

### Rootless

- Update RootlessKit to [v3.0.2](https://github.com/rootless-containers/rootlesskit/releases/tag/v3.0.2). [moby/moby#53054](https://github.com/moby/moby/pull/53054)

## 29.6.1

{{< release-date date="2026-06-26" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.6.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.6.1)
- [moby/moby, 29.6.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.6.1)

### Security

This release includes fixes for multiple security vulnerabilities affecting Docker Engine.

- A malicious image could supply a malicious `/etc/passwd` or `/etc/group`-style file causing excessive memory consumption, potentially resulting in process termination due to Out Of Memory (OOM) conditions. [GHSA-mjcv-p78q-w5fw](https://github.com/moby/sys/security/advisories/GHSA-mjcv-p78q-w5fw), [GHSA-jpcc-p29g-p8mq](https://github.com/containerd/containerd/security/advisories/GHSA-jpcc-p29g-p8mq), [GHSA-72x6-4j93-7w86](https://github.com/moby/buildkit/security/advisories/GHSA-72x6-4j93-7w86)
- A custom frontend could send a crafted build request that disabled Seccomp and AppArmor protections for the build container, even if the user did not explicitly allow the security.insecure entitlement. Other security measures, like Linux capabilities were still applied to these containers. [GHSA-7236-3392-c5c6](https://github.com/moby/buildkit/security/advisories/GHSA-7236-3392-c5c6)

### Bug fixes and enhancements

- Update containerd (static binaries) to [v2.2.5](https://github.com/containerd/containerd/releases/tag/v2.2.5). [moby/moby#52950](https://github.com/moby/moby/pull/52950)

### Packaging updates

- Update BuildKit to [v0.31.1](https://github.com/moby/buildkit/releases/tag/v0.31.1). [moby/moby#52954](https://github.com/moby/moby/pull/52954)

## 29.6.0

{{< release-date date="2026-06-18" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.6.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.6.0)
- [moby/moby, 29.6.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.6.0)

### New

- `POST /containers/{id}/update` now supports per-device blkio resource settingss. [moby/moby#52651](https://github.com/moby/moby/pull/52651)
- Add `GET /images/{name}/attestations` endpoint to retrieve in-toto attestation statements (such as SLSA provenance and SPDX SBOM) attached to an image. Supports optional platform selection, predicate type filtering, and a statement query parameter for verbatim statement bodies.

### Bug fixes and enhancements

- `docker image push` now respects `NO_COLOR`. [docker/cli#6957](https://github.com/docker/cli/pull/6957)
- containerd image store: Fix `docker system prune` to include unpacked image data when reporting reclaimed space. [moby/moby#52905](https://github.com/moby/moby/pull/52905)
- Fix `docker system df` image size reporting to count only snapshots directly used by images. [moby/moby#52901](https://github.com/moby/moby/pull/52901)
- Fix a bug where registry authentication failures during worker image pulls were reported as a misleading “No such image” error. [moby/moby#52698](https://github.com/moby/moby/pull/52698)
- Fix default BuildKit GC policy to prune reproducible cache types as intended. [moby/moby#52814](https://github.com/moby/moby/pull/52814)
- Fix explicit file modes being filtered by the daemon umask, including `COPY --chmod` permissions. [moby/moby#52892](https://github.com/moby/moby/pull/52892)
- Fix image selection with the containerd image store on amd64 hosts when images provide amd64 variant-specific manifests. [moby/moby#52773](https://github.com/moby/moby/pull/52773)
- The `--password` flag on `docker login` now accepts `-` to pass the password through STDIN as alternative to `--password-stdin`. [docker/cli#7029](https://github.com/docker/cli/pull/7029)

### Packaging updates

- Update runc (in static binaries) to [v1.3.6](https://github.com/opencontainers/runc/releases/tag/v1.3.6). [moby/moby#52883](https://github.com/moby/moby/pull/52883)
- Update BuildKit to [v0.31.0](https://github.com/moby/buildkit/releases/tag/v0.31.0). [moby/moby#52904](https://github.com/moby/moby/pull/52904)

### Networking

- Allow the nftables firewall mode to be used with a daemon that is linked against libnftables when the `nft` command is not installed on the system. [moby/moby#52820](https://github.com/moby/moby/pull/52820)
- Don't publish container ports on host ports listed in `net.ipv4.ip_local_reserved_ports` when dynamically allocating ports. [moby/moby#52818](https://github.com/moby/moby/pull/52818)
- Fix a race condition in overlay network bulk sync that caused ~30s DNS resolution delays on newly joined swarm nodes. [moby/moby#52862](https://github.com/moby/moby/pull/52862)
- Mitigate a crash in libnftables when using nftables as the firewall backend by changing the default build option to execute the `nft` command instead. Users building dockerd from source can opt into linking against libnftables by building with the `libnftables` build tag. [moby/moby#52886](https://github.com/moby/moby/pull/52886)

### Rootless

- Silence the spurious warning "IPv4 forwarding is disabled". [moby/moby#52742](https://github.com/moby/moby/pull/52742)

### Deprecations

- The Engine now returns a deprecation warning when a container connected to the default bridge is created with links specified. [moby/moby#47427](https://github.com/moby/moby/pull/47427)

## 29.5.3

{{< release-date date="2026-06-03" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.5.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.5.3)
- [moby/moby, 29.5.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.5.3)

### Bug fixes and enhancements

- Reduce `docker system df` errors when images are pruned at the same time with the containerd image store. [moby/moby#52672](https://github.com/moby/moby/pull/52672)

### Packaging updates

- Update containerd (static binaries only) to [v2.2.4](https://github.com/containerd/containerd/releases/tag/v2.2.4). [moby/moby#52683](https://github.com/moby/moby/pull/52683)
- Update Go runtime to [1.26.4](https://go.dev/doc/devel/release#go1.26.4). [moby/moby#52753](https://github.com/moby/moby/pull/52753), [docker/cli#7025](https://github.com/docker/cli/pull/7025)

### Rootless

- Fix AWS IMDS access with `gvisor-tap-vsock` and UDP port forwarding for non-loopback clients. [moby/moby#52710](https://github.com/moby/moby/pull/52710)
- Fix installation of plugins that require host networking. [moby/moby#52735](https://github.com/moby/moby/pull/52735)
- Update RootlessKit to [v3.0.1](https://github.com/rootless-containers/rootlesskit/releases/tag/v3.0.1). [moby/moby#52710](https://github.com/moby/moby/pull/52710)

## 29.5.2

{{< release-date date="2026-05-20" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.5.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.5.2)
- [moby/moby, 29.5.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.5.2)

### Bug fixes and enhancements

- Fix a regression introduced in 29.5.1 where `docker cp` failed with "mkdirat: file exists" when a container had a bind mount whose target traversed an in-container symlink (e.g. `/var/run -> /run`). [moby/moby#52655](https://github.com/moby/moby/pull/52655)

## 29.5.1

{{< release-date date="2026-05-18" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.5.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.5.1)
- [moby/moby, 29.5.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.5.1)

### Security

This release includes fixes for multiple security vulnerabilities affecting Docker Engine.

- **CVE-2026-41567** Fix a vulnerability in `docker cp` where archive decompression binaries (e.g. `xz`, `unpigz`) were resolved via `PATH` inside the container filesystem while running as host root, allowing a malicious container to execute arbitrary binaries with host root privileges.  
  [GHSA-x86f-5xw2-fm2r](https://github.com/moby/moby/security/advisories/GHSA-x86f-5xw2-fm2r)

- **CVE-2026-41568** Fix a TOCTOU vulnerability in `docker cp` that allowed a container process to create files or directories at arbitrary locations on the host filesystem.  
  [GHSA-vp62-88p7-qqf5](https://github.com/moby/moby/security/advisories/GHSA-vp62-88p7-qqf5)

- **CVE-2026-42306** Fix a TOCTOU vulnerability in `docker cp` that allowed a container process to redirect a bind mount to an arbitrary location on the host filesystem.  
  [GHSA-rg2x-37c3-w2rh](https://github.com/moby/moby/security/advisories/GHSA-rg2x-37c3-w2rh)

### Networking

- Fix UDP conntrack entries not being deleted when not bound to a specific IP address. [moby/moby#52640](https://github.com/moby/moby/pull/52640)

## 29.5.0

{{< release-date date="2026-05-14" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.5.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.5.0)
- [moby/moby, 29.5.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.5.0)

> [!NOTE]
> Rootless: `gvisor-tap-vsock` is now the new default rootless network driver and should be preferred over `slirp4netns` which is no longer installed via Docker packaging.

### New

- Rootless: Add new default  `gvisor-tap-vsock` network driver. [moby/moby#52319](https://github.com/moby/moby/pull/52319)
- Enable private time namespace for containers by default on supported kernels. [moby/moby#52326](https://github.com/moby/moby/pull/52326)
- The `local` logging driver now has support for custom attributes, adding support for the `label`, `label-regex`, `env`, `env-regex`, and `tag` log options. [moby/moby#52348](https://github.com/moby/moby/pull/52348)
- Windows: The daemon now supports listening on a Unix socket (`-H unix://...`), with optional group-based access control via `--group`. [moby/moby#52365](https://github.com/moby/moby/pull/52365)

### Security

- CVE-2026-32288: Fix a denial of service where pulling a maliciously crafted image could cause the daemon to allocate unbounded memory when processing sparse tar archives. [GHSA-x4jj-h2v8-hqqv](https://github.com/advisories/GHSA-x4jj-h2v8-hqqv). [moby/moby#52478](https://github.com/moby/moby/pull/52478)

### Bug fixes and enhancements

- `docker ps --format` now supports a `.HealthStatus` placeholder to print container health state (`starting`, `healthy`, `unhealthy`) as a dedicated field. [docker/cli#6913](https://github.com/docker/cli/pull/6913)
- Add "time-namespaces" feature flag to disable time-namespaces. [moby/moby#52577](https://github.com/moby/moby/pull/52577)
- containerd integration: Fix auth token requests ignoring per-host TLS settings (custom CAs, insecure-registries). [moby/moby#52600](https://github.com/moby/moby/pull/52600)
- Daemon reload events now signify that the daemon reload has fully completed. [moby/moby#52589](https://github.com/moby/moby/pull/52589)
- Expose diagnostic data about userland proxy in `docker info`. [moby/moby#52321](https://github.com/moby/moby/pull/52321)
- Fix `docker image ls --filter reference=...` (`GET /images/json`) to also match fully qualified canonical image names (e.g. `docker.io/library/alpine`), not only the familiar short form. [moby/moby#52333](https://github.com/moby/moby/pull/52333)
- Fix a bug where leaving an autolock-enabled swarm could leave orphaned state, causing subsequent swarm init to fail with "Swarm is encrypted and needs to be unlocked". [moby/moby#52479](https://github.com/moby/moby/pull/52479)
- Fix an issue where logging errors appeared as empty strings in the daemon log instead of the message that failed to write. [moby/moby#52442](https://github.com/moby/moby/pull/52442)
- Fix incorrect SHARED SIZE and UNIQUE SIZE reporting in `docker system df -v` by including shared content blobs in size calculation. [moby/moby#52482](https://github.com/moby/moby/pull/52482)
- Fix support for CDI specifications that request additional group IDs. [moby/moby#52579](https://github.com/moby/moby/pull/52579)
- Fix volume subpath file mounts over an existing file in the image failing container creation with "not a directory". [moby/moby#52584](https://github.com/moby/moby/pull/52584)
- Sort labels in `volume`, `network`, `config`, and `secret` formatters for deterministic output. [docker/cli#6954](https://github.com/docker/cli/pull/6954)
- Swarm: Prevent corruption of Raft snapshots when swarm state is large. [moby/moby#52441](https://github.com/moby/moby/pull/52441)

### Packaging updates

- Update BuildKit to [v0.30.0](https://github.com/moby/buildkit/releases/tag/v0.30.0). [moby/moby#52618](https://github.com/moby/moby/pull/52618)
- Update Go runtime to [1.26.3](https://go.dev/doc/devel/release#go1.26.3). [moby/moby#52572](https://github.com/moby/moby/pull/52572), [docker/cli#6967](https://github.com/docker/cli/pull/6967)

### Networking

- Fix conntrack entries being incorrectly deleted for UDP containers sharing the same port on different IPs when one container is restarted. [moby/moby#52423](https://github.com/moby/moby/pull/52423)
- Fix stale VIP DNS records for swarm service network aliases not being removed during rolling updates. [moby/moby#52236](https://github.com/moby/moby/pull/52236)
- Fix the userland proxy silently dropping UDP datagrams when a previous write to an unavailable backend left a stale ECONNREFUSED error on the socket. [moby/moby#52483](https://github.com/moby/moby/pull/52483)
- Rootless: Properly support `--net=host` and localhost registries. [moby/moby#47103](https://github.com/moby/moby/pull/47103)

### Rootless

- Update RootlessKit to [v3.0.0](https://github.com/rootless-containers/rootlesskit/releases/tag/v3.0.0). [moby/moby#52319](https://github.com/moby/moby/pull/52319)

### Go SDK

- cli/config/configfile: `GetAuthConfig`, `GetCredentialsStore`: normalize hostname when resolving auth. [docker/cli#6846](https://github.com/docker/cli/pull/6846)

### Deprecations

- cli/command/image/build: remove deprecated `DefaultDockerfileName` const. [docker/cli#6737](https://github.com/docker/cli/pull/6737)
- cli/command/image/build: remove deprecated `DetectArchiveReader` util. [docker/cli#6737](https://github.com/docker/cli/pull/6737)
- cli/command/image/build: remove deprecated `IsArchive` utility. [docker/cli#6737](https://github.com/docker/cli/pull/6737)
- cli/command/image/build: remove deprecated `ResolveAndValidateContextPath` util. [docker/cli#6737](https://github.com/docker/cli/pull/6737)
- cli/command/image/build: remove deprecated `WriteTempDockerfile` util. [docker/cli#6737](https://github.com/docker/cli/pull/6737)

## 29.4.3

{{< release-date date="2026-05-06" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.4.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.4.3)
- [moby/moby, 29.4.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.4.3)

### Security

- **CVE-2026-31431**: Replace the socketcall(2) seccomp deny that broke 32-bit programs with targeted AppArmor (deny network alg) and SELinux (alg_socket) rules that block AF_ALG at the LSM layer, covering both socket(2) and socketcall(2) paths without disrupting legitimate 32-bit workloads. [moby/moby#52537](https://github.com/moby/moby/pull/52537)

  On SELinux-based systems, the SELinux mitigation requires the daemon to be configured with `selinux-enabled: true` (via `daemon.json` or the `--selinux-enabled` CLI flag). This option is not enabled by default.

- Fix the default AppArmor profile not being updated on daemon restart, requiring a system reboot to pick up profile changes from daemon upgrades. [moby/moby#52537](https://github.com/moby/moby/pull/52537)

## 29.4.2

{{< release-date date="2026-05-01" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.4.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.4.2)
- [moby/moby, 29.4.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.4.2)

### Security

This release includes hardening for **CVE-2026-31431**.

- Block `AF_ALG` sockets and the `socketcall(2)` multiplexer in the default seccomp profile to prevent in-container privilege escalation via the kernel crypto API ("Copy Fail"). [moby/moby#52501](https://github.com/moby/moby/pull/52501)

### Known issues

The hardening can break 32-bit programs and i386 images, including SteamCMD and some Wine-based workloads. [moby/moby#52506](https://github.com/moby/moby/issues/52506)

#### Workaround

> [!WARNING]
> Don't use `--security-opt seccomp=unconfined` to work around this issue.  
> Don't use the `seccomp/v0.2.0` profile.

If you need a workaround, use the `seccomp/v0.2.1` profile from `moby/profiles`.
Make sure you use a kernel that includes the fix for CVE-2026-31431.

This profile unblocks `socketcall` while keeping `AF_ALG` blocked for `socket`.

> [!IMPORTANT]
> Use this workaround only for containers that require it.  
> Containers that use this profile can still exploit CVE-2026-31431 through the `socketcall` syscall.

Download the `seccomp/v0.2.1` profile:

```console
$ curl -fsSL https://raw.githubusercontent.com/moby/profiles/refs/tags/seccomp/v0.2.1/seccomp/default.json \
  -o /etc/docker/seccomp-profile-v0.2.1.json
```

Use one of these options. You don't need both.

1. To use the profile for a specific container when you control the `docker run` command, use `--security-opt`:

  ```console
  $ docker run --security-opt seccomp=<path> ...
  ```

2. To use the profile as the default for containers created by the daemon, add `seccomp-profile` to your `daemon.json`:

  ```json
  {
    "seccomp-profile": "/etc/docker/seccomp-profile-v0.2.1.json"
  }
  ```

## 29.4.1

{{< release-date date="2026-04-20" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.4.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.4.1)
- [moby/moby, 29.4.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.4.1)

### Bug fixes and enhancements

- containerd image store: Fix `docker image prune --filter label!=key=value` incorrectly skipping images that don't have the specified label. [moby/moby#52338](https://github.com/moby/moby/pull/52338)
- Fix `--log-opt "tag={{.ImageID}}"` not stripping the digest's algorithm. [moby/moby#52343](https://github.com/moby/moby/pull/52343)
- Fix intermittent container start failures (`EBUSY` on secrets/configs remount) on busy Swarm nodes by retrying the read-only remount. [moby/moby#52235](https://github.com/moby/moby/pull/52235)

### Packaging updates

- Update containerd (static binaries only) to [v2.2.3](https://github.com/containerd/containerd/releases/tag/v2.2.3). [moby/moby#52360](https://github.com/moby/moby/pull/52360)
- Update Go runtime to [1.26.2](https://go.dev/doc/devel/release#go1.26.2). [docker/cli#6920](https://github.com/docker/cli/pull/6920), [moby/moby#52329](https://github.com/moby/moby/pull/52329)

### Networking

- if a container has an IPv4-only or an IPv6-only endpoint with higher "gateway priority" than a dual stack endpoint, the single stack endpoint will now be used as the default gateway for its address family. [moby/moby#52328](https://github.com/moby/moby/pull/52328)


## 29.4.0

{{< release-date date="2026-04-07" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.4.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.4.0)
- [moby/moby, 29.4.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.4.0)

### Bug fixes and enhancements

- docker cp: report both content size and transferred size. [docker/cli#6800](https://github.com/docker/cli/pull/6800)
- Fix `docker stats --all` still showing containers that were removed. [docker/cli#6863](https://github.com/docker/cli/pull/6863)
- Fix a rare bug that could cause containers to become unremovable. [moby/moby#51724](https://github.com/moby/moby/pull/51724)
- Fixed privileged containers losing their explicit AppArmor profile (`--security-opt apparmor=<profile>`) after a container restart. [moby/moby#52215](https://github.com/moby/moby/pull/52215)
- Improved duplicate container-exit handling by using live containerd task state (not timestamps). [moby/moby#52156](https://github.com/moby/moby/pull/52156)
- Improved image pull and push performance by enabling HTTP keep-alive for registry connections, avoiding redundant TCP and TLS handshakes. [moby/moby#52198](https://github.com/moby/moby/pull/52198)
- shell completions: add shell completion for `docker rm --link` and exclude legacy links for container names. [docker/cli#6872](https://github.com/docker/cli/pull/6872)
- shell completions: don't provide completions that were already used. [docker/cli#6871](https://github.com/docker/cli/pull/6871)
- Update runc (in static binaries) to [v1.3.5](https://github.com/opencontainers/runc/releases/tag/v1.3.5). [moby/moby#52244](https://github.com/moby/moby/pull/52244)
- Windows: Fix `DOCKER_TMPDIR` not being respected. [moby/moby#52181](https://github.com/moby/moby/pull/52181)

### Packaging updates

- Update BuildKit to [v0.29.0](https://github.com/moby/buildkit/releases/tag/v0.29.0). [moby/moby#52272](https://github.com/moby/moby/pull/52272)

### Networking

- Prevent a daemon crash during startup after upgrading if a container config containers a malformed IP-address. [moby/moby#52275](https://github.com/moby/moby/pull/52275)

### Go SDK

- cli/streams: Out, In: preserve original os.File when available. [docker/cli#6906](https://github.com/docker/cli/pull/6906)
- Update minimum go version to go1.25. [docker/cli#6897](https://github.com/docker/cli/pull/6897)

### Deprecations

- Go SDK: cli-plugins/hooks: deprecate `HookMessage ` and rename to `cli-plugins/hooks.Response`. [docker/cli#6859](https://github.com/docker/cli/pull/6859)
- Go SDK: cli-plugins/hooks: deprecate `HookType` and rename to `cli-plugins/hooks.ResponseType`. [docker/cli#6859](https://github.com/docker/cli/pull/6859)
- Go SDK: cli-plugins/manager: deprecate `HookPluginData` and move to `cli-plugins/hooks.Request`. [docker/cli#6859](https://github.com/docker/cli/pull/6859)

## 29.3.1

{{< release-date date="2026-03-25" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.3.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.3.1)
- [moby/moby, 29.3.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.3.1)

### Security

This release includes fixes for multiple security vulnerabilities affecting Docker Engine and related components.

- **CVE-2026-34040** Fix an authorization bypass in AuthZ plugins that could allow authorization plugins to be bypassed under specific conditions.
  [GHSA-x744-4wpc-v9h2](https://github.com/moby/moby/security/advisories/GHSA-x744-4wpc-v9h2)

- **CVE-2026-33997** Fix a flaw in `docker plugin install` where privilege validation could be partially bypassed, potentially leading to unauthorized privilege escalation.
  [GHSA-pxq6-2prw-chj9](https://github.com/moby/moby/security/advisories/GHSA-pxq6-2prw-chj9)

- **CVE-2026-33748** Fix insufficient validation of Git URL `#ref:subdir` fragments in BuildKit, which could allow access to files outside the intended repository scope.
  [GHSA-4vrq-3vrq-g6gg](https://github.com/moby/buildkit/security/advisories/GHSA-4vrq-3vrq-g6gg)

- **CVE-2026-33747** Fix a vulnerability in BuildKit where an untrusted frontend could cause files to be written outside the BuildKit state directory.
  [GHSA-3c29-8rgm-jvjj](https://github.com/moby/buildkit/security/advisories/GHSA-4c29-8rgm-jvjj)

### Bug fixes and enhancements

- Fix a daemon crash during docker build if `.dockerignore` contained an invalid pattern. [moby/moby#52214](https://github.com/moby/moby/pull/52214)
- Fix a panic when the containerd client uses a closed stream. [moby/moby#52211](https://github.com/moby/moby/pull/52211)

### Packaging updates

- Update containerd (static binaries) to [v2.2.2](https://github.com/containerd/containerd/releases/tag/v2.2.2). [moby/moby#52213](https://github.com/moby/moby/pull/52213)
- Update Go runtime to [1.25.8](https://go.dev/doc/devel/release#go1.25.8). [moby/moby#52210](https://github.com/moby/moby/pull/52210), [docker/cli#6883](https://github.com/docker/cli/pull/6883)

### Go SDK

- Add missing build-tag, which could cause `cannot range over 10 (untyped int constant)`  when importing the `cli/command` package. [docker/cli#6884](https://github.com/docker/cli/pull/6884)

## 29.3.0

{{< release-date date="2026-03-05" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.3.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.3.0)
- [moby/moby, 29.3.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.3.0)

### New

- Add `bind-create-src` option to `--mount` flag for bind mounts. [docker/cli#6792](https://github.com/docker/cli/pull/6792)
- CLI plugin hooks now fire on command failure (not just success), and plugins can use "error-hooks" to show hints only when commands fail. [docker/cli#6794](https://github.com/docker/cli/pull/6794)
- Lower minimum API version from v1.44 to v1.40 (Docker 19.03). [moby/moby#52067](https://github.com/moby/moby/pull/52067)

### Packaging updates

- Update BuildKit to [v0.28.0](https://github.com/moby/buildkit/releases/tag/v0.28.0). [moby/moby#52135](https://github.com/moby/moby/pull/52135)

### Networking

- Fix DNS config corruption on daemon reload. [moby/moby#52060](https://github.com/moby/moby/pull/52060)

### API

- `POST /networks/{id}/connect` now correctly applies the `MacAddress` field in `EndpointSettings`. This field was added in API v1.44, but was previously ignored. [moby/moby#52040](https://github.com/moby/moby/pull/52040)
- `GET /images/json` now supports an `identity` query parameter. When set, the response includes manifest summaries and may include an `Identity` field for each manifest with trusted identity and origin information. [moby/moby#52030](https://github.com/moby/moby/pull/52030)

### Bug fixes and enhancements

- The `--gpus` option now uses CDI-based injection for AMD GPUs. [moby/moby#52048](https://github.com/moby/moby/pull/52048)
- Add `sd_notify` ["RELOADING"](https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html#RELOADING=1) notifications when signalling the daemon to reload its configuration. [moby/moby#52041](https://github.com/moby/moby/pull/52041)
- Send `sd_notify` ["READY"](https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html#READY=1) and ["STOPPING"](https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html#STOPPING=1) synchronously to make sure they are sent before we proceed. [moby/moby#52041](https://github.com/moby/moby/pull/52041)
- Add support for the systemd 253 `Type=notify-reload` service reload protocol. [moby/moby#52041](https://github.com/moby/moby/pull/52041)
- Don't log "failed to determine if container is already mounted" warnings for stopped containers during startup. [moby/moby#52076](https://github.com/moby/moby/pull/52076)
- Fix `docker system prune` failing with "rw layer snapshot not found" when a container is concurrently removed. [moby/moby#52090](https://github.com/moby/moby/pull/52090)
- Fix a panic when running `docker top` on a non-running Windows container. [moby/moby#52025](https://github.com/moby/moby/pull/52025)
- Fix a regression in v29.2.0 that prevented registering the dockerd service on Windows if system requirements were not yet installed. [moby/moby#52006](https://github.com/moby/moby/pull/52006)
- Fix shared mount detection for paths mounted multiple times, which caused "not a shared mount" errors when using bind propagation. [moby/moby#51787](https://github.com/moby/moby/pull/51787)
- Fix spurious "ShouldRestart failed" warning on shutdown. [moby/moby#52079](https://github.com/moby/moby/pull/52079)
- Preserve leading and trailing whitespace when storing registry passwords. [docker/cli#6784](https://github.com/docker/cli/pull/6784)
- Prevent logging "not found" warnings when calculating volume sizes. [moby/moby#52018](https://github.com/moby/moby/pull/52018)
- Update Go runtime to [1.25.7](https://go.dev/doc/devel/release#go1.25.7). [moby/moby#52003](https://github.com/moby/moby/pull/52003), [docker/cli#6780](https://github.com/docker/cli/pull/6780)

## 29.2.1

{{< release-date date="2026-02-02" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.2.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.2.1)
- [moby/moby, 29.2.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.2.1)

### Bug fixes and enhancements

- Update BuildKit to [v0.27.1](https://github.com/moby/buildkit/releases/tag/v0.27.1). [moby/moby#51962](https://github.com/moby/moby/pull/51962)
- Fix `docker system df` failing when run concurrently with `docker system prune`. [moby/moby#51979](https://github.com/moby/moby/pull/51979)
- Fix daemon handling of duplicate container exit events to avoid repeated cleanup and state transitions. [moby/moby#51925](https://github.com/moby/moby/pull/51925)
- Fix panic after failed daemon initialization. [moby/moby#51943](https://github.com/moby/moby/pull/51943)
- Fix encrypted overlay networks not passing traffic to containers on v28 and older Engines. Encrypted overlay networks will no longer pass traffic to containers on v29.2.0 thru v29.0.0, v28.2.2, v25.0.14 or v25.0.13. [moby/moby#51951](https://github.com/moby/moby/pull/51951)
- Fix potential panic on `docker network prune`. [moby/moby#51966](https://github.com/moby/moby/pull/51966)

## 29.2.0

{{< release-date date="2026-01-26" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.2.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.2.0)
- [moby/moby, 29.2.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.2.0)

### New

- `docker info` now includes `NRI` section. [docker/cli#6710](https://github.com/docker/cli/pull/6710)
- Add experimental NRI support. [moby/moby#51711](https://github.com/moby/moby/pull/51711), [moby/moby#51712](https://github.com/moby/moby/pull/51712), [moby/moby#51675](https://github.com/moby/moby/pull/51675), [moby/moby#51674](https://github.com/moby/moby/pull/51674), [moby/moby#51636](https://github.com/moby/moby/pull/51636), [moby/moby#51634](https://github.com/moby/moby/pull/51634)
- New `Identity` field has been added to the inspect endpoint to show trusted origin information about the image. This includes build ref for locally built images, remote registry repository for pulled images, and verified signature information for images that contain a valid signed provenance attestation. [moby/moby#51737](https://github.com/moby/moby/pull/51737)

### Bug fixes and enhancements

- Improve validation of `--detach-keys` command-line options. [docker/cli#6742](https://github.com/docker/cli/pull/6742)
- Prevent a potential panic on daemon shutdown after an incomplete initialization. [moby/moby#51797](https://github.com/moby/moby/pull/51797)
- Remove restriction on anonymous read-only volumes. [moby/moby#51682](https://github.com/moby/moby/pull/51682)
- The `--validate` flag on dockerd now also verifies system requirements, allowing for system requirements to be checked before starting the daemon. [moby/moby#51868](https://github.com/moby/moby/pull/51868)
- Handle `--gpus` requests for NVIDIA devices using CDI if possible. [moby/moby#50228](https://github.com/moby/moby/pull/50228)

### Packaging updates

- Update BuildKit to [v0.27.0](https://github.com/moby/buildkit/releases/tag/v0.27.0). [moby/moby#51886](https://github.com/moby/moby/pull/51886)
- Update containerd (static binaries only) to [v2.2.1](https://github.com/containerd/containerd/releases/tag/v2.2.1). [moby/moby#51765](https://github.com/moby/moby/pull/51765)

### Rootless

- Rootless: Consider `$XDG_CONFIG_HOME/cdi` and `$XDG_RUNTIME_DIR/cdi` when looking for CDI devices. [moby/moby#51624](https://github.com/moby/moby/pull/51624)
- Update RootlessKit to [v2.3.6](https://github.com/rootless-containers/rootlesskit/releases/tag/v2.3.6). [moby/moby#51757](https://github.com/moby/moby/pull/51757)

### API

- Natively support gRPC on the listening socket. [moby/moby#50744](https://github.com/moby/moby/pull/50744)

### Go SDK

- cli/command: add WithAPIClientOptions option. [docker/cli#6740](https://github.com/docker/cli/pull/6740)

### Deprecations

- Remove `%PROGRAMDATA%\Docker\cli-plugins` from the list of paths used for CLI plugins on Windows. This path was present for backward compatibility with old installation, but replaced by `%ProgramFiles%\Docker\cli-plugins`. [docker/cli#6713](https://github.com/docker/cli/pull/6713)

## 29.1.5

{{< release-date date="2026-01-16" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.1.5 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.1.5)
- [moby/moby, 29.1.5 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.1.5)

### Packaging updates

- Update Go runtime to [1.25.6](https://go.dev/doc/devel/release#go1.25.6). [moby/moby#51860](https://github.com/moby/moby/pull/51860), [docker/cli#6750](https://github.com/docker/cli/pull/6750)

### Networking

- Fixed a regression where established network connections could be disrupted during a container's shutdown grace period. [moby/moby#51843](https://github.com/moby/moby/pull/51843)

## 29.1.4

{{< release-date date="2026-01-08" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.1.4 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.1.4)
- [moby/moby, 29.1.4 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.1.4)

### Bug fixes and enhancements

- Fix `docker run --network none` panic on Windows. [moby/moby#51830](https://github.com/moby/moby/pull/51830)
- Fix image mounts failing with "file name too long" for long mount paths. [moby/moby#51829](https://github.com/moby/moby/pull/51829)
- Fix potential creation of orphaned overlay2 layers. [moby/moby#51826](https://github.com/moby/moby/pull/51826), [moby/moby#51824](https://github.com/moby/moby/pull/51824)

### Packaging updates

- Update BuildKit to [v0.26.3](https://github.com/moby/buildkit/releases/tag/v0.26.3). [moby/moby#51821](https://github.com/moby/moby/pull/51821)

## 29.1.3

{{< release-date date="2025-12-12" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.1.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.1.3)
- [moby/moby, 29.1.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.1.3)

### Bug fixes and enhancements

- Add shell completion for `docker stack deploy --compose-file`. [docker/cli#6690](https://github.com/docker/cli/pull/6690)
- containerd image store: Fix a bug causing `docker build` to ignore the explicitly set `unpack` image exporter option. [moby/moby#51514](https://github.com/moby/moby/pull/51514)
- Fix `docker image ls` dangling image handling. [docker/cli#6704](https://github.com/docker/cli/pull/6704)
- Fix a bug that could cause the Engine to leave containers with autoremove set in 'dead' state on shutdown, and never reclaim them. [moby/moby#51693](https://github.com/moby/moby/pull/51693)
- Fix build on i386. [moby/moby#51528](https://github.com/moby/moby/pull/51528)
- Fix explicit graphdriver configuration (`"storage-driver"`) being treated as containerd snapshotter when prior graphdriver state exists. [moby/moby#51516](https://github.com/moby/moby/pull/51516)
- Fix potential creation of orphaned overlay2 layers. [moby/moby#51703](https://github.com/moby/moby/pull/51703)

### Networking

- Allow creation of a container with a specific IP address when its networks were not configured with a specific subnet. [moby/moby#51583](https://github.com/moby/moby/pull/51583)
- Don't crash when starting a container created via the API before upgrade to v29.1.2, with `PublishAll` and a nil `PortBindings` map. [moby/moby#51691](https://github.com/moby/moby/pull/51691)
- Fix a bug preventing DNS resolution of containers attached to non swarm-scoped networks once the node has joined a Swarm cluster. [moby/moby#51515](https://github.com/moby/moby/pull/51515)
- Fix an issue that caused daemon crash when using a remote network driver plugin. [moby/moby#51558](https://github.com/moby/moby/pull/51558)
- Fix an issue that could lead to an "endpoint not found" error when creating a container with multiple network connections, when one of the networks is non-internal but does not have its own external IP connectivity. [moby/moby#51538](https://github.com/moby/moby/pull/51538)
- Fix an issue that prevented rootless Docker from starting on a host with IPv6 disabled. [moby/moby#51543](https://github.com/moby/moby/pull/51543)
- Return an error when a container is created with a port-mapping pointing to container port 0. [moby/moby#51695](https://github.com/moby/moby/pull/51695)

## 29.1.2

{{< release-date date="2025-12-02" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.1.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.1.2)
- [moby/moby, 29.1.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.1.2)

### Security

- Update Go runtime to [1.25.5](https://go.dev/doc/devel/release#go1.25.5). [moby/moby#51648](https://github.com/moby/moby/pull/51648), [docker/cli#6688](https://github.com/docker/cli/pull/6688)
  - Fixes a potential DoS via excessive resource usage when formatting hostname validation errors [**CVE-2025-61729**](https://nvd.nist.gov/vuln/detail/CVE-2025-61729)
  - Fixes incorrect enforcement of excluded subdomain constraints for wildcard SANs, which could allow improperly trusted certificates [**CVE-2025-61727**](https://nvd.nist.gov/vuln/detail/CVE-2025-22874)

### Bug fixes and enhancements

- containerd image store: Fix `docker image inspect` failing to return available image data in case where not all distributable blobs are available locally. [moby/moby#51629](https://github.com/moby/moby/pull/51629)
- dockerd-rootless-setuptool.sh: fix `nsenter: no namespace specified`. [moby/moby#51622](https://github.com/moby/moby/pull/51622)
- Fix `docker system df` showing `N/A` for shared size and unique size when using graph-drivers as storage. [moby/moby#51631](https://github.com/moby/moby/pull/51631)

### Packaging updates

- Update runc (in static binaries) to [v1.3.4](https://github.com/opencontainers/runc/releases/tag/v1.3.4). [moby/moby#51633](https://github.com/moby/moby/pull/51633)

### Networking

- Fix a bug preventing port mappings in rootless mode when slirp4netns is used. [moby/moby#51616](https://github.com/moby/moby/pull/51616)
- Prevent a crash when making an API request with `HostConfig.PublishAllPorts` set (`-P`), and no port bindings. [moby/moby#51621](https://github.com/moby/moby/pull/51621)

## 29.1.1

{{< release-date date="2025-11-28" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.1.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.1.1)
- [moby/moby, 29.1.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.1.1)

### Networking

- Revert a PR breaking external DNS resolution on all custom bridge networks. [moby/moby#51615](https://github.com/moby/moby/pull/51615)

## 29.1.0

{{< release-date date="2025-11-27" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.1.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.1.0)
- [moby/moby, 29.1.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.1.0)

### Packaging updates

- Update BuildKit to [v0.26.1](https://github.com/moby/buildkit/releases/tag/v0.26.1). [moby/moby#51551](https://github.com/moby/moby/pull/51551)
- Update containerd binary to v2.2.0 (static binaries). [moby/moby#51271](https://github.com/moby/moby/pull/51271)

### Networking

- Do not overwrite user-modified `/etc/resolv.conf` across container restarts. [moby/moby#51507](https://github.com/moby/moby/pull/51507)
- fix `--publish-all` / `-P` for Windows containers. [moby/moby#51586](https://github.com/moby/moby/pull/51586)
- Fix an issue that prevented container restart or network reconnection when gateway configuration failed during container stop or network disconnect. [moby/moby#51592](https://github.com/moby/moby/pull/51592)
- Windows containers: don't display an IPv6-mapped IPv4 address in port mappings. For example, `[::ffff:0.0.0.0]:8080->80/tcp` instead of `0.0.0.0:8080->80/tcp`. [moby/moby#51587](https://github.com/moby/moby/pull/51587)

## 29.0.4

{{< release-date date="2025-11-24" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.0.4 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.0.4)
- [moby/moby, 29.0.4 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.0.4)

### Bug fixes and enhancements

- `docker image ls` no longer truncates the image names. [docker/cli#6675](https://github.com/docker/cli/pull/6675)

### Networking

- Allow creation of a container with a specific IP address when its networks were not configured with a specific subnet. [moby/moby#51583](https://github.com/moby/moby/pull/51583)

## 29.0.3

{{< release-date date="2025-11-24" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.0.3 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.0.3)
- [moby/moby, 29.0.3 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.0.3)

### Bug fixes and enhancements

- `docker version --format json`: restore top-level `BuildTime` field to use RFC3339Nano format. [docker/cli#6668](https://github.com/docker/cli/pull/6668)
- Fix `docker image ls` ignoring a custom `imageFormat` from `docker.json`. [docker/cli#6667](https://github.com/docker/cli/pull/6667)

### Networking

- Fix an issue that caused daemon crash when using a remote network driver plugin. [moby/moby#51558](https://github.com/moby/moby/pull/51558)

## 29.0.2

{{< release-date date="2025-11-17" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.0.2 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.0.2)
- [moby/moby, 29.0.2 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.0.2)

### Networking

- Fix an issue that could lead to an "endpoint not found" error when creating a container with multiple network connections, when one of the networks is non-internal but does not have its own external IP connectivity. [moby/moby#51538](https://github.com/moby/moby/pull/51538)
- Fix an issue that prevented rootless Docker from starting on a host with IPv6 disabled. [moby/moby#51543](https://github.com/moby/moby/pull/51543)

## 29.0.1

{{< release-date date="2025-11-14" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.0.1 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.0.1)
- [moby/moby, 29.0.1 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.0.1)

### Bug fixes and enhancements

- `docker image ls` no longer truncates the name width when output is redirect (e.g. for `grep`). [docker/cli#6656](https://github.com/docker/cli/pull/6656)
- `docker image ls` now considers the `NO_COLOR` environment variable for choosing the colored output. [docker/cli#6654](https://github.com/docker/cli/pull/6654)
- containerd image store: Fix a bug causing `docker build` to ignore the explicitly set `unpack` image exporter option. [moby/moby#51514](https://github.com/moby/moby/pull/51514)
- Fix a bug causing `docker image ls --all` to not show untagged/dangling images. [docker/cli#6657](https://github.com/docker/cli/pull/6657)
- Fix build on i386. [moby/moby#51528](https://github.com/moby/moby/pull/51528)
- Fix explicit graphdriver configuration (`"storage-driver"`) being treated as containerd snapshotter when prior graphdriver state exists. [moby/moby#51516](https://github.com/moby/moby/pull/51516)
- Fix output format of the `ApiVersion` and `MinApiVersion` fields in  `docker version --format=json` to align with previous versions. [docker/cli#6648](https://github.com/docker/cli/pull/6648)

### Networking

- Fix a bug preventing DNS resolution of containers attached to non swarm-scoped networks once the node has joined a Swarm cluster. [moby/moby#51515](https://github.com/moby/moby/pull/51515)

## 29.0.0

{{< release-date date="2025-11-10" >}}

For a full list of pull requests and changes in this release, refer to the relevant GitHub milestones:

- [docker/cli, 29.0.0 milestone](https://github.com/docker/cli/issues?q=is%3Aclosed+milestone%3A29.0.0)
- [moby/moby, 29.0.0 milestone](https://github.com/moby/moby/issues?q=is%3Aclosed+milestone%3A29.0.0)

> [!CAUTION]
> This release includes several breaking changes and deprecations. Review the release notes carefully before upgrading.

- Experimental support for nftables can now be enabled by setting Docker daemon's `firewall-backend` option to `nftables`. For more information, see [Docker Engine docs](https://docs.docker.com/engine/network/firewall-nftables/).
- containerd image store is now the default for **fresh installs**. This doesn't apply to daemons configured with `userns-remap` (see [moby#47377](https://github.com/moby/moby/issues/47377)).

### Breaking Changes

- The Go module `github.com/docker/docker` is deprecated in favor of `github.com/moby/moby/client` and `github.com/moby/moby/api`. The `github.com/moby/moby` module is considered an **internal implementation detail** - the only supported public modules are `client` and `api`.
  Starting with v29, releases are tagged with the `docker-` prefix (e.g., `docker-v29.0.0`). **This only affects Go module users and package maintainers.**
- The daemon now requires API version `v1.44` or later (Docker v25.0+).
- Debian armhf (32-bit) packages now target ARMv7 CPUs and will not work on ARMv6 devices.
- Official Raspbian (32-bit) packages are no longer provided. Use Debian arm64 packages for 64-bit devices, or Debian armhf packages for 32-bit ARMv7 devices.
- **cgroup v1 is deprecated.** Support continues until at least May 2029, but migrate to cgroup v2 as soon as possible. See [moby#51111](https://github.com/moby/moby/issues/51111).
- Docker Content Trust was removed from the Docker CLI. Can be built as a separate plugin: https://github.com/docker/cli/blob/v29.0.0/cmd/docker-trust/main.go

---

### New

- `docker image load` and `docker image save` now supports multiple platform selection via `--platform` flag (e.g., `docker image load --platform linux/amd64,linux/arm64 -i image.tar`). [docker/cli#6126](https://github.com/docker/cli/pull/6126)
- `docker image ls` now uses the new view (like `--tree` but collapsed) by default. [docker/cli#6566](https://github.com/docker/cli/pull/6566)
- `docker run --runtime <...>` is now supported on Windows. [moby/moby#50546](https://github.com/moby/moby/pull/50546)
- `GET /containers/json` now includes a `Health` field describing container healthcheck status. [moby/moby#50281](https://github.com/moby/moby/pull/50281)
- Add `device` entitlement to builder configuration. [moby/moby#50386](https://github.com/moby/moby/pull/50386)
- Add support for `memory-swap` and `memory-swappiness` flags to `docker service create` and `docker service update` commands. [docker/cli#6619](https://github.com/docker/cli/pull/6619)
- Allow Docker CLI to set the `GODEBUG` environment variable when the key-value pair (`"GODEBUG":"..."`) exists inside the Docker context metadata. [docker/cli#6371](https://github.com/docker/cli/pull/6371)

### Bug fixes and enhancements

- `docker image ls --tree` now sorts images alphabetically by name instead of by creation date. [docker/cli#6595](https://github.com/docker/cli/pull/6595)
- `docker image ls` no longer shows untagged images by default if no `--all` flag is provided. [docker/cli#6574](https://github.com/docker/cli/pull/6574)
- `docker save`: Fixed inconsistent tar member timestamps when exporting images with the overlay2 storage driver. [moby/moby#51365](https://github.com/moby/moby/pull/51365)
- Add a new log option for fluentd log driver (`fluentd-read-timeout`), which enables specifying read timeouts for reading acks from fluentd connections. [moby/moby#50249](https://github.com/moby/moby/pull/50249)
- Add image name completion for `docker images`. [docker/cli#6452](https://github.com/docker/cli/pull/6452)
- Add shell completion for `docker inspect` if a `--type` is set. [docker/cli#6444](https://github.com/docker/cli/pull/6444)
- Add shell completion for `docker plugin` subcommands. [docker/cli#6445](https://github.com/docker/cli/pull/6445)
- api/types/container: make ContainerState, HealthStatus concrete types. [moby/moby#51439](https://github.com/moby/moby/pull/51439)
- containerd image store is temporarily not available when userns remapping is enabled as a workaround for [moby#47377](https://github.com/moby/moby/issues/47377). [moby/moby#51042](https://github.com/moby/moby/pull/51042)
- contrib: remove contrib/httpserver, which was only used for integration tests. [moby/moby#50654](https://github.com/moby/moby/pull/50654)
- daemon: improve validation of the `--dns` option and corresponding `"dns"` field in `daemon.json`. [moby/moby#50600](https://github.com/moby/moby/pull/50600)
- dockerd-rootless.sh: if slirp4netns is not installed, try using pasta (passt). [moby/moby#51149](https://github.com/moby/moby/pull/51149)
- Fix `--mount type=image` failure when mounting the same image multiple times to a different destinations. [moby/moby#50268](https://github.com/moby/moby/pull/50268)
- Fix `docker stats <container>` not exiting gracefully. [docker/cli#6582](https://github.com/docker/cli/pull/6582)
- Fix a bug preventing the API server from shutting down quickly when there's an open connection to the `/events` endpoint. [moby/moby#51448](https://github.com/moby/moby/pull/51448)
- Fix a bug where collecting container stats in "one-shot" mode would not include the container's ID and Name. [moby/moby#51302](https://github.com/moby/moby/pull/51302)
- Fix an issue where all new tasks in the Swarm could get stuck in the PENDING state forever after scaling up a service with placement preferences. [moby/moby#50202](https://github.com/moby/moby/pull/50202)
- Fix issue where custom meta-headers were not passed through when using the containerd image store. [moby/moby#51024](https://github.com/moby/moby/pull/51024)
- Fix requests not being logged when running the daemon with `--log-level=trace`. [moby/moby#50986](https://github.com/moby/moby/pull/50986)
- Fix Swarm services becoming unreachable from published ports after a firewalld reload. [moby/moby#50443](https://github.com/moby/moby/pull/50443)
- Improve errors when failing to connect to the API to provide more context to the user. [moby/moby#50285](https://github.com/moby/moby/pull/50285)
- Improve shell completion for `docker secret` and `docker config` subcommands. [docker/cli#6446](https://github.com/docker/cli/pull/6446)
- Prefer explicit device driver name over GPU capabilities when selecting the device driver with `docker run --gpus`. [moby/moby#50717](https://github.com/moby/moby/pull/50717)
- Update runc to [v1.3.3](https://github.com/opencontainers/runc/releases/tag/v1.3.3). [moby/moby#51393](https://github.com/moby/moby/pull/51393)
- Update SwarmKit internal TLS configuration to exclude known insecure cipher suites. [moby/moby#51139](https://github.com/moby/moby/pull/51139)
- Windows: Fix BuildKit creating containers which isolation mode is inconsistent with the daemon's config. [moby/moby#50942](https://github.com/moby/moby/pull/50942)

### Packaging updates

- client: remove legacy CBC cipher suites from client config. [moby/moby#50126](https://github.com/moby/moby/pull/50126)
- contrib: remove `editorconfig` as it was unmaintained. [moby/moby#50607](https://github.com/moby/moby/pull/50607)
- contrib: remove Dockerfile syntax highlighting files for `nano` and TextMate (`tmbundle`) as they were unmaintained and outdated. [moby/moby#50606](https://github.com/moby/moby/pull/50606)
- contrib: remove mkimage-xxx scripts as they were unmaintained and not tested. [moby/moby#50297](https://github.com/moby/moby/pull/50297)
- If Docker is downgraded to a version that does not have this support the network will become unusable, it must be deleted and re-created. [moby/moby#50114](https://github.com/moby/moby/pull/50114)
- The Windows overlay network driver now supports option `--dns`. [moby/moby#51229](https://github.com/moby/moby/pull/51229)
- Update BuildKit to [v0.25.2](https://github.com/moby/buildkit/releases/tag/v0.25.2). [moby/moby#51397](https://github.com/moby/moby/pull/51397)
- Update containerd to [v2.1.5](https://github.com/containerd/containerd/releases/tag/v2.1.5). [moby/moby#51409](https://github.com/moby/moby/pull/51409)

  containerd v2.1.5 now uses systemd's default `LimitNOFILE` for containers,
  changing the open file descriptor limit (`ulimit -n`) from `1048576` to
  `1024`. This extends a change introduced in Docker Engine v25.0 for build
  containers to all containers.

  This prevents programs that adjust behavior based on ulimits from consuming
  excessive memory when the limit is set to `infinity`. Containers now behave
  the same way as programs running on the host.

  If your workload needs a higher limit, use `--ulimit` with `docker run`, or
  set defaults in `/etc/docker/daemon.json`:

  ```json
  {
    "default-ulimits": {
      "nofile": {
        "Name": "nofile",
        "Soft": 1048576,
        "Hard": 1048576
      }
    }
  }
  ```

  For more information, see [moby#51485](https://github.com/moby/moby/issues/51485).
- Update Go runtime to [1.25.4](https://go.dev/doc/devel/release#go1.25.4). [moby/moby#51418](https://github.com/moby/moby/pull/51418), [docker/cli#6632](https://github.com/docker/cli/pull/6632)
- Users can request a specific prefix size for networks allocated from the default pools by using the unspecified address, for example `--subnet 0.0.0.0/24 --subnet ::/96`. [moby/moby#50114](https://github.com/moby/moby/pull/50114)

### Networking

- Add daemon option `--bridge-accept-fwmark`. Packets with this firewall mark will accepted by bridge networks, overriding Docker's iptables or nftables "drop" rules. [moby/moby#50476](https://github.com/moby/moby/pull/50476)
- api/types/system: deprecated top level `DiskUsage` fields for type specific fields. [moby/moby#51235](https://github.com/moby/moby/pull/51235)
- Ensure bridge devices are removed when bridge network creation fails. [moby/moby#51147](https://github.com/moby/moby/pull/51147)
- Ensure that Windows NAT networks are recreated with their original labels when the Engine restarts. [moby/moby#50447](https://github.com/moby/moby/pull/50447)
- Environment variables set on a container using legacy links are deprecated and aren't added automatically anymore. [moby/moby#50719](https://github.com/moby/moby/pull/50719)
  - The daemon can be started with `DOCKER_KEEP_DEPRECATED_LEGACY_LINKS_ENV_VARS=1` to get them back
  - Users are encouraged to stop relying on these as they're deprecated, and the escape hatch will be removed in a later version
- Fix a bug in NetworkDB which would sometimes cause entries to get stuck deleted on some of the nodes, leading to connectivity issues between containers on overlay networks. [moby/moby#50342](https://github.com/moby/moby/pull/50342)
- Fix a bug that could cause the Engine and another host process to bind the same UDP port. [moby/moby#50669](https://github.com/moby/moby/pull/50669)
- Fix a deadlock that could happen if a firewalld reload was processed while the bridge networking driver was starting up, or creating or deleting a network, or creating port-mappings. [moby/moby#50620](https://github.com/moby/moby/pull/50620)
- Fix an issue preventing container startup or selection of its network gateway when IPv6 is only disabled on a specific interface. [moby/moby#48971](https://github.com/moby/moby/pull/48971)
- For Linux, `docker info` now reports the firewall backend if available. [docker/cli#6191](https://github.com/docker/cli/pull/6191)
- Greatly improve the reliability of overlay networking and the Swarm routing mesh. [moby/moby#50393](https://github.com/moby/moby/pull/50393)
- Improve the convergence rate of NetworkDB, part of the management plane for overlay networking, after bursts of updates. [moby/moby#50193](https://github.com/moby/moby/pull/50193)
- Improve the reliability of the overlay network driver. [moby/moby#50260](https://github.com/moby/moby/pull/50260)
- Improved error handling for connection of a container to a network. [moby/moby#50945](https://github.com/moby/moby/pull/50945)
- macvlan and IPvlan-l2 networks: no default gateway will be configured unless a `--gateway` is explicitly included in IPAM configuration. This addresses an issue which could cause container startup to fail in networks with IPv6 auto-configuration enabled. [moby/moby#50929](https://github.com/moby/moby/pull/50929)
- nftables: Docker will not enable IP forwarding on the host. If forwarding is needed by a bridge network, but not enabled, daemon startup or network creation will fail with an error. You must either enable forwarding and ensure firewall rules are in place to prevent unwanted forwarding between non-Docker interfaces. Or, use daemon option `--ip-forward=false` to disable the check, but some bridge network functionality including port forwarding may not work. See [Engine Docs](https://docs.docker.com/engine/network/firewall-nftables) for more information about migration from iptables to nftables. [moby/moby#50646](https://github.com/moby/moby/pull/50646)
- On daemon startup, restart containers that share their network stacks before containers that need those stacks. [moby/moby#50327](https://github.com/moby/moby/pull/50327)
- Published ports are now always accessible in networks with gateway mode "routed". Previously, rules to open those ports were only added when the routed mode network was selected as the container's default gateway. [moby/moby#50140](https://github.com/moby/moby/pull/50140)
- Since 28.0.0, an `iptables` mangle rule for checksumming SCTP was only added if environment variable `DOCKER_IPTABLES_SCTP_CHECKSUM=1` was set. The rule has now been removed, the environment variable now has no effect. [moby/moby#50539](https://github.com/moby/moby/pull/50539)
- The iptables rules for bridge networks have been updated, including removal of the `DOCKER-ISOLATION-STAGE-1` and `DOCKER-ISOLATION-STAGE-2` chains. With these changes:. [moby/moby#49981](https://github.com/moby/moby/pull/49981)
  - Containers can now access ports published to host addresses by containers in other networks when the userland-proxy is not running
  - Containers can now access ports on container addresses in other networks that have gateway mode "nat-unprotected"
- When dynamically linked, the Docker daemon now depends on libnftables. [moby/moby#51033](https://github.com/moby/moby/pull/51033)
- Windows: `network inspect`: the HNS network name is now reported in option `com.docker.network.windowsshim.networkname` rather than the Docker network name, which was only reported after a daemon restart. [moby/moby#50961](https://github.com/moby/moby/pull/50961)
- Windows: when restoring networks on daemon restart, preserve their association with non-default IPAM drivers. [moby/moby#50649](https://github.com/moby/moby/pull/50649)

### API

- `events` API now reports content-type as `application/x-ndjson` for newline-delimited JSON event stream. [moby/moby#50953](https://github.com/moby/moby/pull/50953)
- `GET /images/{name}/get` and `POST /images/load` now accept multiple `platform` query parameters, allowing export and load of images for multiple platforms. [moby/moby#50166](https://github.com/moby/moby/pull/50166)
- `GET /images/{name}/json` now omits the following fields if their value is empty: `Parent`, `Comment`, `DockerVersion`, `Author`. [moby/moby#51072](https://github.com/moby/moby/pull/51072)
- `GET /images/{name}/json`: omit empty `Config` fields when not set. [moby/moby#50915](https://github.com/moby/moby/pull/50915)
- `POST /images/{name:}/push`: remove compatibility with API v1.4 auth-config in body. [moby/moby#50371](https://github.com/moby/moby/pull/50371)
- Add support for memory swappiness in Swarm services. [moby/moby#51114](https://github.com/moby/moby/pull/51114)
  - `GET /services` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements
  - `GET /services/{id}` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements
  - `POST /services/create` now accepts `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements
  - `POST /services/{id}/update` now accepts `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements
  - `GET /tasks` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements
  - `GET /tasks/{id}` now returns `SwapBytes` and `MemorySwappiness` fields as part of the `Resource` requirements
- api/types/build: move `CachePruneOptions` type to `client.BuildCachePruneOptions`. [moby/moby#50772](https://github.com/moby/moby/pull/50772)
- api/types/checkpoint: move checkpoint options to client module. [moby/moby#50905](https://github.com/moby/moby/pull/50905)
- api/types/container: `OnBuild` will now be omitted if its value is empty or zero. [moby/moby#51154](https://github.com/moby/moby/pull/51154)
- api/types/container: make the container config `MacAddress` obsolete for v1.52 and onwards. Use network endpoint settings instead. [moby/moby#51189](https://github.com/moby/moby/pull/51189)
- api/types/container: move `ResizeOptions` type to `ContainerResizeOptions` in the client. [moby/moby#50773](https://github.com/moby/moby/pull/50773)
- api/types/events: move `ListOptions` type to the client `EventsListOptions`. [moby/moby#50774](https://github.com/moby/moby/pull/50774)
- api/types/image: move image options out to the client. [moby/moby#50776](https://github.com/moby/moby/pull/50776)
- api/types/network: move `CreateOptions`, `ConnectOptions` and `DisconnectOptions` to the client module. [moby/moby#50817](https://github.com/moby/moby/pull/50817)
- api/types/network: move the `ListOptions` and `InspectOptions` types to the client. [moby/moby#50786](https://github.com/moby/moby/pull/50786)
- api/types/plugin: change `ListResponse` to a non-pointer slice. [moby/moby#51440](https://github.com/moby/moby/pull/51440)
- api/types/plugin: remove deprecated `Config.DockerVersion`. [moby/moby#51458](https://github.com/moby/moby/pull/51458)
- api/types/registry: move `SearchOptions` to `ImageSearchOptions` in the client. [moby/moby#50787](https://github.com/moby/moby/pull/50787)
- api/types/registry: moved `ServiceConfig` legacy field marshaling support into daemon backend. [moby/moby#50826](https://github.com/moby/moby/pull/50826)
- api/types/registry: moved encode/decode auth config functions into reference utility package. [moby/moby#50785](https://github.com/moby/moby/pull/50785)
- api/types/storage: add `Storage` type and integrate in container inspect. [moby/moby#50857](https://github.com/moby/moby/pull/50857)
- api/types/swarm: deprecated and dropped support for `PortConfigProtocol`; use `network.IPProtocol` instead. [moby/moby#51094](https://github.com/moby/moby/pull/51094)
- api/types/swarm: move option types to the client module. [moby/moby#50794](https://github.com/moby/moby/pull/50794)
- api/types/swarm: move the `SecretListOptions` type to the client module. [moby/moby#50816](https://github.com/moby/moby/pull/50816)
- api/types/system: move `DiskUsageOptions` to the client. [moby/moby#50788](https://github.com/moby/moby/pull/50788)
- api/types/system: move `SecurityOpt` and `DecodeSecurityOptions` to client module. [moby/moby#50825](https://github.com/moby/moby/pull/50825)
- api/types/volume: change ListResponse.Volumes to a non-pointer slice. [moby/moby#51454](https://github.com/moby/moby/pull/51454)
- api/types/volume: move the `ListOptions` type to the client module. [moby/moby#50789](https://github.com/moby/moby/pull/50789)
- api/types/volume: moved `UpdateOptions` into client module. [moby/moby#51205](https://github.com/moby/moby/pull/51205)
- api/types: daemon: move the disk usage structs to the backend server. [moby/moby#50764](https://github.com/moby/moby/pull/50764)
- api: make `GraphDriver` field in `image.InspectResponse` optional. This field will continue to be emitted when using the legacy graph drivers and will be omitted when using the containerd image backend. [moby/moby#50893](https://github.com/moby/moby/pull/50893)
- api: redefine container network port types. [moby/moby#50710](https://github.com/moby/moby/pull/50710)
- client: PluginListResult: change Items field to a non-pointer slice. [moby/moby#51440](https://github.com/moby/moby/pull/51440)
- Inspecting networks with API v1.52 and newer provides statistics about IPAM allocations for the subnets assigned to the network. [moby/moby#50917](https://github.com/moby/moby/pull/50917)
- MAC address fields are represented as byte slices compatible with the standard library net.HardwareAddr type instead of strings. [moby/moby#51355](https://github.com/moby/moby/pull/51355)
- Swagger definitions for `NetworkSummary` and `NetworkInspect` have been added to the Swagger spec describing the Engine API. [moby/moby#50855](https://github.com/moby/moby/pull/50855)
- Update API version to 1.52. [moby/moby#50418](https://github.com/moby/moby/pull/50418)

### Go SDK

- `api/pkg/progress` and `api/pkg/streamformatter` have been removed. [moby/moby#51153](https://github.com/moby/moby/pull/51153)
- `api/types/registry`: `EncodeAuthConfig`: use empty string for zero value. [moby/moby#50426](https://github.com/moby/moby/pull/50426)
- `api/types/versions` has moved to the client and daemon. [moby/moby#51284](https://github.com/moby/moby/pull/51284)
- `client.ConfigCreate`, `client.ConfigList`, `client.ConfigInspectWithRaw`, `client.ConfigUpdate`, and `client.ConfigRemove` methods now accept option structs instead of positional arguments, and return dedicated result structs. [moby/moby#51078](https://github.com/moby/moby/pull/51078)
- `client.ImageBuild`, `client.BuildCancel`, `client.ImageList`, `client.ImageRemove`, `client.ImageTag`, and `client.ImageSearch` methods now accept option structs instead of positional arguments, and return dedicated result structs. [moby/moby#51227](https://github.com/moby/moby/pull/51227)
- `client`: `ContainerExec...` methods were renamed to `Exec...`. [moby/moby#51262](https://github.com/moby/moby/pull/51262)
- `client`: Wrap return values of `ImageInspect`, `ImageHistory`, `ImageLoad` and `ImageSave` in a struct. [moby/moby#51236](https://github.com/moby/moby/pull/51236)
- `ImagePull` now returns an object with `JSONMessages` method returning iterator over the message objects. [moby/moby#50935](https://github.com/moby/moby/pull/50935)
- `ImagePush` now returns an object with `JSONMessages` method returning iterator over the message objects. [moby/moby#51148](https://github.com/moby/moby/pull/51148)
- api/types/container: move `StatsResponseReader` to `client` package. [moby/moby#50521](https://github.com/moby/moby/pull/50521)
- api/types/container: move container options to client. [moby/moby#50897](https://github.com/moby/moby/pull/50897)
- api/types/container: rename `Port` to `PortSummary`. [moby/moby#50711](https://github.com/moby/moby/pull/50711)
- api/types/container: StatsResponse: add `OSType` field. [moby/moby#51305](https://github.com/moby/moby/pull/51305)
- api/types: move `ErrorResponse` to `common/ErrorResponse`. [moby/moby#50632](https://github.com/moby/moby/pull/50632)
- api: remove unused `DefaultVersion`, `MinSupportedAPIVersion` consts. [moby/moby#50587](https://github.com/moby/moby/pull/50587)
- cli/command: add `WithUserAgent` option. [docker/cli#4574](https://github.com/docker/cli/pull/4574)
- client: `ContainerCommitOptions`: remove `Pause` field in favor of `NoPause`. [moby/moby#51019](https://github.com/moby/moby/pull/51019)
- client: add `DefaultAPIVersion` const, which defines the default (and maximum) API version supported by the client. [moby/moby#50433](https://github.com/moby/moby/pull/50433)
- client: add `ExecAPIClient` interface for exec methods provided by the client. [moby/moby#50997](https://github.com/moby/moby/pull/50997)
- client: Client.PluginList: add options-struct. [moby/moby#51207](https://github.com/moby/moby/pull/51207)
- client: ContainersPrune: rewrite to use option structs and result. [moby/moby#51200](https://github.com/moby/moby/pull/51200)
- client: ImagesPrune: rewrite to use option structs and result. [moby/moby#51200](https://github.com/moby/moby/pull/51200)
- client: NetworksPrune: rewrite to use option structs and result. [moby/moby#51200](https://github.com/moby/moby/pull/51200)
- client: remove `client.ContainerStatsResult.OSType` field. [moby/moby#51305](https://github.com/moby/moby/pull/51305)
- client: VolumesPrune: rewrite to use option structs and result. [moby/moby#51200](https://github.com/moby/moby/pull/51200)
- daemon/config: add `DefaultAPIVersion` const, which defines the default (and maximum) API version supported by the daemon. [moby/moby#50436](https://github.com/moby/moby/pull/50436)
- Fix data race in `ContainerExecStart`, `ContainerList`, and `Events`. [moby/moby#50448](https://github.com/moby/moby/pull/50448)
- IP addresses and subnets are now of type `netip.Addr` and `netip.Prefix`, respectively. [moby/moby#50956](https://github.com/moby/moby/pull/50956)
- Remove structs `NetworkSettingsBase` and `DefaultNetworkSettings`. Fields in `NetworkSettingsBase` that were not deprecated are now directly in `NetworkSettings`. [moby/moby#50846](https://github.com/moby/moby/pull/50846)
- the client now uses its own `client.Filters` type for filtering API requests, with a more ergonomic interface. Users of the `github.com/docker/docker/api/types/filters` package will need to refactor when they upgrade to the v29 client. [moby/moby#51115](https://github.com/moby/moby/pull/51115)
- Types `"github.com/moby/moby/api/types/network".Summary` and `"github.com/moby/moby/api/types/network".Inspect` are no longer aliases, and most of their fields have been moved into an embedded struct. Engine API clients may require some source-level changes when migrating to the new github.com/moby/moby/api module. [moby/moby#50878](https://github.com/moby/moby/pull/50878)
- Update minimum Go version to 1.24. [docker/cli#6624](https://github.com/docker/cli/pull/6624)

### Deprecations

- `client/pkg/jsonmessage`: remove deprecated `ProgressMessage`, `ErrorMessage`, `DisplayJSONMessagesToStream` and `Stream` interface. [moby/moby#49264](https://github.com/moby/moby/pull/49264)
- `GET /events` no longer includes the deprecated `status`, `id`, and `from` fields. These fields were removed in API v1.22, but still included in the response. These fields are now omitted when using API v1.52 or later. [moby/moby#50832](https://github.com/moby/moby/pull/50832)
- api/types/network: CreateRequest: remove deprecated CheckDuplicate field. [moby/moby#50998](https://github.com/moby/moby/pull/50998)
- api/types/plugin: deprecate `Config.DockerVersion` field. [moby/moby#51109](https://github.com/moby/moby/pull/51109)
- api/types/registry: remove deprecated AuthConfig.Email field. [moby/moby#51059](https://github.com/moby/moby/pull/51059)
- api/types/strslice: deprecate StrSlice in favor of using a regular `[]string`. [moby/moby#50292](https://github.com/moby/moby/pull/50292)
- api/types/system: remove deprecated `DiskUsage.BuilderSize`. [moby/moby#51180](https://github.com/moby/moby/pull/51180)
- api/types: move plugin types to api/types/plugin. [moby/moby#48114](https://github.com/moby/moby/pull/48114)
- API: Deprecation: the Engine was automatically backfilling empty `PortBindings` lists with a PortBinding with an empty HostIP and HostPort when starting a container. This behavior is deprecated for API 1.52, and will be dropped in API 1.53. [moby/moby#50874](https://github.com/moby/moby/pull/50874)
- build: remove DCT support for classic builder. [docker/cli#6195](https://github.com/docker/cli/pull/6195)
- cli/command: Remove deprecated `ResolveDefaultContext`. [docker/cli#6555](https://github.com/docker/cli/pull/6555)
- client: ImageBuildResponse: remove OSType field. [moby/moby#50995](https://github.com/moby/moby/pull/50995)
- client: Remove `ImageCreate` method - use`ImagePull` or `ImageImport` instead. [moby/moby#51366](https://github.com/moby/moby/pull/51366)
- client: remove deprecated `ImageListOptions.ContainerCount`. [moby/moby#51006](https://github.com/moby/moby/pull/51006)
- client: remove support for negotiating API version < v1.44 (docker 25.0). [moby/moby#51119](https://github.com/moby/moby/pull/51119)
- client: remove unused `Client.HTTPClient()` method. [moby/moby#51011](https://github.com/moby/moby/pull/51011)
- daemon/graphdriver: remove deprecated `GetDriver()`. [moby/moby#50377](https://github.com/moby/moby/pull/50377)
- daemon: raise minimum API version to v1.44. [moby/moby#51186](https://github.com/moby/moby/pull/51186)
- Deprecate the `--pause` flag on `docker commit` in favor of `--no-pause`. [docker/cli#6460](https://github.com/docker/cli/pull/6460)
- Deprecate cgroup v1. [moby/moby#51360](https://github.com/moby/moby/pull/51360), [docker/cli#6598](https://github.com/docker/cli/pull/6598)
- Go SDK: `cli-plugins/manager`: deprecate metadata aliases in favor of their equivalent in `cli-plugins/manager/metadata`. [docker/cli#6237](https://github.com/docker/cli/pull/6237)
- Go SDK: `cli-plugins/manager`: remove `Candidate` interface, which was only for internal use. [docker/cli#6237](https://github.com/docker/cli/pull/6237)
- Go SDK: `cli-plugins/manager`: remove `NewPluginError` function, which was only for internal use. [docker/cli#6237](https://github.com/docker/cli/pull/6237)
- Go SDK: `cli-plugins/manager`: remove deprecated `ResourceAttributesEnvvar` const. [docker/cli#6237](https://github.com/docker/cli/pull/6237)
- Go SDK: `cli/command`: remove the `ErrPromptTerminated`, `DisableInputEcho`, `PromptForInput`, and `PromptForConfirmation` utilities. These utilities were for internal use and are no longer used. [docker/cli#6243](https://github.com/docker/cli/pull/6243)
- Go SDK: `cli/registry/client`: remove deprecated `RepoNameForReference`. [docker/cli#6206](https://github.com/docker/cli/pull/6206)
- Go SDK: api/types/build: remove deprecated BuildCache.Parent field. [moby/moby#51185](https://github.com/moby/moby/pull/51185)
- Go SDK: api/types/container: remove deprecated `ContainerTopOKBody` alias. [moby/moby#50400](https://github.com/moby/moby/pull/50400)
- Go SDK: api/types/container: remove deprecated `ContainerUpdateOKBody` alias. [moby/moby#50400](https://github.com/moby/moby/pull/50400)
- Go SDK: api/types/container: remove deprecated `Stats` type. [moby/moby#50492](https://github.com/moby/moby/pull/50492)
- Go SDK: api/types/filters: remove deprecated `ToParamWithVersion`. [moby/moby#50561](https://github.com/moby/moby/pull/50561)
- Go SDK: api/types/image: `InspectResponse`: remove deprecated `VirtualSize`, `Container`, `ContainerConfig`, `Parent`, and `DockerVersion` fields. [moby/moby#51103](https://github.com/moby/moby/pull/51103)
- Go SDK: api/types/image: remove deprecated Summary.VirtualSize field. [moby/moby#51190](https://github.com/moby/moby/pull/51190)
- Go SDK: api/types/registry: remove deprecated `ServiceConfig.AllowNondistributableArtifactsCIDRs` and `ServiceConfig.AllowNondistributableArtifactsHostnames` fields. [moby/moby#50375](https://github.com/moby/moby/pull/50375)
- Go SDK: api/types/swarm: remove deprecated ServiceSpec.Networks field. [moby/moby#51184](https://github.com/moby/moby/pull/51184)
- GO SDK: api/types/system: remove deprecated `Commit.Expected` field. [moby/moby#51127](https://github.com/moby/moby/pull/51127)
- Go SDK: api/types: remove deprecated aliases. [moby/moby#50452](https://github.com/moby/moby/pull/50452)
- Go SDK: api: deprecate `NoBaseImageSpecifier` const. This const is no longer used and will be removed in the next release. [moby/moby#50437](https://github.com/moby/moby/pull/50437)
- Go SDK: api: remove `NoBaseImageSpecifier`. [moby/moby#50574](https://github.com/moby/moby/pull/50574)
- Go SDK: cli/command/builder: remove `CachePrune()`, which was no longer used. [docker/cli#6236](https://github.com/docker/cli/pull/6236)
- Go SDK: cli/command/builder: remove `NewBuilderCommand` and `NewBakeStubCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/checkpoint: remove `NewCheckpointCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/checkpoint: remove deprecated `NewFormat`, `FormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/completion: remove deprecated `NoComplete`. [docker/cli#6408](https://github.com/docker/cli/pull/6408)
- Go SDK: cli/command/config: remove `NewConfigCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/config: remove deprecated `NewFormat`, `FormatWrite`, `InspectFormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/config: remove deprecated `RunConfigCreate`, `CreateOptions`, `RunConfigInspect`, `InspectOptions`, `RunConfigList`, `ListOptions`, `RunConfigRemove`, and `RemoveOptions`. [docker/cli#6370](https://github.com/docker/cli/pull/6370)
- Go SDK: cli/command/container: deprecate `NewDiffFormat`, `DiffFormatWrite`. These functions were only used internally and will be removed in the next release. [docker/cli#6187](https://github.com/docker/cli/pull/6187)
- Go SDK: cli/command/container: remove `NewBuildCommand`, `NewPullCommand`, `NewPushCommand`, `NewImagesCommand`, `NewImageCommand`, `NewHistoryCommand`, `NewImportCommand`, `NewLoadCommand`, `NewRemoveCommand`, `NewSaveCommand`, `NewTagCommand`, `NewPruneCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/container: remove `NewRunCommand`, `NewExecCommand`, `NewPsCommand`, `NewContainerCommand`, `NewAttachCommand`, `NewCommitCommand`, `NewCopyCommand`, `NewCreateCommand`, `NewDiffCommand`, `NewExportCommand`, `NewKillCommand`, `NewLogsCommand`, `NewPauseCommand`, `NewPortCommand`, `NewRenameCommand`, `NewRestartCommand`, `NewRmCommand`, `NewStartCommand`, `NewStatsCommand`, `NewStopCommand`, `NewTopCommand`, `NewUnpauseCommand`, `NewUpdateCommand`, `NewWaitCommand`, `NewPruneCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/container: remove `RunPrune()`, which was no longer used. [docker/cli#6236](https://github.com/docker/cli/pull/6236)
- Go SDK: cli/command/container: remove deprecated `NewDiffFormat`, `DiffFormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/context: remove `NewContextCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/context: remove deprecated `RunCreate` and `CreateOptions`. [docker/cli#6407](https://github.com/docker/cli/pull/6407)
- Go SDK: cli/command/context: remove deprecated `RunExport` and `ExportOptions`. [docker/cli#6407](https://github.com/docker/cli/pull/6407)
- Go SDK: cli/command/context: remove deprecated `RunImport`. [docker/cli#6407](https://github.com/docker/cli/pull/6407)
- Go SDK: cli/command/context: remove deprecated `RunRemove` and `RemoveOptions`. [docker/cli#6407](https://github.com/docker/cli/pull/6407)
- Go SDK: cli/command/context: remove deprecated `RunUpdate` and `UpdateOptions`. [docker/cli#6407](https://github.com/docker/cli/pull/6407)
- Go SDK: cli/command/context: remove deprecated `RunUse`. [docker/cli#6407](https://github.com/docker/cli/pull/6407)
- Go SDK: cli/command/formatter/swarm: remove deprecated `GetStacks` function. [docker/cli#6406](https://github.com/docker/cli/pull/6406)
- Go SDK: cli/command/image/build: deprecate `DefaultDockerfileName`, `DetectArchiveReader`, `WriteTempDockerfile`, `ResolveAndValidateContextPath`. These utilities were only used internally and will be removed in the next release. [docker/cli#6561](https://github.com/docker/cli/pull/6561)
- Go SDK: cli/command/image: remove `RunPrune()`, which was no longer used. [docker/cli#6236](https://github.com/docker/cli/pull/6236)
- Go SDK: cli/command/image: remove deprecated `AuthResolver` utility. [docker/cli#6373](https://github.com/docker/cli/pull/6373)
- Go SDK: cli/command/image: remove deprecated `NewHistoryFormat`, `HistoryWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339), [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/manifest: remove `NewManifestCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/network: remove `NewNetworkCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/network: remove `RunPrune()`, which was no longer used. [docker/cli#6236](https://github.com/docker/cli/pull/6236)
- Go SDK: cli/command/network: remove deprecated `NewFormat`, `FormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/node: remove `NewNodeCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/node: remove deprecated `NewFormat`, `FormatWrite`, `InspectFormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/plugin: remove `NewPluginCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/plugin: remove deprecated `NewFormat`, `FormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/registry: remove `NewLoginCommand`, `NewLogoutCommand`, `NewSearchCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/registry: remove deprecated `NewSearchFormat`, `SearchWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/registry: remove deprecated `OauthLoginEscapeHatchEnvVar` const. [docker/cli#6463](https://github.com/docker/cli/pull/6463)
- Go SDK: cli/command/secret: remove `NewSecretCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/secret: remove deprecated `NewFormat`, `FormatWrite`, `InspectFormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/service: remove `NewServiceCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/service: remove deprecated `NewFormat`, `InspectFormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/stack/swarm: remove deprecated RunPS and options.PS. [docker/cli#6398](https://github.com/docker/cli/pull/6398)
- Go SDK: cli/command/stack: remove `NewStackCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/stack: remove deprecated RunList and options.List. [docker/cli#6398](https://github.com/docker/cli/pull/6398)
- Go SDK: cli/command/stack: remove deprecated RunServices and swarm.GetServices. [docker/cli#6398](https://github.com/docker/cli/pull/6398)
- Go SDK: cli/command/swarm: remove `NewSwarmCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/system: remove `NewVersionCommand`, `NewInfoCommand`, `NewSystemCommand`, `NewEventsCommand`, `NewInspectCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/task: remove deprecated `NewTaskFormat`, `FormatWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/trust: remove `NewTrustCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/trust: remove deprecated `NewPruneCommand`. [docker/cli#6344](https://github.com/docker/cli/pull/6344)
- Go SDK: cli/command/trust: remove deprecated `SignedTagInfo`, `SignerInfo`, `NewTrustTagFormat`, `NewSignerInfoFormat`, `TagWrite`, `SignerInfoWrite`. [docker/cli#6339](https://github.com/docker/cli/pull/6339)
- Go SDK: cli/command/volume: remove `NewVolumeCommand`, `NewPruneCommand`. [docker/cli#6335](https://github.com/docker/cli/pull/6335)
- Go SDK: cli/command/volume: remove `RunPrune()`, which was no longer used. [docker/cli#6236](https://github.com/docker/cli/pull/6236)
- Go SDK: cli/command: remove `AddTrustSigningFlags`, `AddTrustVerificationFlags`, and `AddPlatformFlag` utilities, which were only used internally. [docker/cli#6244](https://github.com/docker/cli/pull/6244)
- Go SDK: cli/command: remove deprecated `DockerCli.Apply`. [docker/cli#6503](https://github.com/docker/cli/pull/6503)
- Go SDK: cli/command: remove deprecated `DockerCli.ContentTrustEnabled`. [docker/cli#6502](https://github.com/docker/cli/pull/6502)
- Go SDK: cli/command: remove deprecated `DockerCli.DefaultVersion`. [docker/cli#6502](https://github.com/docker/cli/pull/6502)
- Go SDK: cli/command: remove deprecated `RegistryAuthenticationPrivilegedFunc`. [docker/cli#6349](https://github.com/docker/cli/pull/6349)
- Go SDK: cli/command: remove deprecated `WithContentTrustFromEnv`, `WithContentTrust` options. [docker/cli#6502](https://github.com/docker/cli/pull/6502)
- Go SDK: cli/config/configfile: remove deprecated `ConfigFile.Experimental` field. [docker/cli#6464](https://github.com/docker/cli/pull/6464)
- Go SDK: cli/config/types: remove deprecated `AuthConfig.Email` field. [docker/cli#6515](https://github.com/docker/cli/pull/6515)
- Go SDK: cli/manifest/store: remove deprecated `IsNotFound`. [docker/cli#6523](https://github.com/docker/cli/pull/6523)
- Go SDK: cli: remove deprecated `VisitAll`, `DisableFlagsInUseLine` utilities. [docker/cli#6296](https://github.com/docker/cli/pull/6296)
- Go SDK: client: remove `APIClient.ImageInspectWithRaw` from the `APIClient` interface. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove `ImageAPIClient.ImageInspectWithRaw` from the `ImageAPIClient` interface. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove `ImageAPIClientDeprecated.ImageInspectWithRaw` from the `ImageAPIClientDeprecated`. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove deprecated `ErrorConnectionFailed` and `IsErrNotFound` functions. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove deprecated `NewClient` and `NewEnvClient` functions. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove the `CommonAPIClient` interface. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove the `ImageAPIClientDeprecated` interface. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: client: remove the deprecated `Client.ImageInspectWithRaw` method. [moby/moby#50485](https://github.com/moby/moby/pull/50485)
- Go SDK: container: remove deprecated `IsValidHealthString`. [moby/moby#50378](https://github.com/moby/moby/pull/50378)
- Go SDK: container: remove deprecated `IsValidStateString`. [moby/moby#50378](https://github.com/moby/moby/pull/50378)
- Go SDK: container: remove deprecated `StateStatus`, `WaitCondition`, and the related `WaitConditionNotRunning`, `WaitConditionNextExit`, and `WaitConditionRemoved` consts. [moby/moby#50378](https://github.com/moby/moby/pull/50378)
- Go SDK: deprecate `pkg/stdcopy`, which was moved to `api/pkg/stdcopy`. [moby/moby#50462](https://github.com/moby/moby/pull/50462)
- Go SDK: Deprecate field `NetworkSettingsBase.Bridge`, struct `NetworkSettingsBase`, all the fields of `DefaultNetworkSettings`, and struct `DefaultNetworkSettings`. [moby/moby#50848](https://github.com/moby/moby/pull/50848)
- Go SDK: deprecate pkg/stringid in favour of `github.com/moby/moby/client/pkg/stringid`. [moby/moby#50504](https://github.com/moby/moby/pull/50504)
- Go SDK: deprecate profiles package which got migrated to `github.com/moby/profiles`. [moby/moby#50481](https://github.com/moby/moby/pull/50481)
- Go SDK: oci: deprecate SetCapabilities, and some minor cleanups/fixes. [moby/moby#50461](https://github.com/moby/moby/pull/50461)
- Go SDK: opts: remove deprecated `ListOpts.GetAll`. It's no longer used and replaced by `ListOpts.GetSlice`. [docker/cli#6293](https://github.com/docker/cli/pull/6293)
- Go SDK: opts: remove deprecated `NewNamedListOptsRef`, `NewNamedMapOpts`, `NamedListOpts`, `NamedMapOpts`, and `NamedOption`. These types and functions are no longer used and will be removed in the next release. [docker/cli#6293](https://github.com/docker/cli/pull/6293)
- Go SDK: opts: remove deprecated `ParseEnvFile` in favour of `kvfile.Parse`. [docker/cli#6382](https://github.com/docker/cli/pull/6382)
- Go SDK: opts: remove deprecated `QuotedString`. [docker/cli#6293](https://github.com/docker/cli/pull/6293)
- Go SDK: opts: remove deprecated `ValidateHost`. [docker/cli#6293](https://github.com/docker/cli/pull/6293)
- Go SDK: pkg/system was removed, and is now an internal package. [moby/moby#50559](https://github.com/moby/moby/pull/50559)
- Go SDK: pkg/system: deprecate `EscapeArgs()` and `IsAbs`. These functions were only used internally and will be removed in the next release. [moby/moby#50399](https://github.com/moby/moby/pull/50399)
- Go SDK: registry: remove deprecated `APIEndpoint.TrimHostName`, `APIEndpoint.Official`, and `APIEndpoint.AllowNondistributableArtifacts` fields. [moby/moby#50376](https://github.com/moby/moby/pull/50376)
- Go SDK: registry: remove deprecated `HostCertsDir()` and `SetCertsDir()` functions. [moby/moby#50373](https://github.com/moby/moby/pull/50373)
- Go SDK: registry: remove deprecated `RepositoryInfo.Official` and `RepositoryInfo.Class` field. [moby/moby#50498](https://github.com/moby/moby/pull/50498)
- Go SDK: registry: remove deprecated `Service.ResolveRepository()`. [moby/moby#50374](https://github.com/moby/moby/pull/50374)
- Go SDK: Remove `buildkit.ClientOpts`. [moby/moby#50318](https://github.com/moby/moby/pull/50318)
- Go SDK: remove `pkg/fileutils`. [moby/moby#50558](https://github.com/moby/moby/pull/50558)
- Go SDK: Remove deprecated `IsNotFound`, `CommandAnnotationPlugin`, `CommandAnnotationPluginVendor`, `CommandAnnotationPluginVersion`, `CommandAnnotationPluginInvalid`, `CommandAnnotationPluginCommandPath`, `NamePrefix`, `MetadataSubcommandName`, `HookSubcommandName`, `Metadata`, and `ReexecEnvvar` from `cli-plugins/manager` in favor of their `cli-plugins/manager/metadata` equivalents. [docker/cli#6414](https://github.com/docker/cli/pull/6414)
- Go SDK: remove deprecated `types/plugins/logdriver` and `types/swarm/runtime` packages; plugin-runtime spec is now exposed as `types/swarm.RuntimeSpec` and `types/swarm.RuntimePrivilege`. [moby/moby#50554](https://github.com/moby/moby/pull/50554)
- Go SDK: remove deprecated `cli/command/formatter` package. [docker/cli#6406](https://github.com/docker/cli/pull/6406)
- Go SDK: remove deprecated `cli/registry/client` package. [docker/cli#6462](https://github.com/docker/cli/pull/6462)
- Go SDK: remove deprecated `pkg/idtools` package. [moby/moby#50456](https://github.com/moby/moby/pull/50456)
- Go SDK: templates: remove deprecated `NewParse` function. [docker/cli#6453](https://github.com/docker/cli/pull/6453)
- Hide the `--kernel-memory` option on `docker run` and `docker create`, and produce a warning when used as it's no longer supported by the daemon and kernel. [docker/cli#6455](https://github.com/docker/cli/pull/6455)
- Remove `VirtualSize` field from `docker image ls` output when using JSON format. [docker/cli#6524](https://github.com/docker/cli/pull/6524)
- Remove `VirtualSize` formatting options and output. [docker/cli#6524](https://github.com/docker/cli/pull/6524)
- Remove API version compatibility for API version < v1.44 (Docker v24.0 and older). [docker/cli#6551](https://github.com/docker/cli/pull/6551)
- Remove deprecated `bind-nonrecursive` option for `--mount`. [docker/cli#6241](https://github.com/docker/cli/pull/6241)
- Remove deprecated packages (`pkg/archive`, `pkg/chrootarchive`, `pkg/atomicwriter`, `pkg/reexec`, `pkg/platform`, `pkg/parsers`), `pkg/system.MkdirAll`. For replacements, see `github.com/moby/go-archive`, `github.com/moby/sys` and the standard library. [moby/moby#50208](https://github.com/moby/moby/pull/50208)
- Remove special handling for quoted values for the `--tlscacert`, `--tlscert`, and `--tlskey` command-line flags. [docker/cli#6306](https://github.com/docker/cli/pull/6306)
- Remove support for AutoRemove (`--rm`) on API < 1.30. [docker/cli#6525](https://github.com/docker/cli/pull/6525)
- Remove support for loading legacy (pre-Docker 1.10) images. [moby/moby#50324](https://github.com/moby/moby/pull/50324)


---

# Release notes

*Sección: Engine*




---

# Docker Engine prior releases

*Sección: Engine*

## 1.13.1 (2017-02-08)

> [!IMPORTANT]
>
> On Linux distributions where `devicemapper` was the default storage driver, the `overlay2`, or `overlay` is now used by default (if the kernel supports it). To use devicemapper, you can manually configure the storage driver to use through the `--storage-driver` daemon option, or by setting "storage-driver" in the `daemon.json` configuration file.

> [!IMPORTANT]
>
> In Docker 1.13, the managed plugin api changed, as compared to the experimental version introduced in Docker 1.12. You must **uninstall** plugins which you installed with Docker 1.12 _before_ upgrading to Docker 1.13. You can uninstall plugins using the `docker plugin rm` command.

If you have already upgraded to Docker 1.13 without uninstalling
previously-installed plugins, you may see this message when the Docker daemon
starts:

    Error starting daemon: json: cannot unmarshal string into Go value of type types.PluginEnv

To manually remove all plugins and resolve this problem, take the following steps:

1. Remove plugins.json from: `/var/lib/docker/plugins/`.
2. Restart Docker. Verify that the Docker daemon starts with no errors.
3. Reinstall your plugins.

### Contrib

* Do not require a custom build of tini [#28454](https://github.com/docker/docker/pull/28454)
* Upgrade to Go 1.7.5 [#30489](https://github.com/docker/docker/pull/30489)

### Remote API (v1.26) & Client

+ Support secrets in docker stack deploy with compose file [#30144](https://github.com/docker/docker/pull/30144)

### Runtime

* Fix size issue in `docker system df` [#30378](https://github.com/docker/docker/pull/30378)
* Fix error on `docker inspect` when Swarm certificates were expired. [#29246](https://github.com/docker/docker/pull/29246)
* Fix deadlock on v1 plugin with activate error [#30408](https://github.com/docker/docker/pull/30408)
* Fix SELinux regression [#30649](https://github.com/docker/docker/pull/30649)

### Plugins

* Support global scoped network plugins (v2) in swarm mode [#30332](https://github.com/docker/docker/pull/30332)
+ Add `docker plugin upgrade` [#29414](https://github.com/docker/docker/pull/29414)

### Windows

* Fix small regression with old plugins in Windows [#30150](https://github.com/docker/docker/pull/30150)
* Fix warning on Windows [#30730](https://github.com/docker/docker/pull/30730)

## 1.13.0 (2017-01-18)

> [!IMPORTANT]
>
> On Linux distributions where `devicemapper` was the default storage driver, the `overlay2`, or `overlay` is now used by default (if the kernel supports it). To use devicemapper, you can manually configure the storage driver to use through the `--storage-driver` daemon option, or by setting "storage-driver" in the `daemon.json` configuration file.

> [!IMPORTANT]
>
> In Docker 1.13, the managed plugin api changed, as compared to the experimental version introduced in Docker 1.12. You must **uninstall** plugins which you installed with Docker 1.12 _before_ upgrading to Docker 1.13. You can uninstall plugins using the `docker plugin rm` command.

If you have already upgraded to Docker 1.13 without uninstalling
previously-installed plugins, you may see this message when the Docker daemon
starts:

    Error starting daemon: json: cannot unmarshal string into Go value of type types.PluginEnv

To manually remove all plugins and resolve this problem, take the following steps:

1. Remove plugins.json from: `/var/lib/docker/plugins/`.
2. Restart Docker. Verify that the Docker daemon starts with no errors.
3. Reinstall your plugins.

### Builder

+ Add capability to specify images used as a cache source on build. These images do not need to have local parent chain and can be pulled from other registries [#26839](https://github.com/docker/docker/pull/26839)
+ (experimental) Add option to squash image layers to the FROM image after successful builds [#22641](https://github.com/docker/docker/pull/22641)
* Fix dockerfile parser with empty line after escape [#24725](https://github.com/docker/docker/pull/24725)
- Add step number on `docker build` [#24978](https://github.com/docker/docker/pull/24978)
+ Add support for compressing build context during image build [#25837](https://github.com/docker/docker/pull/25837)
+ add `--network` to `docker build` [#27702](https://github.com/docker/docker/pull/27702)
- Fix inconsistent behavior between `--label` flag on `docker build` and `docker run` [#26027](https://github.com/docker/docker/issues/26027)
- Fix image layer inconsistencies when using the overlay storage driver [#27209](https://github.com/docker/docker/pull/27209)
* Unused build-args are now allowed. A warning is presented instead of an error and failed build [#27412](https://github.com/docker/docker/pull/27412)
- Fix builder cache issue on Windows [#27805](https://github.com/docker/docker/pull/27805)
+ Allow `USER` in builder on Windows [#28415](https://github.com/docker/docker/pull/28415)
+ Handle env case-insensitive on Windows [#28725](https://github.com/docker/docker/pull/28725)

### Contrib

+ Add support for building docker debs for Ubuntu 16.04 Xenial on PPC64LE [#23438](https://github.com/docker/docker/pull/23438)
+ Add support for building docker debs for Ubuntu 16.04 Xenial on s390x [#26104](https://github.com/docker/docker/pull/26104)
+ Add support for building docker debs for Ubuntu 16.10 Yakkety Yak on PPC64LE [#28046](https://github.com/docker/docker/pull/28046)
- Add RPM builder for VMWare Photon OS [#24116](https://github.com/docker/docker/pull/24116)
+ Add shell completions to tgz [#27735](https://github.com/docker/docker/pull/27735)
* Update the install script to allow using the mirror in China [#27005](https://github.com/docker/docker/pull/27005)
+ Add DEB builder for Ubuntu 16.10 Yakkety Yak [#27993](https://github.com/docker/docker/pull/27993)
+ Add RPM builder for Fedora 25 [#28222](https://github.com/docker/docker/pull/28222)
+ Add `make deb` support for aarch64 [#27625](https://github.com/docker/docker/pull/27625)

### Distribution

* Update notary dependency to 0.4.2 (full changelogs [here](https://github.com/docker/notary/releases/tag/v0.4.2)) [#27074](https://github.com/docker/docker/pull/27074)
  - Support for compilation on windows [docker/notary#970](https://github.com/docker/notary/pull/970)
  - Improved error messages for client authentication errors [docker/notary#972](https://github.com/docker/notary/pull/972)
  - Support for finding keys that are anywhere in the `~/.docker/trust/private` directory, not just under `~/.docker/trust/private/root_keys` or `~/.docker/trust/private/tuf_keys` [docker/notary#981](https://github.com/docker/notary/pull/981)
  - Previously, on any error updating, the client would fall back on the cache.  Now we only do so if there is a network error or if the server is unavailable or missing the TUF data. Invalid TUF data will cause the update to fail - for example if there was an invalid root rotation. [docker/notary#982](https://github.com/docker/notary/pull/982)
  - Improve root validation and yubikey debug logging [docker/notary#858](https://github.com/docker/notary/pull/858) [docker/notary#891](https://github.com/docker/notary/pull/891)
  - Warn if certificates for root or delegations are near expiry [docker/notary#802](https://github.com/docker/notary/pull/802)
  - Warn if role metadata is near expiry [docker/notary#786](https://github.com/docker/notary/pull/786)
  - Fix passphrase retrieval attempt counting and terminal detection [docker/notary#906](https://github.com/docker/notary/pull/906)
- Avoid unnecessary blob uploads when different users push same layers to authenticated registry [#26564](https://github.com/docker/docker/pull/26564)
* Allow external storage for registry credentials [#26354](https://github.com/docker/docker/pull/26354)

### Logging

* Standardize the default logging tag value in all logging drivers [#22911](https://github.com/docker/docker/pull/22911)
- Improve performance and memory use when logging of long log lines [#22982](https://github.com/docker/docker/pull/22982)
+ Enable syslog driver for windows [#25736](https://github.com/docker/docker/pull/25736)
+ Add Logentries Driver [#27471](https://github.com/docker/docker/pull/27471)
+ Update of AWS log driver to support tags [#27707](https://github.com/docker/docker/pull/27707)
+ Unix socket support for fluentd [#26088](https://github.com/docker/docker/pull/26088)
* Enable fluentd logging driver on Windows [#28189](https://github.com/docker/docker/pull/28189)
- Sanitize docker labels when used as journald field names [#23725](https://github.com/docker/docker/pull/23725)
- Fix an issue where `docker logs --tail` returned less lines than expected [#28203](https://github.com/docker/docker/pull/28203)
- Splunk Logging Driver: performance and reliability improvements [#26207](https://github.com/docker/docker/pull/26207)
- Splunk Logging Driver: configurable formats and skip for verifying connection [#25786](https://github.com/docker/docker/pull/25786)

### Networking

+ Add `--attachable` network support to enable `docker run` to work in swarm-mode overlay network [#25962](https://github.com/docker/docker/pull/25962)
+ Add support for host port PublishMode in services using the `--publish` option in `docker service create` [#27917](https://github.com/docker/docker/pull/27917) and [#28943](https://github.com/docker/docker/pull/28943)
+ Add support for Windows server 2016 overlay network driver (requires upcoming ws2016 update) [#28182](https://github.com/docker/docker/pull/28182)
* Change the default `FORWARD` policy to `DROP` [#28257](https://github.com/docker/docker/pull/28257)
+ Add support for specifying static IP addresses for predefined network on windows [#22208](https://github.com/docker/docker/pull/22208)
- Fix `--publish` flag on `docker run` not working with IPv6 addresses [#27860](https://github.com/docker/docker/pull/27860)
- Fix inspect network show gateway with mask [#25564](https://github.com/docker/docker/pull/25564)
- Fix an issue where multiple addresses in a bridge may cause `--fixed-cidr` to not have the correct addresses [#26659](https://github.com/docker/docker/pull/26659)
+ Add creation timestamp to `docker network inspect` [#26130](https://github.com/docker/docker/pull/26130)
- Show peer nodes in `docker network inspect` for swarm overlay networks [#28078](https://github.com/docker/docker/pull/28078)
- Enable ping for service VIP address [#28019](https://github.com/docker/docker/pull/28019)

### Plugins

- Move plugins out of experimental [#28226](https://github.com/docker/docker/pull/28226)
- Add `--force` on `docker plugin remove` [#25096](https://github.com/docker/docker/pull/25096)
* Add support for dynamically reloading authorization plugins [#22770](https://github.com/docker/docker/pull/22770)
+ Add description in `docker plugin ls` [#25556](https://github.com/docker/docker/pull/25556)
+ Add `-f`/`--format` to `docker plugin inspect` [#25990](https://github.com/docker/docker/pull/25990)
+ Add `docker plugin create` command [#28164](https://github.com/docker/docker/pull/28164)
* Send request's TLS peer certificates to authorization plugins [#27383](https://github.com/docker/docker/pull/27383)
* Support for global-scoped network and ipam plugins in swarm-mode [#27287](https://github.com/docker/docker/pull/27287)
* Split `docker plugin install` into two API call `/privileges` and `/pull` [#28963](https://github.com/docker/docker/pull/28963)

### Remote API (v1.25) & Client

+ Support `docker stack deploy` from a Compose file [#27998](https://github.com/docker/docker/pull/27998)
+ (experimental) Implement checkpoint and restore [#22049](https://github.com/docker/docker/pull/22049)
+ Add `--format` flag to `docker info` [#23808](https://github.com/docker/docker/pull/23808)
* Remove `--name` from `docker volume create` [#23830](https://github.com/docker/docker/pull/23830)
+ Add `docker stack ls` [#23886](https://github.com/docker/docker/pull/23886)
+ Add a new `is-task` ps filter [#24411](https://github.com/docker/docker/pull/24411)
+ Add `--env-file` flag to `docker service create` [#24844](https://github.com/docker/docker/pull/24844)
+ Add `--format` on `docker stats` [#24987](https://github.com/docker/docker/pull/24987)
+ Make `docker node ps` default to `self` in swarm node [#25214](https://github.com/docker/docker/pull/25214)
+ Add `--group` in `docker service create` [#25317](https://github.com/docker/docker/pull/25317)
+ Add `--no-trunc` to service/node/stack ps output [#25337](https://github.com/docker/docker/pull/25337)
+ Add Logs to `ContainerAttachOptions` so go clients can request to retrieve container logs as part of the attach process [#26718](https://github.com/docker/docker/pull/26718)
+ Allow client to talk to an older server [#27745](https://github.com/docker/docker/pull/27745)
* Inform user client-side that a container removal is in progress [#26074](https://github.com/docker/docker/pull/26074)
+ Add `Isolation` to the /info endpoint [#26255](https://github.com/docker/docker/pull/26255)
+ Add `userns` to the /info endpoint [#27840](https://github.com/docker/docker/pull/27840)
- Do not allow more than one mode be requested at once in the services endpoint [#26643](https://github.com/docker/docker/pull/26643)
+ Add capability to /containers/create API to specify mounts in a more granular and safer way [#22373](https://github.com/docker/docker/pull/22373)
+ Add `--format` flag to `network ls` and `volume ls` [#23475](https://github.com/docker/docker/pull/23475)
* Allow the top-level `docker inspect` command to inspect any kind of resource [#23614](https://github.com/docker/docker/pull/23614)
+ Add --cpus flag to control cpu resources for `docker run` and `docker create`, and add `NanoCPUs` to `HostConfig` [#27958](https://github.com/docker/docker/pull/27958)
- Allow unsetting the `--entrypoint` in `docker run` or `docker create` [#23718](https://github.com/docker/docker/pull/23718)
* Restructure CLI commands by adding `docker image` and `docker container` commands for more consistency [#26025](https://github.com/docker/docker/pull/26025)
- Remove `COMMAND` column from `service ls` output [#28029](https://github.com/docker/docker/pull/28029)
+ Add `--format` to `docker events` [#26268](https://github.com/docker/docker/pull/26268)
* Allow specifying multiple nodes on `docker node ps` [#26299](https://github.com/docker/docker/pull/26299)
* Restrict fractional digits to 2 decimals in `docker images` output [#26303](https://github.com/docker/docker/pull/26303)
+ Add `--dns-option` to `docker run` [#28186](https://github.com/docker/docker/pull/28186)
+ Add Image ID to container commit event [#28128](https://github.com/docker/docker/pull/28128)
+ Add external binaries version to docker info [#27955](https://github.com/docker/docker/pull/27955)
+ Add information for `Manager Addresses` in the output of `docker info` [#28042](https://github.com/docker/docker/pull/28042)
+ Add a new reference filter for `docker images` [#27872](https://github.com/docker/docker/pull/27872)

### Runtime

+ Add `--experimental` daemon flag to enable experimental features, instead of shipping them in a separate build [#27223](https://github.com/docker/docker/pull/27223)
+ Add a `--shutdown-timeout` daemon flag to specify the default timeout (in seconds) to stop containers gracefully before daemon exit [#23036](https://github.com/docker/docker/pull/23036)
+ Add `--stop-timeout` to specify the timeout value (in seconds) for individual containers to stop [#22566](https://github.com/docker/docker/pull/22566)
+ Add a new daemon flag `--userland-proxy-path` to allow configuring the userland proxy instead of using the hardcoded `docker-proxy` from `$PATH` [#26882](https://github.com/docker/docker/pull/26882)
+ Add boolean flag `--init` on `dockerd` and on `docker run` to use [tini](https://github.com/krallin/tini) a zombie-reaping init process as PID 1 [#26061](https://github.com/docker/docker/pull/26061) [#28037](https://github.com/docker/docker/pull/28037)
+ Add a new daemon flag `--init-path` to allow configuring the path to the `docker-init` binary [#26941](https://github.com/docker/docker/pull/26941)
+ Add support for live reloading insecure registry in configuration [#22337](https://github.com/docker/docker/pull/22337)
+ Add support for storage-opt size on Windows daemons [#23391](https://github.com/docker/docker/pull/23391)
* Improve reliability of `docker run --rm` by moving it from the client to the daemon  [#20848](https://github.com/docker/docker/pull/20848)
+ Add support for `--cpu-rt-period` and `--cpu-rt-runtime` flags, allowing containers to run real-time threads when `CONFIG_RT_GROUP_SCHED` is enabled in the kernel [#23430](https://github.com/docker/docker/pull/23430)
* Allow parallel stop, pause, unpause [#24761](https://github.com/docker/docker/pull/24761) / [#26778](https://github.com/docker/docker/pull/26778)
* Implement XFS quota for overlay2 [#24771](https://github.com/docker/docker/pull/24771)
- Fix partial/full filter issue in `service tasks --filter` [#24850](https://github.com/docker/docker/pull/24850)
- Allow engine to run inside a user namespace [#25672](https://github.com/docker/docker/pull/25672)
- Fix a race condition between device deferred removal and resume device, when using the devicemapper graphdriver [#23497](https://github.com/docker/docker/pull/23497)
- Add `docker stats` support in Windows [#25737](https://github.com/docker/docker/pull/25737)
- Allow using `--pid=host` and `--net=host` when `--userns=host` [#25771](https://github.com/docker/docker/pull/25771)
+ (experimental) Add metrics (Prometheus) output for basic `container`, `image`, and `daemon` operations [#25820](https://github.com/docker/docker/pull/25820)
- Fix issue in `docker stats` with `NetworkDisabled=true` [#25905](https://github.com/docker/docker/pull/25905)
+ Add `docker top` support in Windows [#25891](https://github.com/docker/docker/pull/25891)
+ Record pid of exec'd process [#27470](https://github.com/docker/docker/pull/27470)
+ Add support for looking up user/groups via `getent` [#27599](https://github.com/docker/docker/pull/27599)
+ Add new `docker system` command with `df` and `prune` subcommands for system resource management, as well as `docker {container,image,volume,network} prune` subcommands [#26108](https://github.com/docker/docker/pull/26108) [#27525](https://github.com/docker/docker/pull/27525) / [#27525](https://github.com/docker/docker/pull/27525)
- Fix an issue where containers could not be stopped or killed by setting xfs max_retries to 0 upon ENOSPC with devicemapper [#26212](https://github.com/docker/docker/pull/26212)
- Fix `docker cp` failing to copy to a container's volume dir on CentOS with devicemapper [#28047](https://github.com/docker/docker/pull/28047)
* Promote overlay(2) graphdriver [#27932](https://github.com/docker/docker/pull/27932)
+ Add `--seccomp-profile` daemon flag to specify a path to a seccomp profile that overrides the default [#26276](https://github.com/docker/docker/pull/26276)
- Fix ulimits in `docker inspect` when `--default-ulimit` is set on daemon [#26405](https://github.com/docker/docker/pull/26405)
- Add workaround for overlay issues during build in older kernels [#28138](https://github.com/docker/docker/pull/28138)
+ Add `TERM` environment variable on `docker exec -t` [#26461](https://github.com/docker/docker/pull/26461)
* Honor a container’s `--stop-signal` setting upon `docker kill` [#26464](https://github.com/docker/docker/pull/26464)

### Swarm Mode

+ Add secret management [#27794](https://github.com/docker/docker/pull/27794)
+ Add support for templating service options (hostname, mounts, and environment variables) [#28025](https://github.com/docker/docker/pull/28025)
* Display the endpoint mode in the output of `docker service inspect --pretty` [#26906](https://github.com/docker/docker/pull/26906)
* Make `docker service ps` output more bearable by shortening service IDs in task names [#28088](https://github.com/docker/docker/pull/28088)
* Make `docker node ps` default to the current node [#25214](https://github.com/docker/docker/pull/25214)
+ Add `--dns`, -`-dns-opt`, and `--dns-search` to service create. [#27567](https://github.com/docker/docker/pull/27567)
+ Add `--force` to `docker service update` [#27596](https://github.com/docker/docker/pull/27596)
+ Add `--health-*` and `--no-healthcheck` flags to `docker service create` and `docker service update` [#27369](https://github.com/docker/docker/pull/27369)
+ Add `-q` to `docker service ps` [#27654](https://github.com/docker/docker/pull/27654)
* Display number of global services in `docker service ls` [#27710](https://github.com/docker/docker/pull/27710)
- Remove `--name` flag from `docker service update`. This flag is only functional on `docker service create`, so was removed from the `update` command [#26988](https://github.com/docker/docker/pull/26988)
- Fix worker nodes failing to recover because of transient networking issues [#26646](https://github.com/docker/docker/issues/26646)
* Add support for health aware load balancing and DNS records [#27279](https://github.com/docker/docker/pull/27279)
+ Add `--hostname` to `docker service create` [#27857](https://github.com/docker/docker/pull/27857)
+ Add `--host` to `docker service create`, and `--host-add`, `--host-rm` to `docker service update` [#28031](https://github.com/docker/docker/pull/28031)
+ Add `--tty` flag to `docker service create`/`update` [#28076](https://github.com/docker/docker/pull/28076)
* Autodetect, store, and expose node IP address as seen by the manager [#27910](https://github.com/docker/docker/pull/27910)
* Encryption at rest of manager keys and raft data [#27967](https://github.com/docker/docker/pull/27967)
+ Add `--update-max-failure-ratio`, `--update-monitor` and `--rollback` flags to `docker service update` [#26421](https://github.com/docker/docker/pull/26421)
- Fix an issue with address autodiscovery on `docker swarm init` running inside a container [#26457](https://github.com/docker/docker/pull/26457)
+ (experimental) Add `docker service logs` command to view logs for a service [#28089](https://github.com/docker/docker/pull/28089)
+ Pin images by digest for `docker service create` and `update` [#28173](https://github.com/docker/docker/pull/28173)
* Add short (`-f`) flag for `docker node rm --force` and `docker swarm leave --force` [#28196](https://github.com/docker/docker/pull/28196)
+ Add options to customize Raft snapshots (`--max-snapshots`, `--snapshot-interval`) [#27997](https://github.com/docker/docker/pull/27997)
- Don't repull image if pinned by digest [#28265](https://github.com/docker/docker/pull/28265)
+ Swarm-mode support for Windows [#27838](https://github.com/docker/docker/pull/27838)
+ Allow hostname to be updated on service [#28771](https://github.com/docker/docker/pull/28771)
+ Support v2 plugins [#29433](https://github.com/docker/docker/pull/29433)
+ Add content trust for services [#29469](https://github.com/docker/docker/pull/29469)

### Volume

+ Add support for labels on volumes [#21270](https://github.com/docker/docker/pull/21270)
+ Add support for filtering volumes by label [#25628](https://github.com/docker/docker/pull/25628)
* Add a `--force` flag in `docker volume rm` to forcefully purge the data of the volume that has already been deleted [#23436](https://github.com/docker/docker/pull/23436)
* Enhance `docker volume inspect` to show all options used when creating the volume [#26671](https://github.com/docker/docker/pull/26671)
* Add support for local NFS volumes to resolve hostnames [#27329](https://github.com/docker/docker/pull/27329)

### Security

- Fix selinux labeling of volumes shared in a container [#23024](https://github.com/docker/docker/pull/23024)
- Prohibit `/sys/firmware/**` from being accessed with apparmor [#26618](https://github.com/docker/docker/pull/26618)

### Deprecation

- Marked the `docker daemon` command as deprecated. The daemon is moved to a separate binary (`dockerd`), and should be used instead [#26834](https://github.com/docker/docker/pull/26834)
- Deprecate unversioned API endpoints [#28208](https://github.com/docker/docker/pull/28208)
- Remove Ubuntu 15.10 (Wily Werewolf) as supported platform. Ubuntu 15.10 is EOL, and no longer receives updates [#27042](https://github.com/docker/docker/pull/27042)
- Remove Fedora 22 as supported platform. Fedora 22 is EOL, and no longer receives updates [#27432](https://github.com/docker/docker/pull/27432)
- Remove Fedora 23 as supported platform. Fedora 23 is EOL, and no longer receives updates [#29455](https://github.com/docker/docker/pull/29455)
- Deprecate the `repo:shortid` syntax on `docker pull` [#27207](https://github.com/docker/docker/pull/27207)
- Deprecate backing filesystem without `d_type` for overlay and overlay2 storage drivers [#27433](https://github.com/docker/docker/pull/27433)
- Deprecate `MAINTAINER` in Dockerfile [#25466](https://github.com/docker/docker/pull/25466)
- Deprecate `filter` param for endpoint `/images/json` [#27872](https://github.com/docker/docker/pull/27872)
- Deprecate setting duplicate engine labels [#24533](https://github.com/docker/docker/pull/24533)
- Deprecate "top-level" network information in `NetworkSettings` [#28437](https://github.com/docker/docker/pull/28437)

## 1.12.6 (2017-01-10)

> [!IMPORTANT]
>
> Docker 1.12 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the `docker service` if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.

> [!NOTE]
>
> Docker 1.12.5 will correctly validate that either an IPv6 subnet is provided or that the IPAM driver can provide one when you specify the `--ipv6` option.

If you are currently using the `--ipv6` option _without_ specifying the
`--fixed-cidr-v6` option, the Docker daemon will refuse to start with the
following message:

```text
Error starting daemon: Error initializing network controller: Error creating
                       default "bridge" network: failed to parse pool request
                       for address space "LocalDefault" pool " subpool ":
                       could not find an available, non-overlapping IPv6 address
                       pool among the defaults to assign to the network
```

To resolve this error, either remove the `--ipv6` flag (to preserve the same
behavior as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the
value of the `--fixed-cidr-v6` flag.

In a similar way, if you specify the `--ipv6` flag when creating a network
with the default IPAM driver, without providing an IPv6 `--subnet`, network
creation will fail with the following message:

```text
Error response from daemon: failed to parse pool request for address space
                            "LocalDefault" pool "" subpool "": could not find an
                            available, non-overlapping IPv6 address pool among
                            the defaults to assign to the network
```

To resolve this, either remove the `--ipv6` flag (to preserve the same behavior
as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the value of the
`--subnet` flag.

The network creation will instead succeed if you use an external IPAM driver
which supports automatic allocation of IPv6 subnets.

### Runtime

- Fix runC privilege escalation (CVE-2016-9962)

## 1.12.5 (2016-12-15)

> [!IMPORTANT]
>
> Docker 1.12 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the `docker service` if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.

> [!NOTE]
>
> Docker 1.12.5 will correctly validate that either an IPv6 subnet is provided or that the IPAM driver can provide one when you specify the `--ipv6` option.

If you are currently using the `--ipv6` option _without_ specifying the
`--fixed-cidr-v6` option, the Docker daemon will refuse to start with the
following message:

```text
Error starting daemon: Error initializing network controller: Error creating
                       default "bridge" network: failed to parse pool request
                       for address space "LocalDefault" pool " subpool ":
                       could not find an available, non-overlapping IPv6 address
                       pool among the defaults to assign to the network
```

To resolve this error, either remove the `--ipv6` flag (to preserve the same
behavior as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the
value of the `--fixed-cidr-v6` flag.

In a similar way, if you specify the `--ipv6` flag when creating a network
with the default IPAM driver, without providing an IPv6 `--subnet`, network
creation will fail with the following message:

```text
Error response from daemon: failed to parse pool request for address space
                            "LocalDefault" pool "" subpool "": could not find an
                            available, non-overlapping IPv6 address pool among
                            the defaults to assign to the network
```

To resolve this, either remove the `--ipv6` flag (to preserve the same behavior
as in Docker 1.12.3 and earlier), or provide an IPv6 subnet as the value of the
`--subnet` flag.

The network network creation will instead succeed if you use an external IPAM driver
which supports automatic allocation of IPv6 subnets.

### Runtime

- Fix race on sending stdin close event [#29424](https://github.com/docker/docker/pull/29424)

### Networking

- Fix panic in docker network ls when a network was created with `--ipv6` and no ipv6 `--subnet` in older docker versions [#29416](https://github.com/docker/docker/pull/29416)

### Contrib

- Fix compilation on Darwin [#29370](https://github.com/docker/docker/pull/29370)

## 1.12.4 (2016-12-12)

> [!IMPORTANT]
>
> Docker 1.12 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the `docker service` if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.


### Runtime

- Fix issue where volume metadata was not removed [#29083](https://github.com/docker/docker/pull/29083)
- Asynchronously close streams to prevent holding container lock [#29050](https://github.com/docker/docker/pull/29050)
- Fix selinux labels for newly created container volumes [#29050](https://github.com/docker/docker/pull/29050)
- Remove hostname validation [#28990](https://github.com/docker/docker/pull/28990)
- Fix deadlocks caused by IO races [#29095](https://github.com/docker/docker/pull/29095) [#29141](https://github.com/docker/docker/pull/29141)
- Return an empty stats if the container is restarting [#29150](https://github.com/docker/docker/pull/29150)
- Fix volume store locking [#29151](https://github.com/docker/docker/pull/29151)
- Ensure consistent status code in API [#29150](https://github.com/docker/docker/pull/29150)
- Fix incorrect opaque directory permission in overlay2 [#29093](https://github.com/docker/docker/pull/29093)
- Detect plugin content and error out on `docker pull` [#29297](https://github.com/docker/docker/pull/29297)

### Swarm Mode

* Update Swarmkit [#29047](https://github.com/docker/docker/pull/29047)
  - orchestrator/global: Fix deadlock on updates [docker/swarmkit#1760](https://github.com/docker/swarmkit/pull/1760)
  - on leader switchover preserve the vxlan id for existing networks [docker/swarmkit#1773](https://github.com/docker/swarmkit/pull/1773)
- Refuse swarm spec not named "default" [#29152](https://github.com/docker/docker/pull/29152)

### Networking

* Update libnetwork [#29004](https://github.com/docker/docker/pull/29004) [#29146](https://github.com/docker/docker/pull/29146)
  - Fix panic in embedded DNS [docker/libnetwork#1561](https://github.com/docker/libnetwork/pull/1561)
  - Fix unmarhalling panic when passing --link-local-ip on global scope network [docker/libnetwork#1564](https://github.com/docker/libnetwork/pull/1564)
  - Fix panic when network plugin returns nil StaticRoutes [docker/libnetwork#1563](https://github.com/docker/libnetwork/pull/1563)
  - Fix panic in `osl.(*networkNamespace).DeleteNeighbor` [docker/libnetwork#1555](https://github.com/docker/libnetwork/pull/1555)
  - Fix panic in swarm networking concurrent map read/write [docker/libnetwork#1570](https://github.com/docker/libnetwork/pull/1570)
  * Allow encrypted networks when running docker inside a container [docker/libnetwork#1502](https://github.com/docker/libnetwork/pull/1502)
  - Do not block autoallocation of IPv6 pool [docker/libnetwork#1538](https://github.com/docker/libnetwork/pull/1538)
  - Set timeout for netlink calls [docker/libnetwork#1557](https://github.com/docker/libnetwork/pull/1557)
  - Increase networking local store timeout to one minute [docker/libkv#140](https://github.com/docker/libkv/pull/140)
  - Fix a panic in `libnetwork.(*sandbox).execFunc` [docker/libnetwork#1556](https://github.com/docker/libnetwork/pull/1556)
  - Honor icc=false for internal networks [docker/libnetwork#1525](https://github.com/docker/libnetwork/pull/1525)

### Logging

* Update syslog log driver [#29150](https://github.com/docker/docker/pull/29150)

### Contrib

- Run "dnf upgrade" before installing in fedora [#29150](https://github.com/docker/docker/pull/29150)
- Add build-date back to RPM packages [#29150](https://github.com/docker/docker/pull/29150)
- deb package filename changed to include distribution to distinguish between distribution code names [#27829](https://github.com/docker/docker/pull/27829)

## 1.12.3 (2016-10-26)

> [!IMPORTANT]
>
> Docker 1.12 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the Docker service if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.


### Runtime

- Fix ambient capability usage in containers (CVE-2016-8867) [#27610](https://github.com/docker/docker/pull/27610)
- Prevent a deadlock in libcontainerd for Windows [#27136](https://github.com/docker/docker/pull/27136)
- Fix error reporting in CopyFileWithTar [#27075](https://github.com/docker/docker/pull/27075)
* Reset health status to starting when a container is restarted [#27387](https://github.com/docker/docker/pull/27387)
* Properly handle shared mount propagation in storage directory [#27609](https://github.com/docker/docker/pull/27609)
- Fix docker exec [#27610](https://github.com/docker/docker/pull/27610)
- Fix backward compatibility with containerd’s events log [#27693](https://github.com/docker/docker/pull/27693)

### Swarm Mode

- Fix conversion of restart-policy [#27062](https://github.com/docker/docker/pull/27062)
* Update Swarmkit [#27554](https://github.com/docker/docker/pull/27554)
 * Avoid restarting a task that has already been restarted [docker/swarmkit#1305](https://github.com/docker/swarmkit/pull/1305)
 * Allow duplicate published ports when they use different protocols [docker/swarmkit#1632](https://github.com/docker/swarmkit/pull/1632)
 * Allow multiple randomly assigned published ports on service [docker/swarmkit#1657](https://github.com/docker/swarmkit/pull/1657)
 - Fix panic when allocations happen at init time [docker/swarmkit#1651](https://github.com/docker/swarmkit/pull/1651)

### Networking

* Update libnetwork [#27559](https://github.com/docker/docker/pull/27559)
 - Fix race in serializing sandbox to string [docker/libnetwork#1495](https://github.com/docker/libnetwork/pull/1495)
 - Fix race during deletion [docker/libnetwork#1503](https://github.com/docker/libnetwork/pull/1503)
 * Reset endpoint port info on connectivity revoke in bridge driver [docker/libnetwork#1504](https://github.com/docker/libnetwork/pull/1504)
 - Fix a deadlock in networking code [docker/libnetwork#1507](https://github.com/docker/libnetwork/pull/1507)
 - Fix a race in load balancer state [docker/libnetwork#1512](https://github.com/docker/libnetwork/pull/1512)

### Logging

* Update fluent-logger-golang to v1.2.1 [#27474](https://github.com/docker/docker/pull/27474)

### Contrib

* Update buildtags for armhf ubuntu-trusty [#27327](https://github.com/docker/docker/pull/27327)
* Add AppArmor to runc buildtags for armhf [#27421](https://github.com/docker/docker/pull/27421)

## 1.12.2 (2016-10-11)

> [!IMPORTANT]
>
> Docker 1.12 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the `docker service` if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.


### Runtime

- Fix a panic due to a race condition filtering `docker ps` [#26049](https://github.com/docker/docker/pull/26049)
* Implement retry logic to prevent "Unable to remove filesystem" errors when using the aufs storage driver [#26536](https://github.com/docker/docker/pull/26536)
* Prevent devicemapper from removing device symlinks if `dm.use_deferred_removal` is enabled [#24740](https://github.com/docker/docker/pull/24740)
- Fix an issue where the CLI did not return correct exit codes if a command was run with invalid options [#26777](https://github.com/docker/docker/pull/26777)
- Fix a panic due to a bug in stdout / stderr processing in health checks [#26507](https://github.com/docker/docker/pull/26507)
- Fix exec's children handling [#26874](https://github.com/docker/docker/pull/26874)
- Fix exec form of HEALTHCHECK CMD [#26208](https://github.com/docker/docker/pull/26208)

### Networking

- Fix a daemon start panic on armv5 [#24315](https://github.com/docker/docker/issues/24315)
* Vendor libnetwork [#26879](https://github.com/docker/docker/pull/26879) [#26953](https://github.com/docker/docker/pull/26953)
 * Avoid returning early on agent join failures [docker/libnetwork#1473](https://github.com/docker/libnetwork/pull/1473)
 - Fix service published port cleanup issues [docker/libetwork#1432](https://github.com/docker/libnetwork/pull/1432) [docker/libnetwork#1433](https://github.com/docker/libnetwork/pull/1433)
 * Recover properly from transient gossip failures [docker/libnetwork#1446](https://github.com/docker/libnetwork/pull/1446)
 * Disambiguate node names known to gossip cluster to avoid node name collision [docker/libnetwork#1451](https://github.com/docker/libnetwork/pull/1451)
 * Honor user provided listen address for gossip  [docker/libnetwork#1460](https://github.com/docker/libnetwork/pull/1460)
 * Allow reachability via published port across services on the same host [docker/libnetwork#1398](https://github.com/docker/libnetwork/pull/1398)
 * Change the ingress sandbox name from random id to just `ingress_sbox` [docker/libnetwork#1449](https://github.com/docker/libnetwork/pull/1449)
 - Disable service discovery in ingress network [docker/libnetwork#1489](https://github.com/docker/libnetwork/pull/1489)

### Swarm Mode

* Fix remote detection of a node's address when it joins the cluster [#26211](https://github.com/docker/docker/pull/26211)
* Vendor SwarmKit [#26765](https://github.com/docker/docker/pull/26765)
 * Bounce session after failed status update [docker/swarmkit#1539](https://github.com/docker/swarmkit/pull/1539)
 - Fix possible raft deadlocks [docker/swarmkit#1537](https://github.com/docker/swarmkit/pull/1537)
 - Fix panic and endpoint leak when a service is updated with no endpoints [docker/swarmkit#1481](https://github.com/docker/swarmkit/pull/1481)
 * Produce an error if the same port is published twice on `service create` or `service update` [docker/swarmkit#1495](https://github.com/docker/swarmkit/pull/1495)
 - Fix an issue where changes to a service were not detected, resulting in the service not being updated [docker/swarmkit#1497](https://github.com/docker/swarmkit/pull/1497)
 - Do not allow service creation on ingress network [docker/swarmkit#1600](https://github.com/docker/swarmkit/pull/1600)

### Contrib

* Update the debian sysv-init script to use `dockerd` instead of `docker daemon` [#25869](https://github.com/docker/docker/pull/25869)
* Improve stability when running the docker client on MacOS Sierra [#26875](https://github.com/docker/docker/pull/26875)
- Fix installation on debian stretch [#27184](https://github.com/docker/docker/pull/27184)

### Windows

- Fix an issue where arrow-navigation did not work when running the docker client in ConEmu [#25578](https://github.com/docker/docker/pull/25578)

## 1.12.1 (2016-08-18)

> [!IMPORTANT]
>
> Docker 1.12 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the `docker service` if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.


### Client

* Add `Joined at` information in `node inspect --pretty` [#25512](https://github.com/docker/docker/pull/25512)
- Fix a crash on `service inspect` [#25454](https://github.com/docker/docker/pull/25454)
- Fix issue preventing `service update --env-add` to work as intended [#25427](https://github.com/docker/docker/pull/25427)
- Fix issue preventing `service update --publish-add` to work as intended [#25428](https://github.com/docker/docker/pull/25428)
- Remove `service update --network-add` and `service update --network-rm` flags
  because this feature is not yet implemented in 1.12, but was inadvertently added
  to the client in 1.12.0 [#25646](https://github.com/docker/docker/pull/25646)

### Contrib

+ Official ARM installation for Debian Jessie, Ubuntu Trusty, and Raspbian Jessie [#24815](https://github.com/docker/docker/pull/24815) [#25591](https://github.com/docker/docker/pull/25637)
- Add selinux policy per distribution/version, fixing issue preventing successful installation on Fedora 24, and Oracle Linux [#25334](https://github.com/docker/docker/pull/25334) [#25593](https://github.com/docker/docker/pull/25593)

### Networking

- Fix issue that prevented containers to be accessed by hostname with Docker overlay driver in Swarm Mode [#25603](https://github.com/docker/docker/pull/25603) [#25648](https://github.com/docker/docker/pull/25648)
- Fix random network issues on service with published port [#25603](https://github.com/docker/docker/pull/25603)
- Fix unreliable inter-service communication after scaling down and up [#25603](https://github.com/docker/docker/pull/25603)
- Fix issue where removing all tasks on a node and adding them back breaks connectivity with other services [#25603](https://github.com/docker/docker/pull/25603)
- Fix issue where a task that fails to start results in a race, causing a `network xxx not found` error that masks the actual error [#25550](https://github.com/docker/docker/pull/25550)
- Relax validation of SRV records for external services that use SRV records not formatted according to RFC 2782 [#25739](https://github.com/docker/docker/pull/25739)

### Plugins (experimental)

* Make daemon events listen for plugin lifecycle events [#24760](https://github.com/docker/docker/pull/24760)
* Check for plugin state before enabling plugin [#25033](https://github.com/docker/docker/pull/25033)
- Remove plugin root from filesystem on `plugin rm` [#25187](https://github.com/docker/docker/pull/25187)
- Prevent deadlock when more than one plugin is installed [#25384](https://github.com/docker/docker/pull/25384)

### Runtime

* Mask join tokens in daemon logs [#25346](https://github.com/docker/docker/pull/25346)
- Fix `docker ps --filter` causing the results to no longer be sorted by creation time [#25387](https://github.com/docker/docker/pull/25387)
- Fix various crashes [#25053](https://github.com/docker/docker/pull/25053)

### Security

* Add `/proc/timer_list` to the masked paths list to prevent information leak from the host [#25630](https://github.com/docker/docker/pull/25630)
* Allow systemd to run with only `--cap-add SYS_ADMIN` rather than having to also add `--cap-add DAC_READ_SEARCH` or disabling seccomp filtering [#25567](https://github.com/docker/docker/pull/25567)

### Swarm

- Fix an issue where the swarm can get stuck electing a new leader after quorum is lost [#25055](https://github.com/docker/docker/issues/25055)
- Fix unwanted rescheduling of containers after a leader failover [#25017](https://github.com/docker/docker/issues/25017)
- Change swarm root CA key to P256 curve [swarmkit#1376](https://github.com/docker/swarmkit/pull/1376)
- Allow forced removal of a node from a swarm [#25159](https://github.com/docker/docker/pull/25159)
- Fix connection leak when a node leaves a swarm [swarmkit/#1277](https://github.com/docker/swarmkit/pull/1277)
- Backdate swarm certificates by one hour to tolerate more clock skew [swarmkit/#1243](https://github.com/docker/swarmkit/pull/1243)
- Avoid high CPU use with many unschedulable tasks [swarmkit/#1287](https://github.com/docker/swarmkit/pull/1287)
- Fix issue with global tasks not starting up [swarmkit/#1295](https://github.com/docker/swarmkit/pull/1295)
- Garbage collect raft logs [swarmkit/#1327](https://github.com/docker/swarmkit/pull/1327)

### Volume

- Persist local volume options after a daemon restart [#25316](https://github.com/docker/docker/pull/25316)
- Fix an issue where the mount ID was not returned on volume unmount [#25333](https://github.com/docker/docker/pull/25333)
- Fix an issue where a volume mount could inadvertently create a bind mount [#25309](https://github.com/docker/docker/pull/25309)
- `docker service create --mount type=bind,...` now correctly validates if the source path exists, instead of creating it [#25494](https://github.com/docker/docker/pull/25494)

## 1.12.0 (2016-07-28)


> [!IMPORTANT]
>
> Docker 1.12.0 ships with an updated systemd unit file for rpm
based installs (which includes RHEL, Fedora, CentOS, and Oracle Linux 7). When upgrading from an older version of Docker, the upgrade process may not automatically install the updated version of the unit file, or fail to start the `docker service` if;
> - the systemd unit file (`/usr/lib/systemd/system/docker.service`) contains local changes, or
> - a systemd drop-in file is present, and contains `-H fd://` in the `ExecStart` directive

Starting the `docker service` will produce an error:

    Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

or

    no sockets found via socket activation: make sure the service was started by systemd.

To resolve this:

- Backup the current version of the unit file, and replace the file with the
  [version that ships with docker 1.12](https://raw.githubusercontent.com/docker/docker/v1.12.0/contrib/init/systemd/docker.service.rpm)
- Remove the `Requires=docker.socket` directive from the `/usr/lib/systemd/system/docker.service` file if present
- Remove `-H fd://` from the `ExecStart` directive (both in the main unit file, and in any drop-in files present).

After making those changes, run `sudo systemctl daemon-reload`, and `sudo
systemctl restart docker` to reload changes and (re)start the docker daemon.

> [!IMPORTANT]
>
> With Docker 1.12, a Linux `docker` installation now has two
additional binaries; `dockerd`, and `docker-proxy`. If you have scripts for installing `docker`, make sure to update them accordingly.

### Builder

+ New `HEALTHCHECK` Dockerfile instruction to support user-defined healthchecks [#23218](https://github.com/docker/docker/pull/23218)
+ New `SHELL` Dockerfile instruction to specify the default shell when using the shell form for commands in a Dockerfile [#22489](https://github.com/docker/docker/pull/22489)
+ Add `#escape=` Dockerfile directive to support platform-specific parsing of file paths in Dockerfile [#22268](https://github.com/docker/docker/pull/22268)
+ Add support for comments in `.dockerignore` [#23111](https://github.com/docker/docker/pull/23111)
* Support for UTF-8 in Dockerfiles [#23372](https://github.com/docker/docker/pull/23372)
* Skip UTF-8 BOM bytes from `Dockerfile` and `.dockerignore` if exist [#23234](https://github.com/docker/docker/pull/23234)
* Windows: support for `ARG` to match Linux [#22508](https://github.com/docker/docker/pull/22508)
- Fix error message when building using a daemon with the bridge network disabled [#22932](https://github.com/docker/docker/pull/22932)

### Contrib

* Enable seccomp for Centos 7 and Oracle Linux 7 [#22344](https://github.com/docker/docker/pull/22344)
- Remove MountFlags in systemd unit to allow shared mount propagation [#22806](https://github.com/docker/docker/pull/22806)

### Distribution

+ Add `--max-concurrent-downloads` and `--max-concurrent-uploads` daemon flags useful for situations where network connections don't support multiple downloads/uploads [#22445](https://github.com/docker/docker/pull/22445)
* Registry operations now honor the `ALL_PROXY` environment variable [#22316](https://github.com/docker/docker/pull/22316)
* Provide more information to the user on `docker load` [#23377](https://github.com/docker/docker/pull/23377)
* Always save registry digest metadata about images pushed and pulled [#23996](https://github.com/docker/docker/pull/23996)

### Logging

+ Syslog logging driver now supports DGRAM sockets [#21613](https://github.com/docker/docker/pull/21613)
+ Add `--details` option to `docker logs` to also display log tags [#21889](https://github.com/docker/docker/pull/21889)
+ Enable syslog logger to have access to env and labels [#21724](https://github.com/docker/docker/pull/21724)
+ An additional syslog-format option `rfc5424micro` to allow microsecond resolution in syslog timestamp [#21844](https://github.com/docker/docker/pull/21844)
* Inherit the daemon log options when creating containers [#21153](https://github.com/docker/docker/pull/21153)
* Remove `docker/` prefix from log messages tag and replace it with `{{.DaemonName}}` so that users have the option of changing the prefix [#22384](https://github.com/docker/docker/pull/22384)

### Networking

+ Built-in Virtual-IP based  internal and ingress load-balancing using IPVS [#23361](https://github.com/docker/docker/pull/23361)
+ Routing Mesh using ingress overlay network [#23361](https://github.com/docker/docker/pull/23361)
+ Secured multi-host overlay networking using encrypted control-plane and Data-plane [#23361](https://github.com/docker/docker/pull/23361)
+ MacVlan driver is out of experimental [#23524](https://github.com/docker/docker/pull/23524)
+ Add `driver` filter to `network ls` [#22319](https://github.com/docker/docker/pull/22319)
+ Adding `network` filter to `docker ps --filter` [#23300](https://github.com/docker/docker/pull/23300)
+ Add `--link-local-ip` flag to `create`, `run` and `network connect` to specify a container's link-local address [#23415](https://github.com/docker/docker/pull/23415)
+ Add network label filter support [#21495](https://github.com/docker/docker/pull/21495)
* Removed dependency on external KV-Store for Overlay networking in Swarm-Mode  [#23361](https://github.com/docker/docker/pull/23361)
* Add container's short-id as default network alias [#21901](https://github.com/docker/docker/pull/21901)
* `run` options `--dns` and `--net=host` are no longer mutually exclusive [#22408](https://github.com/docker/docker/pull/22408)
- Fix DNS issue when renaming containers with generated names [#22716](https://github.com/docker/docker/pull/22716)
- Allow both `network inspect -f {{.Id}}` and `network inspect -f {{.ID}}` to address inconsistency with inspect output [#23226](https://github.com/docker/docker/pull/23226)

### Plugins (experimental)

+ New `plugin` command to manager plugins with `install`, `enable`, `disable`, `rm`, `inspect`, `set` subcommands [#23446](https://github.com/docker/docker/pull/23446)

### Remote API (v1.24) & Client

+ Split the binary into two: `docker` (client) and `dockerd` (daemon) [#20639](https://github.com/docker/docker/pull/20639)
+ Add `before` and `since` filters to `docker images --filter` [#22908](https://github.com/docker/docker/pull/22908)
+ Add `--limit` option to `docker search` [#23107](https://github.com/docker/docker/pull/23107)
+ Add `--filter` option to `docker search` [#22369](https://github.com/docker/docker/pull/22369)
+ Add security options to `docker info` output [#21172](https://github.com/docker/docker/pull/21172) [#23520](https://github.com/docker/docker/pull/23520)
+ Add insecure registries to `docker info` output [#20410](https://github.com/docker/docker/pull/20410)
+ Extend Docker authorization with TLS user information [#21556](https://github.com/docker/docker/pull/21556)
+ devicemapper: expose Minimum Thin Pool Free Space through `docker info` [#21945](https://github.com/docker/docker/pull/21945)
* API now returns a JSON object when an error occurs making it more consistent [#22880](https://github.com/docker/docker/pull/22880)
- Prevent `docker run -i --restart` from hanging on exit [#22777](https://github.com/docker/docker/pull/22777)
- Fix API/CLI discrepancy on hostname validation [#21641](https://github.com/docker/docker/pull/21641)
- Fix discrepancy in the format of sizes in `stats` from HumanSize to BytesSize [#21773](https://github.com/docker/docker/pull/21773)
- authz: when request is denied return forbidden exit code (403) [#22448](https://github.com/docker/docker/pull/22448)
- Windows: fix tty-related displaying issues [#23878](https://github.com/docker/docker/pull/23878)

### Runtime

+ Split the userland proxy to a separate binary (`docker-proxy`) [#23312](https://github.com/docker/docker/pull/23312)
+ Add `--live-restore` daemon flag to keep containers running when daemon shuts down, and regain control on startup [#23213](https://github.com/docker/docker/pull/23213)
+ Ability to add OCI-compatible runtimes (via `--add-runtime` daemon flag) and select one with `--runtime` on `create` and `run` [#22983](https://github.com/docker/docker/pull/22983)
+ New `overlay2` graphdriver for Linux 4.0+ with multiple lower directory support [#22126](https://github.com/docker/docker/pull/22126)
+ New load/save image events [#22137](https://github.com/docker/docker/pull/22137)
+ Add support for reloading daemon configuration through systemd [#22446](https://github.com/docker/docker/pull/22446)
+ Add disk quota support for btrfs [#19651](https://github.com/docker/docker/pull/19651)
+ Add disk quota support for zfs [#21946](https://github.com/docker/docker/pull/21946)
+ Add support for `docker run --pid=container:<id>` [#22481](https://github.com/docker/docker/pull/22481)
+ Align default seccomp profile with selected capabilities [#22554](https://github.com/docker/docker/pull/22554)
+ Add a `daemon reload` event when the daemon reloads its configuration [#22590](https://github.com/docker/docker/pull/22590)
+ Add `trace` capability in the pprof profiler to show execution traces in binary form [#22715](https://github.com/docker/docker/pull/22715)
+ Add a `detach` event [#22898](https://github.com/docker/docker/pull/22898)
+ Add support for setting sysctls with `--sysctl` [#19265](https://github.com/docker/docker/pull/19265)
+ Add `--storage-opt` flag to `create` and `run` allowing to set `size` on devicemapper [#19367](https://github.com/docker/docker/pull/19367)
+ Add `--oom-score-adjust` daemon flag with a default value of `-500` making the daemon less likely to be killed before containers [#24516](https://github.com/docker/docker/pull/24516)
* Undeprecate the `-c` short alias of `--cpu-shares` on `run`, `build`, `create`, `update` [#22621](https://github.com/docker/docker/pull/22621)
* Prevent from using aufs and overlay graphdrivers on an eCryptfs mount [#23121](https://github.com/docker/docker/pull/23121)
- Fix issues with tmpfs mount ordering [#22329](https://github.com/docker/docker/pull/22329)
- Created containers are no longer listed on `docker ps -a -f exited=0` [#21947](https://github.com/docker/docker/pull/21947)
- Fix an issue where containers are stuck in a "Removal In Progress" state [#22423](https://github.com/docker/docker/pull/22423)
- Fix bug that was returning an HTTP 500 instead of a 400 when not specifying a command on run/create [#22762](https://github.com/docker/docker/pull/22762)
- Fix bug with `--detach-keys` whereby input matching a prefix of the detach key was not preserved [#22943](https://github.com/docker/docker/pull/22943)
- SELinux labeling is now disabled when using `--privileged` mode [#22993](https://github.com/docker/docker/pull/22993)
- If volume-mounted into a container, `/etc/hosts`, `/etc/resolv.conf`, `/etc/hostname` are no longer SELinux-relabeled [#22993](https://github.com/docker/docker/pull/22993)
- Fix inconsistency in `--tmpfs` behavior regarding mount options [#22438](https://github.com/docker/docker/pull/22438)
- Fix an issue where daemon hangs at startup [#23148](https://github.com/docker/docker/pull/23148)
- Ignore SIGPIPE events to prevent journald restarts to crash docker in some cases [#22460](https://github.com/docker/docker/pull/22460)
- Containers are not removed from stats list on error [#20835](https://github.com/docker/docker/pull/20835)
- Fix `on-failure` restart policy when daemon restarts [#20853](https://github.com/docker/docker/pull/20853)
- Fix an issue with `stats` when a container is using another container's network [#21904](https://github.com/docker/docker/pull/21904)

### Swarm Mode

+ New `swarm` command to manage swarms with `init`, `join`, `join-token`, `leave`, `update` subcommands [#23361](https://github.com/docker/docker/pull/23361) [#24823](https://github.com/docker/docker/pull/24823)
+ New `service` command to manage swarm-wide services with `create`, `inspect`, `update`, `rm`, `ps` subcommands [#23361](https://github.com/docker/docker/pull/23361) [#25140](https://github.com/docker/docker/pull/25140)
+ New `node` command to manage nodes with `accept`, `promote`, `demote`, `inspect`, `update`, `ps`, `ls` and `rm` subcommands [#23361](https://github.com/docker/docker/pull/23361) [#25140](https://github.com/docker/docker/pull/25140)
+ (experimental) New `stack` and `deploy` commands to manage and deploy multi-service applications [#23522](https://github.com/docker/docker/pull/23522) [#25140](https://github.com/docker/docker/pull/25140)

### Volume

+ Add support for local and global volume scopes (analogous to network scopes) [#22077](https://github.com/docker/docker/pull/22077)
+ Allow volume drivers to provide a `Status` field [#21006](https://github.com/docker/docker/pull/21006)
+ Add name/driver filter support for volume [#21361](https://github.com/docker/docker/pull/21361)
* Mount/Unmount operations now receives an opaque ID to allow volume drivers to differentiate between two callers [#21015](https://github.com/docker/docker/pull/21015)
- Fix issue preventing to remove a volume in a corner case [#22103](https://github.com/docker/docker/pull/22103)
- Windows: Enable auto-creation of host-path to match Linux [#22094](https://github.com/docker/docker/pull/22094)


### Deprecation

* Environment variables `DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and `DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` have been renamed
  to `DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE` and `DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE` respectively [#22574](https://github.com/docker/docker/pull/22574)
* Remove deprecated `syslog-tag`, `gelf-tag`, `fluentd-tag` log option in favor of the more generic `tag` one [#22620](https://github.com/docker/docker/pull/22620)
* Remove deprecated feature of passing HostConfig at API container start [#22570](https://github.com/docker/docker/pull/22570)
* Remove deprecated `-f`/`--force` flag on docker tag [#23090](https://github.com/docker/docker/pull/23090)
* Remove deprecated `/containers/<id|name>/copy` endpoint [#22149](https://github.com/docker/docker/pull/22149)
* Remove deprecated `docker ps` flags `--since` and `--before` [#22138](https://github.com/docker/docker/pull/22138)
* Deprecate the old 3-args form of `docker import` [#23273](https://github.com/docker/docker/pull/23273)

## 1.11.2 (2016-05-31)

### Networking

- Fix a stale endpoint issue on overlay networks during ungraceful restart ([#23015](https://github.com/docker/docker/pull/23015))
- Fix an issue where the wrong port could be reported by `docker inspect/ps/port` ([#22997](https://github.com/docker/docker/pull/22997))

### Runtime

- Fix a potential panic when running `docker build` ([#23032](https://github.com/docker/docker/pull/23032))
- Fix interpretation of `--user` parameter ([#22998](https://github.com/docker/docker/pull/22998))
- Fix a bug preventing container statistics to be correctly reported ([#22955](https://github.com/docker/docker/pull/22955))
- Fix an issue preventing container to be restarted after daemon restart ([#22947](https://github.com/docker/docker/pull/22947))
- Fix issues when running 32 bit binaries on Ubuntu 16.04 ([#22922](https://github.com/docker/docker/pull/22922))
- Fix a possible deadlock on image deletion and container attach ([#22918](https://github.com/docker/docker/pull/22918))
- Fix an issue where containers fail to start after a daemon restart if they depend on a containerized cluster store ([#22561](https://github.com/docker/docker/pull/22561))
- Fix an issue causing `docker ps` to hang on CentOS when using devicemapper ([#22168](https://github.com/docker/docker/pull/22168), [#23067](https://github.com/docker/docker/pull/23067))
- Fix a bug preventing to `docker exec` into a container when using devicemapper ([#22168](https://github.com/docker/docker/pull/22168), [#23067](https://github.com/docker/docker/pull/23067))


## 1.11.1 (2016-04-26)

### Distribution

- Fix schema2 manifest media type to be of type `application/vnd.docker.container.image.v1+json` ([#21949](https://github.com/docker/docker/pull/21949))

### Documentation

+ Add missing API documentation for changes introduced with 1.11.0 ([#22048](https://github.com/docker/docker/pull/22048))

### Builder

* Append label passed to `docker build` as arguments as an implicit `LABEL` command at the end of the processed `Dockerfile` ([#22184](https://github.com/docker/docker/pull/22184))

### Networking

- Fix a panic that would occur when forwarding DNS query ([#22261](https://github.com/docker/docker/pull/22261))
- Fix an issue where OS threads could end up within an incorrect network namespace when using user defined networks ([#22261](https://github.com/docker/docker/pull/22261))

### Runtime

- Fix a bug preventing labels configuration to be reloaded via the config file ([#22299](https://github.com/docker/docker/pull/22299))
- Fix a regression where container mounting `/var/run` would prevent other containers from being removed ([#22256](https://github.com/docker/docker/pull/22256))
- Fix an issue where it would be impossible to update both `memory-swap` and `memory` value together ([#22255](https://github.com/docker/docker/pull/22255))
- Fix a regression from 1.11.0 where the `/auth` endpoint would not initialize `serveraddress` if it is not provided ([#22254](https://github.com/docker/docker/pull/22254))
- Add missing cleanup of container temporary files when cancelling a schedule restart ([#22237](https://github.com/docker/docker/pull/22237))
- Remove scary error message when no restart policy is specified ([#21993](https://github.com/docker/docker/pull/21993))
- Fix a panic that would occur when the plugins were activated via the json spec ([#22191](https://github.com/docker/docker/pull/22191))
- Fix restart backoff logic to correctly reset delay if container ran for at least 10secs ([#22125](https://github.com/docker/docker/pull/22125))
- Remove error message when a container restart get cancelled ([#22123](https://github.com/docker/docker/pull/22123))
- Fix an issue where `docker` would not correctly clean up after `docker exec` ([#22121](https://github.com/docker/docker/pull/22121))
- Fix a panic that could occur when serving concurrent `docker stats` commands ([#22120](https://github.com/docker/docker/pull/22120))`
- Revert deprecation of non-existent host directories auto-creation ([#22065](https://github.com/docker/docker/pull/22065))
- Hide misleading rpc error on daemon shutdown ([#22058](https://github.com/docker/docker/pull/22058))

## 1.11.0 (2016-04-13)

> [!IMPORTANT]
>
> With Docker 1.11, a Linux Docker installation is now made of 4 binaries (`docker`, [`docker-containerd`](https://github.com/docker/containerd), [`docker-containerd-shim`](https://github.com/docker/containerd) and [`docker-runc`](https://github.com/opencontainers/runc)). If you have scripts relying on `docker` being a single static binaries, make sure to update them. Interaction with the daemon stay the same otherwise, the usage of the other binaries should be transparent. A Windows Docker installation remains a single binary, `docker.exe`.

### Builder

- Fix a bug where Docker would not use the correct uid/gid when processing the `WORKDIR` command ([#21033](https://github.com/docker/docker/pull/21033))
- Fix a bug where copy operations with userns would not use the proper uid/gid ([#20782](https://github.com/docker/docker/pull/20782), [#21162](https://github.com/docker/docker/pull/21162))

### Client

* Usage of the `:` separator for security option has been deprecated. `=` should be used instead ([#21232](https://github.com/docker/docker/pull/21232))
+ The client user agent is now passed to the registry on `pull`, `build`, `push`, `login` and `search` operations ([#21306](https://github.com/docker/docker/pull/21306), [#21373](https://github.com/docker/docker/pull/21373))
* Allow setting the Domainname and Hostname separately through the API ([#20200](https://github.com/docker/docker/pull/20200))
* Docker info will now warn users if it can not detect the kernel version or the operating system ([#21128](https://github.com/docker/docker/pull/21128))
- Fix an issue where `docker stats --no-stream` output could be all 0s ([#20803](https://github.com/docker/docker/pull/20803))
- Fix a bug where some newly started container would not appear in a running `docker stats` command ([#20792](https://github.com/docker/docker/pull/20792))
* Post processing is no longer enabled for linux-cgo terminals ([#20587](https://github.com/docker/docker/pull/20587))
- Values to `--hostname` are now refused if they do not comply with [RFC1123](https://tools.ietf.org/html/rfc1123) ([#20566](https://github.com/docker/docker/pull/20566))
+ Docker learned how to use a SOCKS proxy ([#20366](https://github.com/docker/docker/pull/20366), [#18373](https://github.com/docker/docker/pull/18373))
+ Docker now supports external credential stores ([#20107](https://github.com/docker/docker/pull/20107))
* `docker ps` now supports displaying the list of volumes mounted inside a container ([#20017](https://github.com/docker/docker/pull/20017))
* `docker info` now also reports Docker's root directory location ([#19986](https://github.com/docker/docker/pull/19986))
- Docker now prohibits login in with an empty username (spaces are trimmed) ([#19806](https://github.com/docker/docker/pull/19806))
* Docker events attributes are now sorted by key ([#19761](https://github.com/docker/docker/pull/19761))
* `docker ps` no longer shows exported port for stopped containers ([#19483](https://github.com/docker/docker/pull/19483))
- Docker now cleans after itself if a save/export command fails ([#17849](https://github.com/docker/docker/pull/17849))
* Docker load learned how to display a progress bar ([#17329](https://github.com/docker/docker/pull/17329), [#120078](https://github.com/docker/docker/pull/20078))

### Distribution

- Fix a panic that occurred when pulling an image with 0 layers ([#21222](https://github.com/docker/docker/pull/21222))
- Fix a panic that could occur on error while pushing to a registry with a misconfigured token service ([#21212](https://github.com/docker/docker/pull/21212))
+ All first-level delegation roles are now signed when doing a trusted push ([#21046](https://github.com/docker/docker/pull/21046))
+ OAuth support for registries was added ([#20970](https://github.com/docker/docker/pull/20970))
* `docker login` now handles token using the implementation found in [docker/distribution](https://github.com/docker/distribution) ([#20832](https://github.com/docker/docker/pull/20832))
* `docker login` will no longer prompt for an email ([#20565](https://github.com/docker/docker/pull/20565))
* Docker will now fallback to registry V1 if no basic auth credentials are available ([#20241](https://github.com/docker/docker/pull/20241))
* Docker will now try to resume layer download where it left off after a network error/timeout ([#19840](https://github.com/docker/docker/pull/19840))
- Fix generated manifest mediaType when pushing cross-repository ([#19509](https://github.com/docker/docker/pull/19509))
- Fix docker requesting additional push credentials when pulling an image if Content Trust is enabled ([#20382](https://github.com/docker/docker/pull/20382))

### Logging

- Fix a race in the journald log driver ([#21311](https://github.com/docker/docker/pull/21311))
* Docker syslog driver now uses the RFC-5424 format when emitting logs ([#20121](https://github.com/docker/docker/pull/20121))
* Docker GELF log driver now allows to specify the compression algorithm and level via the `gelf-compression-type` and `gelf-compression-level` options ([#19831](https://github.com/docker/docker/pull/19831))
* Docker daemon learned to output uncolorized logs via the `--raw-logs` options ([#19794](https://github.com/docker/docker/pull/19794))
+ Docker, on Windows platform, now includes an ETW (Event Tracing in Windows) logging driver named `etwlogs` ([#19689](https://github.com/docker/docker/pull/19689))
* Journald log driver learned how to handle tags ([#19564](https://github.com/docker/docker/pull/19564))
+ The fluentd log driver learned the following options: `fluentd-address`, `fluentd-buffer-limit`, `fluentd-retry-wait`, `fluentd-max-retries` and `fluentd-async-connect` ([#19439](https://github.com/docker/docker/pull/19439))
+ Docker learned to send log to Google Cloud via the new `gcplogs` logging driver. ([#18766](https://github.com/docker/docker/pull/18766))


### Misc

+ When saving linked images together with `docker save` a subsequent `docker load` will correctly restore their parent/child relationship ([#21385](https://github.com/docker/docker/pull/21385))
+ Support for building the Docker cli for OpenBSD was added ([#21325](https://github.com/docker/docker/pull/21325))
+ Labels can now be applied at network, volume and image creation ([#21270](https://github.com/docker/docker/pull/21270))
* The `dockremap` is now created as a system user ([#21266](https://github.com/docker/docker/pull/21266))
- Fix a few response body leaks ([#21258](https://github.com/docker/docker/pull/21258))
- Docker, when run as a service with systemd, will now properly manage its processes cgroups ([#20633](https://github.com/docker/docker/pull/20633))
* `docker info` now reports the value of cgroup KernelMemory or emits a warning if it is not supported ([#20863](https://github.com/docker/docker/pull/20863))
* `docker info` now also reports the cgroup driver in use ([#20388](https://github.com/docker/docker/pull/20388))
* Docker completion is now available on PowerShell ([#19894](https://github.com/docker/docker/pull/19894))
* `dockerinit` is no more ([#19490](https://github.com/docker/docker/pull/19490),[#19851](https://github.com/docker/docker/pull/19851))
+ Support for building Docker on arm64 was added ([#19013](https://github.com/docker/docker/pull/19013))
+ Experimental support for building docker.exe in a native Windows Docker installation ([#18348](https://github.com/docker/docker/pull/18348))

### Networking

- Fix panic if a node is forcibly removed from the cluster ([#21671](https://github.com/docker/docker/pull/21671))
- Fix "error creating vxlan interface" when starting a container in a Swarm cluster ([#21671](https://github.com/docker/docker/pull/21671))
* `docker network inspect` will now report all endpoints whether they have an active container or not ([#21160](https://github.com/docker/docker/pull/21160))
+ Experimental support for the MacVlan and IPVlan network drivers has been added ([#21122](https://github.com/docker/docker/pull/21122))
* Output of `docker network ls` is now sorted by network name ([#20383](https://github.com/docker/docker/pull/20383))
- Fix a bug where Docker would allow a network to be created with the reserved `default` name ([#19431](https://github.com/docker/docker/pull/19431))
* `docker network inspect` returns whether a network is internal or not ([#19357](https://github.com/docker/docker/pull/19357))
+ Control IPv6 via explicit option when creating a network (`docker network create --ipv6`). This shows up as a new `EnableIPv6` field in `docker network inspect` ([#17513](https://github.com/docker/docker/pull/17513))
* Support for AAAA Records (aka IPv6 Service Discovery) in embedded DNS Server ([#21396](https://github.com/docker/docker/pull/21396))
- Fix to not forward docker domain IPv6 queries to external servers ([#21396](https://github.com/docker/docker/pull/21396))
* Multiple A/AAAA records from embedded DNS Server for DNS Round robin ([#21019](https://github.com/docker/docker/pull/21019))
- Fix endpoint count inconsistency after an ungraceful daemon restart ([#21261](https://github.com/docker/docker/pull/21261))
- Move the ownership of exposed ports and port-mapping options from Endpoint to Sandbox ([#21019](https://github.com/docker/docker/pull/21019))
- Fixed a bug which prevents docker reload when host is configured with ipv6.disable=1 ([#21019](https://github.com/docker/docker/pull/21019))
- Added inbuilt nil IPAM driver ([#21019](https://github.com/docker/docker/pull/21019))
- Fixed bug in iptables.Exists() logic [#21019](https://github.com/docker/docker/pull/21019)
- Fixed a Veth interface leak when using overlay network ([#21019](https://github.com/docker/docker/pull/21019))
- Fixed a bug which prevents docker reload after a network delete during shutdown ([#20214](https://github.com/docker/docker/pull/20214))
- Make sure iptables chains are recreated on firewalld reload ([#20419](https://github.com/docker/docker/pull/20419))
- Allow to pass global datastore during config reload ([#20419](https://github.com/docker/docker/pull/20419))
- For anonymous containers use the alias name for IP to name mapping, ie:DNS PTR record ([#21019](https://github.com/docker/docker/pull/21019))
- Fix a panic when deleting an entry from /etc/hosts file  ([#21019](https://github.com/docker/docker/pull/21019))
- Source the forwarded DNS queries from the container net namespace  ([#21019](https://github.com/docker/docker/pull/21019))
- Fix to retain the network internal mode config for bridge networks on daemon reload ([#21780] (https://github.com/docker/docker/pull/21780))
- Fix to retain IPAM driver option configs on daemon reload ([#21914] (https://github.com/docker/docker/pull/21914))

### Plugins

- Fix a file descriptor leak that would occur every time plugins were enumerated ([#20686](https://github.com/docker/docker/pull/20686))
- Fix an issue where Authz plugin would corrupt the payload body when faced with a large amount of data ([#20602](https://github.com/docker/docker/pull/20602))

### Runtime

- Fix a panic that could occur when cleanup after a container started with invalid parameters ([#21716](https://github.com/docker/docker/pull/21716))
- Fix a race with event timers stopping early ([#21692](https://github.com/docker/docker/pull/21692))
- Fix race conditions in the layer store, potentially corrupting the map and crashing the process ([#21677](https://github.com/docker/docker/pull/21677))
- Un-deprecate auto-creation of host directories for mounts. This feature was marked deprecated in ([#21666](https://github.com/docker/docker/pull/21666))
  Docker 1.9, but was decided to be too much of a backward-incompatible change, so it was decided to keep the feature.
+ It is now possible for containers to share the NET and IPC namespaces when `userns` is enabled ([#21383](https://github.com/docker/docker/pull/21383))
+ `docker inspect <image-id>` will now expose the rootfs layers ([#21370](https://github.com/docker/docker/pull/21370))
+ Docker Windows gained a minimal `top` implementation ([#21354](https://github.com/docker/docker/pull/21354))
* Docker learned to report the faulty exe when a container cannot be started due to its condition ([#21345](https://github.com/docker/docker/pull/21345))
* Docker with device mapper will now refuse to run if `udev sync` is not available ([#21097](https://github.com/docker/docker/pull/21097))
- Fix a bug where Docker would not validate the config file upon configuration reload ([#21089](https://github.com/docker/docker/pull/21089))
- Fix a hang that would happen on attach if initial start was to fail ([#21048](https://github.com/docker/docker/pull/21048))
- Fix an issue where registry service options in the daemon configuration file were not properly taken into account ([#21045](https://github.com/docker/docker/pull/21045))
- Fix a race between the exec and resize operations ([#21022](https://github.com/docker/docker/pull/21022))
- Fix an issue where nanoseconds were not correctly taken in account when filtering Docker events ([#21013](https://github.com/docker/docker/pull/21013))
- Fix the handling of Docker command when passed a 64 bytes id ([#21002](https://github.com/docker/docker/pull/21002))
* Docker will now return a `204` (i.e http.StatusNoContent) code when it successfully deleted a network ([#20977](https://github.com/docker/docker/pull/20977))
- Fix a bug where the daemon would wait indefinitely in case the process it was about to killed had already exited on its own ([#20967](https://github.com/docker/docker/pull/20967)
* The devmapper driver learned the `dm.min_free_space` option. If the mapped device free space reaches the passed value, new device creation will be prohibited. ([#20786](https://github.com/docker/docker/pull/20786))
+ Docker can now prevent processes in container to gain new privileges via the `--security-opt=no-new-privileges` flag ([#20727](https://github.com/docker/docker/pull/20727))
- Starting a container with the `--device` option will now correctly resolves symlinks ([#20684](https://github.com/docker/docker/pull/20684))
+ Docker now relies on [`containerd`](https://github.com/docker/containerd) and [`runc`](https://github.com/opencontainers/runc) to spawn containers. ([#20662](https://github.com/docker/docker/pull/20662))
- Fix docker configuration reloading to only alter value present in the given config file ([#20604](https://github.com/docker/docker/pull/20604))
+ Docker now allows setting a container hostname via the `--hostname` flag when `--net=host` ([#20177](https://github.com/docker/docker/pull/20177))
+ Docker now allows executing privileged container while running with `--userns-remap` if both `--privileged` and the new `--userns=host` flag are specified ([#20111](https://github.com/docker/docker/pull/20111))
- Fix Docker not cleaning up correctly old containers upon restarting after a crash ([#19679](https://github.com/docker/docker/pull/19679))
* Docker will now error out if it doesn't recognize a configuration key within the config file ([#19517](https://github.com/docker/docker/pull/19517))
- Fix container loading, on daemon startup, when they depends on a plugin running within a container ([#19500](https://github.com/docker/docker/pull/19500))
* `docker update` learned how to change a container restart policy ([#19116](https://github.com/docker/docker/pull/19116))
* `docker inspect` now also returns a new `State` field containing the container state in a human readable way (i.e. one of `created`, `restarting`, `running`, `paused`, `exited` or `dead`)([#18966](https://github.com/docker/docker/pull/18966))
+ Docker learned to limit the number of active pids (i.e. processes) within the container via the `pids-limit` flags. NOTE: This requires `CGROUP_PIDS=y` to be in the kernel configuration. ([#18697](https://github.com/docker/docker/pull/18697))
- `docker load` now has a `--quiet` option to suppress the load output ([#20078](https://github.com/docker/docker/pull/20078))
- Fix a bug in neighbor discovery for IPv6 peers ([#20842](https://github.com/docker/docker/pull/20842))
- Fix a panic during cleanup if a container was started with invalid options ([#21802](https://github.com/docker/docker/pull/21802))
- Fix a situation where a container cannot be stopped if the terminal is closed ([#21840](https://github.com/docker/docker/pull/21840))

### Security

* Object with the `pcp_pmcd_t` selinux type were given management access to `/var/lib/docker(/.*)?` ([#21370](https://github.com/docker/docker/pull/21370))
* `restart_syscall`, `copy_file_range`, `mlock2` joined the list of allowed calls in the default seccomp profile ([#21117](https://github.com/docker/docker/pull/21117), [#21262](https://github.com/docker/docker/pull/21262))
* `send`, `recv` and `x32` were added to the list of allowed syscalls and arch in the default seccomp profile ([#19432](https://github.com/docker/docker/pull/19432))
* Docker Content Trust now requests the server to perform snapshot signing ([#21046](https://github.com/docker/docker/pull/21046))
* Support for using YubiKeys for Content Trust signing has been moved out of experimental ([#21591](https://github.com/docker/docker/pull/21591))

### Volumes

* Output of `docker volume ls` is now sorted by volume name ([#20389](https://github.com/docker/docker/pull/20389))
* Local volumes can now accept options similar to the unix `mount` tool ([#20262](https://github.com/docker/docker/pull/20262))
- Fix an issue where one letter directory name could not be used as source for volumes ([#21106](https://github.com/docker/docker/pull/21106))
+ `docker run -v` now accepts a new flag `nocopy`. This tells the runtime not to copy the container path content into the volume (which is the default behavior) ([#21223](https://github.com/docker/docker/pull/21223))

## 1.10.3 (2016-03-10)

### Runtime

- Fix Docker client exiting with an "Unrecognized input header" error [#20706](https://github.com/docker/docker/pull/20706)
- Fix Docker exiting if Exec is started with both `AttachStdin` and `Detach` [#20647](https://github.com/docker/docker/pull/20647)

### Distribution

- Fix a crash when pushing multiple images sharing the same layers to the same repository in parallel [#20831](https://github.com/docker/docker/pull/20831)
- Fix a panic when pushing images to a registry which uses a misconfigured token service [#21030](https://github.com/docker/docker/pull/21030)

### Plugin system

- Fix issue preventing volume plugins to start when SELinux is enabled [#20834](https://github.com/docker/docker/pull/20834)
- Prevent Docker from exiting if a volume plugin returns a null response for Get requests [#20682](https://github.com/docker/docker/pull/20682)
- Fix plugin system leaking file descriptors if a plugin has an error [#20680](https://github.com/docker/docker/pull/20680)

### Security

- Fix linux32 emulation to fail during docker build [#20672](https://github.com/docker/docker/pull/20672)
  It was due to the `personality` syscall being blocked by the default seccomp profile.
- Fix Oracle XE 10g failing to start in a container [#20981](https://github.com/docker/docker/pull/20981)
  It was due to the `ipc` syscall being blocked by the default seccomp profile.
- Fix user namespaces not working on Linux From Scratch [#20685](https://github.com/docker/docker/pull/20685)
- Fix issue preventing daemon to start if userns is enabled and the `subuid` or `subgid` files contain comments [#20725](https://github.com/docker/docker/pull/20725)

## 1.10.2 (2016-02-22)

### Runtime

- Prevent systemd from deleting containers' cgroups when its configuration is reloaded [#20518](https://github.com/docker/docker/pull/20518)
- Fix SELinux issues by disregarding `--read-only` when mounting `/dev/mqueue` [#20333](https://github.com/docker/docker/pull/20333)
- Fix chown permissions used during `docker cp` when userns is used [#20446](https://github.com/docker/docker/pull/20446)
- Fix configuration loading issue with all booleans defaulting to `true` [#20471](https://github.com/docker/docker/pull/20471)
- Fix occasional panic with `docker logs -f` [#20522](https://github.com/docker/docker/pull/20522)

### Distribution

- Keep layer reference if deletion failed to avoid a badly inconsistent state [#20513](https://github.com/docker/docker/pull/20513)
- Handle gracefully a corner case when canceling migration [#20372](https://github.com/docker/docker/pull/20372)
- Fix docker import on compressed data [#20367](https://github.com/docker/docker/pull/20367)
- Fix tar-split files corruption during migration that later cause docker push and docker save to fail [#20458](https://github.com/docker/docker/pull/20458)

### Networking

- Fix daemon crash if embedded DNS is sent garbage [#20510](https://github.com/docker/docker/pull/20510)

### Volumes

- Fix issue with multiple volume references with same name [#20381](https://github.com/docker/docker/pull/20381)

### Security

- Fix potential cache corruption and delegation conflict issues [#20523](https://github.com/docker/docker/pull/20523)

## 1.10.1 (2016-02-11)

### Runtime

* Do not stop daemon on migration hard failure [#20156](https://github.com/docker/docker/pull/20156)
- Fix various issues with migration to content-addressable images [#20058](https://github.com/docker/docker/pull/20058)
- Fix ZFS permission bug with user namespaces [#20045](https://github.com/docker/docker/pull/20045)
- Do not leak /dev/mqueue from the host to all containers, keep it container-specific [#19876](https://github.com/docker/docker/pull/19876) [#20133](https://github.com/docker/docker/pull/20133)
- Fix `docker ps --filter before=...` to not show stopped containers without providing `-a` flag [#20135](https://github.com/docker/docker/pull/20135)

### Security

- Fix issue preventing docker events to work properly with authorization plugin [#20002](https://github.com/docker/docker/pull/20002)

### Distribution

* Add additional verifications and prevent from uploading invalid data to registries [#20164](https://github.com/docker/docker/pull/20164)
- Fix regression preventing uppercase characters in image reference hostname [#20175](https://github.com/docker/docker/pull/20175)

### Networking

- Fix embedded DNS for user-defined networks in the presence of firewalld [#20060](https://github.com/docker/docker/pull/20060)
- Fix issue where removing a network during shutdown left Docker inoperable [#20181](https://github.com/docker/docker/issues/20181) [#20235](https://github.com/docker/docker/issues/20235)
- Embedded DNS is now able to return compressed results [#20181](https://github.com/docker/docker/issues/20181)
- Fix port-mapping issue with `userland-proxy=false` [#20181](https://github.com/docker/docker/issues/20181)

### Logging

- Fix bug where tcp+tls protocol would be rejected [#20109](https://github.com/docker/docker/pull/20109)

### Volumes

- Fix issue whereby older volume drivers would not receive volume options [#19983](https://github.com/docker/docker/pull/19983)

### Misc

- Remove TasksMax from Docker systemd service [#20167](https://github.com/docker/docker/pull/20167)

## 1.10.0 (2016-02-04)

> [!IMPORTANT]
>
> Docker 1.10 uses a new content-addressable storage for images and layers.

A migration is performed the first time `docker` is run, and can take a significant amount of time depending on the number of images present. Refer to this page on the wiki for more information: https://github.com/docker/docker/wiki/Engine-v1.10.0-content-addressability-migration
We also released a cool migration utility that enables you to perform the migration before updating to reduce downtime.
Engine 1.10 migrator can be found on Docker Hub: https://hub.docker.com/r/docker/v1.10-migrator/

### Runtime

+ New `docker update` command that allows updating resource constraints on running containers [#15078](https://github.com/docker/docker/pull/15078)
+ Add `--tmpfs` flag to `docker run` to create a tmpfs mount in a container [#13587](https://github.com/docker/docker/pull/13587)
+ Add `--format` flag to `docker images` command [#17692](https://github.com/docker/docker/pull/17692)
+ Allow to set daemon configuration in a file and hot-reload it with the `SIGHUP` signal [#18587](https://github.com/docker/docker/pull/18587)
+ Updated docker events to include more meta-data and event types [#18888](https://github.com/docker/docker/pull/18888)
  This change is backward compatible in the API, but not on the CLI.
+ Add `--blkio-weight-device` flag to `docker run` [#13959](https://github.com/docker/docker/pull/13959)
+ Add `--device-read-bps` and `--device-write-bps` flags to `docker run` [#14466](https://github.com/docker/docker/pull/14466)
+ Add `--device-read-iops` and `--device-write-iops` flags to `docker run` [#15879](https://github.com/docker/docker/pull/15879)
+ Add `--oom-score-adj` flag to `docker run` [#16277](https://github.com/docker/docker/pull/16277)
+ Add `--detach-keys` flag to `attach`, `run`, `start` and `exec` commands to override the default key sequence that detaches from a container  [#15666](https://github.com/docker/docker/pull/15666)
+ Add `--shm-size` flag to `run`, `create` and `build` to set the size of `/dev/shm` [#16168](https://github.com/docker/docker/pull/16168)
+ Show the number of running, stopped, and paused containers in `docker info` [#19249](https://github.com/docker/docker/pull/19249)
+ Show the `OSType` and `Architecture` in `docker info` [#17478](https://github.com/docker/docker/pull/17478)
+ Add `--cgroup-parent` flag on `daemon` to set cgroup parent for all containers [#19062](https://github.com/docker/docker/pull/19062)
+ Add `-L` flag to docker cp to follow symlinks [#16613](https://github.com/docker/docker/pull/16613)
+ New `status=dead` filter for `docker ps` [#17908](https://github.com/docker/docker/pull/17908)
* Change `docker run` exit codes to distinguish between runtime and application errors [#14012](https://github.com/docker/docker/pull/14012)
* Enhance `docker events --since` and `--until` to support nanoseconds and timezones [#17495](https://github.com/docker/docker/pull/17495)
* Add `--all`/`-a` flag to `stats` to include both running and stopped containers [#16742](https://github.com/docker/docker/pull/16742)
* Change the default cgroup-driver to `cgroupfs` [#17704](https://github.com/docker/docker/pull/17704)
* Emit a "tag" event when tagging an image with `build -t` [#17115](https://github.com/docker/docker/pull/17115)
* Best effort for linked containers' start order when starting the daemon [#18208](https://github.com/docker/docker/pull/18208)
* Add ability to add multiple tags on `build` [#15780](https://github.com/docker/docker/pull/15780)
* Permit `OPTIONS` request against any url, thus fixing issue with CORS [#19569](https://github.com/docker/docker/pull/19569)
- Fix the `--quiet` flag on `docker build` to actually be quiet [#17428](https://github.com/docker/docker/pull/17428)
- Fix `docker images --filter dangling=false` to now show all non-dangling images [#19326](https://github.com/docker/docker/pull/19326)
- Fix race condition causing autorestart turning off on restart [#17629](https://github.com/docker/docker/pull/17629)
- Recognize GPFS filesystems [#19216](https://github.com/docker/docker/pull/19216)
- Fix obscure bug preventing to start containers [#19751](https://github.com/docker/docker/pull/19751)
- Forbid `exec` during container restart [#19722](https://github.com/docker/docker/pull/19722)
- devicemapper: Increasing `--storage-opt dm.basesize` will now increase the base device size on daemon restart [#19123](https://github.com/docker/docker/pull/19123)

### Security

+ Add `--userns-remap` flag to `daemon` to support user namespaces (previously in experimental) [#19187](https://github.com/docker/docker/pull/19187)
+ Add support for custom seccomp profiles in `--security-opt` [#17989](https://github.com/docker/docker/pull/17989)
+ Add default seccomp profile [#18780](https://github.com/docker/docker/pull/18780)
+ Add `--authorization-plugin` flag to `daemon` to customize ACLs [#15365](https://github.com/docker/docker/pull/15365)
+ Docker Content Trust now supports the ability to read and write user delegations [#18887](https://github.com/docker/docker/pull/18887)
  This is an optional, opt-in feature that requires the explicit use of the Notary command-line utility in order to be enabled.
  Enabling delegation support in a specific repository will break the ability of Docker 1.9 and 1.8 to pull from that repository, if content trust is enabled.
* Allow SELinux to run in a container when using the BTRFS storage driver [#16452](https://github.com/docker/docker/pull/16452)

### Distribution

* Use content-addressable storage for images and layers [#17924](https://github.com/docker/docker/pull/17924)
  A migration is performed the first time docker is run; it can take a significant amount of time depending on the number of images and containers present.
  Images no longer depend on the parent chain but contain a list of layer references.
  `docker load`/`docker save` tarballs now also contain content-addressable image configurations.
  For more information: https://github.com/docker/docker/wiki/Engine-v1.10.0-content-addressability-migration
* Add support for the new [manifest format ("schema2")](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md) [#18785](https://github.com/docker/docker/pull/18785)
* Lots of improvements for push and pull: performance++, retries on failed downloads, cancelling on client disconnect [#18353](https://github.com/docker/docker/pull/18353), [#18418](https://github.com/docker/docker/pull/18418), [#19109](https://github.com/docker/docker/pull/19109), [#18353](https://github.com/docker/docker/pull/18353)
* Limit v1 protocol fallbacks [#18590](https://github.com/docker/docker/pull/18590)
- Fix issue where docker could hang indefinitely waiting for a nonexistent process to pull an image [#19743](https://github.com/docker/docker/pull/19743)

### Networking

+ Use DNS-based discovery instead of `/etc/hosts` [#19198](https://github.com/docker/docker/pull/19198)
+ Support for network-scoped alias using `--net-alias` on `run` and `--alias` on `network connect` [#19242](https://github.com/docker/docker/pull/19242)
+ Add `--ip` and `--ip6` on `run` and `network connect` to support custom IP addresses for a container in a network [#19001](https://github.com/docker/docker/pull/19001)
+ Add `--ipam-opt` to `network create` for passing custom IPAM options [#17316](https://github.com/docker/docker/pull/17316)
+ Add `--internal` flag to `network create` to restrict external access to and from the network [#19276](https://github.com/docker/docker/pull/19276)
+ Add `kv.path` option to `--cluster-store-opt` [#19167](https://github.com/docker/docker/pull/19167)
+ Add `discovery.heartbeat` and `discovery.ttl` options to `--cluster-store-opt` to configure discovery TTL and heartbeat timer [#18204](https://github.com/docker/docker/pull/18204)
+ Add `--format` flag to `network inspect` [#17481](https://github.com/docker/docker/pull/17481)
+ Add `--link` to `network connect` to provide a container-local alias [#19229](https://github.com/docker/docker/pull/19229)
+ Support for Capability exchange with remote IPAM plugins [#18775](https://github.com/docker/docker/pull/18775)
+ Add `--force` to `network disconnect` to force container to be disconnected from network [#19317](https://github.com/docker/docker/pull/19317)
* Support for multi-host networking using built-in overlay driver for all engine supported kernels: 3.10+ [#18775](https://github.com/docker/docker/pull/18775)
* `--link` is now supported on `docker run` for containers in user-defined network [#19229](https://github.com/docker/docker/pull/19229)
* Enhance `docker network rm` to allow removing multiple networks [#17489](https://github.com/docker/docker/pull/17489)
* Include container names in `network inspect` [#17615](https://github.com/docker/docker/pull/17615)
* Include auto-generated subnets for user-defined networks in `network inspect` [#17316](https://github.com/docker/docker/pull/17316)
* Add `--filter` flag to `network ls` to hide predefined networks [#17782](https://github.com/docker/docker/pull/17782)
* Add support for network connect/disconnect to stopped containers [#18906](https://github.com/docker/docker/pull/18906)
* Add network ID to container inspect [#19323](https://github.com/docker/docker/pull/19323)
- Fix MTU issue where Docker would not start with two or more default routes [#18108](https://github.com/docker/docker/pull/18108)
- Fix duplicate IP address for containers [#18106](https://github.com/docker/docker/pull/18106)
- Fix issue preventing sometimes docker from creating the bridge network [#19338](https://github.com/docker/docker/pull/19338)
- Do not substitute 127.0.0.1 name server when using `--net=host` [#19573](https://github.com/docker/docker/pull/19573)

### Logging

+ New logging driver for Splunk [#16488](https://github.com/docker/docker/pull/16488)
+ Add support for syslog over TCP+TLS [#18998](https://github.com/docker/docker/pull/18998)
* Enhance `docker logs --since` and `--until` to support nanoseconds and time [#17495](https://github.com/docker/docker/pull/17495)
* Enhance AWS logs to auto-detect region [#16640](https://github.com/docker/docker/pull/16640)

### Volumes

+ Add support to set the mount propagation mode for a volume [#17034](https://github.com/docker/docker/pull/17034)
* Add `ls` and `inspect` endpoints to volume plugin API [#16534](https://github.com/docker/docker/pull/16534)
  Existing plugins need to make use of these new APIs to satisfy users' expectation
  For that, use the new MIME type `application/vnd.docker.plugins.v1.2+json` [#19549](https://github.com/docker/docker/pull/19549)
- Fix data not being copied to named volumes [#19175](https://github.com/docker/docker/pull/19175)
- Fix issues preventing volume drivers from being containerized [#19500](https://github.com/docker/docker/pull/19500)
- Fix `docker volumes ls --dangling=false` to now show all non-dangling volumes [#19671](https://github.com/docker/docker/pull/19671)
- Do not remove named volumes on container removal [#19568](https://github.com/docker/docker/pull/19568)
- Allow external volume drivers to host anonymous volumes [#19190](https://github.com/docker/docker/pull/19190)

### Builder

+ Add support for `**` in `.dockerignore` to wildcard multiple levels of directories [#17090](https://github.com/docker/docker/pull/17090)
- Fix handling of UTF-8 characters in Dockerfiles [#17055](https://github.com/docker/docker/pull/17055)
- Fix permissions problem when reading from STDIN [#19283](https://github.com/docker/docker/pull/19283)

### Client

+ Add support for overriding the API version to use via an `DOCKER_API_VERSION` environment-variable [#15964](https://github.com/docker/docker/pull/15964)
- Fix a bug preventing Windows clients to log in to Docker Hub [#19891](https://github.com/docker/docker/pull/19891)

### Misc

* systemd: Set TasksMax in addition to LimitNPROC in systemd service file [#19391](https://github.com/docker/docker/pull/19391)

### Deprecations

* Remove LXC support. The LXC driver was deprecated in Docker 1.8, and has now been removed [#17700](https://github.com/docker/docker/pull/17700)
* Remove `--exec-driver` daemon flag, because it is no longer in use [#17700](https://github.com/docker/docker/pull/17700)
* Remove old deprecated single-dashed long CLI flags (such as `-rm`; use `--rm` instead) [#17724](https://github.com/docker/docker/pull/17724)
* Deprecate HostConfig at API container start [#17799](https://github.com/docker/docker/pull/17799)
* Deprecate docker packages for newly EOL'd Linux distributions: Fedora 21 and Ubuntu 15.04 (Vivid) [#18794](https://github.com/docker/docker/pull/18794), [#18809](https://github.com/docker/docker/pull/18809)
* Deprecate `-f` flag for docker tag [#18350](https://github.com/docker/docker/pull/18350)

## 1.9.1 (2015-11-21)

### Runtime

- Do not prevent daemon from booting if images could not be restored (#17695)
- Force IPC mount to unmount on daemon shutdown/init (#17539)
- Turn IPC unmount errors into warnings (#17554)
- Fix `docker stats` performance regression (#17638)
- Clarify cryptic error message upon `docker logs` if `--log-driver=none` (#17767)
- Fix seldom panics (#17639, #17634, #17703)
- Fix opq whiteouts problems for files with dot prefix (#17819)
- devicemapper: try defaulting to xfs instead of ext4 for performance reasons (#17903, #17918)
- devicemapper: fix displayed fs in docker info (#17974)
- selinux: only relabel if user requested so with the `z` option (#17450, #17834)
- Do not make network calls when normalizing names (#18014)

### Client

- Fix `docker login` on windows (#17738)
- Fix bug with `docker inspect` output when not connected to daemon (#17715)
- Fix `docker inspect -f {{.HostConfig.Dns}} somecontainer` (#17680)

### Builder

- Fix regression with symlink behavior in ADD/COPY (#17710)

### Networking

- Allow passing a network ID as an argument for `--net` (#17558)
- Fix connect to host and prevent disconnect from host for `host` network (#17476)
- Fix `--fixed-cidr` issue when gateway ip falls in ip-range and ip-range is
  not the first block in the network (#17853)
- Restore deterministic `IPv6` generation from `MAC` address on default `bridge` network (#17890)
- Allow port-mapping only for endpoints created on docker run (#17858)
- Fixed an endpoint delete issue with a possible stale sbox (#18102)

### Distribution

- Correct parent chain in v2 push when v1Compatibility files on the disk are inconsistent (#18047)

## 1.9.0 (2015-11-03)

### Runtime

+ `docker stats` now returns block IO metrics (#15005)
+ `docker stats` now details network stats per interface (#15786)
+ Add `ancestor=<image>` filter to `docker ps --filter` flag to filter
containers based on their ancestor images (#14570)
+ Add `label=<somelabel>` filter to `docker ps --filter` to filter containers
based on label (#16530)
+ Add `--kernel-memory` flag to `docker run` (#14006)
+ Add `--message` flag to `docker import` allowing to specify an optional
message (#15711)
+ Add `--privileged` flag to `docker exec` (#14113)
+ Add `--stop-signal` flag to `docker run` allowing to replace the container
process stopping signal (#15307)
+ Add a new `unless-stopped` restart policy (#15348)
+ Inspecting an image now returns tags (#13185)
+ Add container size information to `docker inspect` (#15796)
+ Add `RepoTags` and `RepoDigests` field to `/images/{name:.*}/json` (#17275)
- Remove the deprecated `/container/ps` endpoint from the API (#15972)
- Send and document correct HTTP codes for `/exec/<name>/start` (#16250)
- Share shm and mqueue between containers sharing IPC namespace (#15862)
- Event stream now shows OOM status when `--oom-kill-disable` is set (#16235)
- Ensure special network files (/etc/hosts etc.) are read-only if bind-mounted
with `ro` option (#14965)
- Improve `rmi` performance (#16890)
- Do not update /etc/hosts for the default bridge network, except for links (#17325)
- Fix conflict with duplicate container names (#17389)
- Fix an issue with incorrect template execution in `docker inspect` (#17284)
- DEPRECATE `-c` short flag variant for `--cpu-shares` in docker run (#16271)

### Client

+ Allow `docker import` to import from local files (#11907)

### Builder

+ Add a `STOPSIGNAL` Dockerfile instruction allowing to set a different
stop-signal for the container process (#15307)
+ Add an `ARG` Dockerfile instruction and a `--build-arg` flag to `docker build`
that allows to add build-time environment variables (#15182)
- Improve cache miss performance (#16890)

### Storage

- devicemapper: Implement deferred deletion capability (#16381)

### Networking

+ `docker network` exits experimental and is part of standard release (#16645)
+ New network top-level concept, with associated subcommands and API (#16645)
  WARNING: the API is different from the experimental API
+ Support for multiple isolated/micro-segmented networks (#16645)
+ Built-in multihost networking using VXLAN based overlay driver (#14071)
+ Support for third-party network plugins (#13424)
+ Ability to dynamically connect containers to multiple networks (#16645)
+ Support for user-defined IP address management via pluggable IPAM drivers (#16910)
+ Add daemon flags `--cluster-store` and `--cluster-advertise` for built-in nodes discovery (#16229)
+ Add `--cluster-store-opt` for setting up TLS settings (#16644)
+ Add `--dns-opt` to the daemon (#16031)
- DEPRECATE following container `NetworkSettings` fields in API v1.21: `EndpointID`, `Gateway`,
  `GlobalIPv6Address`, `GlobalIPv6PrefixLen`, `IPAddress`, `IPPrefixLen`, `IPv6Gateway` and `MacAddress`.
  Those are now specific to the `bridge` network. Use `NetworkSettings.Networks` to inspect
  the networking settings of a container per network.

### Volumes

+ New top-level `volume` subcommand and API (#14242)
- Move API volume driver settings to host-specific config (#15798)
- Print an error message if volume name is not unique (#16009)
- Ensure volumes created from Dockerfiles always use the local volume driver
(#15507)
- DEPRECATE auto-creating missing host paths for bind mounts (#16349)

### Logging

+ Add `awslogs` logging driver for Amazon CloudWatch (#15495)
+ Add generic `tag` log option to allow customizing container/image
information passed to driver (#15384)
- Implement the `docker logs` endpoint for the journald driver (#13707)
- DEPRECATE driver-specific log tags (#15384)

### Distribution

+ `docker search` now works with partial names (#16509)
- Push optimization: avoid buffering to file (#15493)
- The daemon will display progress for images that were already being pulled
by another client (#15489)
- Only permissions required for the current action being performed are requested (#)
+ Renaming trust keys (and respective environment variables) from `offline` to
`root` and `tagging` to `repository` (#16894)
- DEPRECATE trust key environment variables
`DOCKER_CONTENT_TRUST_OFFLINE_PASSPHRASE` and
`DOCKER_CONTENT_TRUST_TAGGING_PASSPHRASE` (#16894)

### Security

+ Add SELinux profiles to the rpm package (#15832)
- Fix various issues with AppArmor profiles provided in the deb package
(#14609)
- Add AppArmor policy that prevents writing to /proc (#15571)

## 1.8.3 (2015-10-12)

### Distribution

- Fix layer IDs lead to local graph poisoning (CVE-2014-8178)
- Fix manifest validation and parsing logic errors allow pull-by-digest validation bypass (CVE-2014-8179)
+ Add `--disable-legacy-registry` to prevent a daemon from using a v1 registry

## 1.8.2 (2015-09-10)

### Distribution

- Fixes rare edge case of handling GNU LongLink and LongName entries.
- Fix ^C on docker pull.
- Fix docker pull issues on client disconnection.
- Fix issue that caused the daemon to panic when loggers weren't configured properly.
- Fix goroutine leak pulling images from registry V2.

### Runtime

- Fix a bug mounting cgroups for docker daemons running inside docker containers.
- Initialize log configuration properly.

### Client:

- Handle `-q` flag in `docker ps` properly when there is a default format.

### Networking

- Fix several corner cases with netlink.

### Contrib

- Fix several issues with bash completion.

## 1.8.1 (2015-08-12)

### Distribution

* Fix a bug where pushing multiple tags would result in invalid images

## 1.8.0 (2015-08-11)

### Distribution

+ Trusted pull, push and build, disabled by default
* Make tar layers deterministic between registries
* Don't allow deleting the image of running containers
* Check if a tag name to load is a valid digest
* Allow one character repository names
* Add a more accurate error description for invalid tag name
* Make build cache ignore mtime

### Cli

+ Add support for DOCKER_CONFIG/--config to specify config file dir
+ Add --type flag  for docker inspect command
+ Add formatting options to `docker ps` with `--format`
+ Replace `docker -d` with new subcommand `docker daemon`
* Zsh completion updates and improvements
* Add some missing events to bash completion
* Support daemon urls with base paths in `docker -H`
* Validate status= filter to docker ps
* Display when a container is in --net=host in docker ps
* Extend docker inspect to export image metadata related to graph driver
* Restore --default-gateway{,-v6} daemon options
* Add missing unpublished ports in docker ps
* Allow duration strings in `docker events` as --since/--until
* Expose more mounts information in `docker inspect`

### Runtime

+ Add new Fluentd logging driver
+ Allow `docker import` to load from local files
+ Add logging driver for GELF via UDP
+ Allow to copy files from host to containers with `docker cp`
+ Promote volume drivers from experimental to master
+ Add rollover options to json-file log driver, and --log-driver-opts flag
+ Add memory swappiness tuning options
* Remove cgroup read-only flag when privileged
* Make /proc, /sys, & /dev readonly for readonly containers
* Add cgroup bind mount by default
* Overlay: Export metadata for container and image in `docker inspect`
* Devicemapper: external device activation
* Devicemapper: Compare uuid of base device on startup
* Remove RC4 from the list of registry cipher suites
* Add syslog-facility option
* LXC execdriver compatibility with recent LXC versions
* Mark LXC execriver as deprecated (to be removed with the migration to runc)

### Plugins

* Separate plugin sockets and specs locations
* Allow TLS connections to plugins

### Bug fixes

- Add missing 'Names' field to /containers/json API output
- Make `docker rmi` of dangling images safe while pulling
- Devicemapper: Change default basesize to 100G
- Go Scheduler issue with sync.Mutex and gcc
- Fix issue where Search API endpoint would panic due to empty AuthConfig
- Set image canonical names correctly
- Check dockerinit only if lxc driver is used
- Fix ulimit usage of nproc
- Always attach STDIN if -i,--interactive is specified
- Show error messages when saving container state fails
- Fixed incorrect assumption on --bridge=none treated as disable network
- Check for invalid port specifications in host configuration
- Fix endpoint leave failure for --net=host mode
- Fix goroutine leak in the stats API if the container is not running
- Check for apparmor file before reading it
- Fix DOCKER_TLS_VERIFY being ignored
- Set umask to the default on startup
- Correct the message of pause and unpause a non-running container
- Adjust disallowed CpuShares in container creation
- ZFS: correctly apply selinux context
- Display empty string instead of <nil> when IP opt is nil
- `docker kill` returns error when container is not running
- Fix COPY/ADD quoted/json form
- Fix goroutine leak on logs -f with no output
- Remove panic in nat package on invalid hostport
- Fix container linking in Fedora 22
- Fix error caused using default gateways outside of the allocated range
- Format times in inspect command with a template as RFC3339Nano
- Make registry client to accept 2xx and 3xx http status responses as successful
- Fix race issue that caused the daemon to crash with certain layer downloads failed in a specific order.
- Fix error when the docker ps format was not valid.
- Remove redundant ip forward check.
- Fix issue trying to push images to repository mirrors.
- Fix error cleaning up network entrypoints when there is an initialization issue.

## 1.7.1 (2015-07-14)

### Runtime

- Fix default user spawning exec process with `docker exec`
- Make `--bridge=none` not to configure the network bridge
- Publish networking stats properly
- Fix implicit devicemapper selection with static binaries
- Fix socket connections that hung intermittently
- Fix bridge interface creation on CentOS/RHEL 6.6
- Fix local dns lookups added to resolv.conf
- Fix copy command mounting volumes
- Fix read/write privileges in volumes mounted with --volumes-from

### Remote API

- Fix unmarshalling of Command and Entrypoint
- Set limit for minimum client version supported
- Validate port specification
- Return proper errors when attach/reattach fail

### Distribution

- Fix pulling private images
- Fix fallback between registry V2 and V1

## 1.7.0 (2015-06-16)

### Runtime
+ Experimental feature: support for out-of-process volume plugins
* The userland proxy can be disabled in favor of hairpin NAT using the daemon’s `--userland-proxy=false` flag
* The `exec` command supports the `-u|--user` flag to specify the new process owner
+ Default gateway for containers can be specified daemon-wide using the `--default-gateway` and `--default-gateway-v6` flags
+ The CPU CFS (Completely Fair Scheduler) quota can be set in `docker run` using `--cpu-quota`
+ Container block IO can be controlled in `docker run` using`--blkio-weight`
+ ZFS support
+ The `docker logs` command supports a `--since` argument
+ UTS namespace can be shared with the host with `docker run --uts=host`

### Quality
* Networking stack was entirely rewritten as part of the libnetwork effort
* Engine internals refactoring
* Volumes code was entirely rewritten to support the plugins effort
+ Sending SIGUSR1 to a daemon will dump all goroutines stacks without exiting

### Build
+ Support ${variable:-value} and ${variable:+value} syntax for environment variables
+ Support resource management flags `--cgroup-parent`, `--cpu-period`, `--cpu-quota`, `--cpuset-cpus`, `--cpuset-mems`
+ git context changes with branches and directories
* The .dockerignore file support exclusion rules

### Distribution
+ Client support for v2 mirroring support for the official registry

### Bugfixes
* Firewalld is now supported and will automatically be used when available
* mounting --device recursively

## 1.6.2 (2015-05-13)

### Runtime
- Revert change prohibiting mounting into /sys

## 1.6.1 (2015-05-07)

### Security
- Fix read/write /proc paths (CVE-2015-3630)
- Prohibit VOLUME /proc and VOLUME / (CVE-2015-3631)
- Fix opening of file-descriptor 1 (CVE-2015-3627)
- Fix symlink traversal on container respawn allowing local privilege escalation (CVE-2015-3629)
- Prohibit mount of /sys

### Runtime
- Update AppArmor policy to not allow mounts

## 1.6.0 (2015-04-07)

### Builder
+ Building images from an image ID
+ Build containers with resource constraints, ie `docker build --cpu-shares=100 --memory=1024m...`
+ `commit --change` to apply specified Dockerfile instructions while committing the image
+ `import --change` to apply specified Dockerfile instructions while importing the image
+ Builds no longer continue in the background when canceled with CTRL-C

### Client
+ Windows Support

### Runtime
+ Container and image Labels
+ `--cgroup-parent` for specifying a parent cgroup to place container cgroup within
+ Logging drivers, `json-file`, `syslog`, or `none`
+ Pulling images by ID
+ `--ulimit` to set the ulimit on a container
+ `--default-ulimit` option on the daemon which applies to all created containers (and overwritten by `--ulimit` on run)

## 1.5.0 (2015-02-10)

### Builder
+ Dockerfile to use for a given `docker build` can be specified with the `-f` flag
* Dockerfile and .dockerignore files can be themselves excluded as part of the .dockerignore file, thus preventing modifications to these files invalidating ADD or COPY instructions cache
* ADD and COPY instructions accept relative paths
* Dockerfile `FROM scratch` instruction is now interpreted as a no-base specifier
* Improve performance when exposing a large number of ports

### Hack
+ Allow client-side only integration tests for Windows
* Include docker-py integration tests against Docker daemon as part of our test suites

### Packaging
+ Support for the new version of the registry HTTP API
* Speed up `docker push` for images with a majority of already existing layers
- Fixed contacting a private registry through a proxy

### Remote API
+ A new endpoint will stream live container resource metrics and can be accessed with the `docker stats` command
+ Containers can be renamed using the new `rename` endpoint and the associated `docker rename` command
* Container `inspect` endpoint show the ID of `exec` commands running in this container
* Container `inspect` endpoint show the number of times Docker auto-restarted the container
* New types of event can be streamed by the `events` endpoint: ‘OOM’ (container died with out of memory), ‘exec_create’, and ‘exec_start'
- Fixed returned string fields which hold numeric characters incorrectly omitting surrounding double quotes

### Runtime
+ Docker daemon has full IPv6 support
+ The `docker run` command can take the `--pid=host` flag to use the host PID namespace, which makes it possible for example to debug host processes using containerized debugging tools
+ The `docker run` command can take the `--read-only` flag to make the container’s root filesystem mounted as readonly, which can be used in combination with volumes to force a container’s processes to only write to locations that will be persisted
+ Container total memory usage can be limited for `docker run` using the `--memory-swap` flag
* Major stability improvements for devicemapper storage driver
* Better integration with host system: containers will reflect changes to the host's `/etc/resolv.conf` file when restarted
* Better integration with host system: per-container iptable rules are moved to the DOCKER chain
- Fixed container exiting on out of memory to return an invalid exit code

### Other
* The HTTP_PROXY, HTTPS_PROXY, and NO_PROXY environment variables are properly taken into account by the client when connecting to the Docker daemon

## 1.4.1 (2014-12-15)

### Runtime
- Fix issue with volumes-from and bind mounts not being honored after create

## 1.4.0 (2014-12-11)

### Notable Features since 1.3.0
+ Set key=value labels to the daemon (displayed in `docker info`), applied with
  new `-label` daemon flag
+ Add support for `ENV` in Dockerfile of the form:
  `ENV name=value name2=value2...`
+ New Overlayfs Storage Driver
+ `docker info` now returns an `ID` and `Name` field
+ Filter events by event name, container, or image
+ `docker cp` now supports copying from container volumes
- Fixed `docker tag`, so it honors `--force` when overriding a tag for existing
  image.

## 1.3.3 (2014-12-11)

### Security
- Fix path traversal vulnerability in processing of absolute symbolic links (CVE-2014-9356)
- Fix decompression of xz image archives, preventing privilege escalation (CVE-2014-9357)
- Validate image IDs (CVE-2014-9358)

### Runtime
- Fix an issue when image archives are being read slowly

### Client
- Fix a regression related to stdin redirection
- Fix a regression with `docker cp` when destination is the current directory

## 1.3.2 (2014-11-20)

### Security
- Fix tar breakout vulnerability
* Extractions are now sandboxed chroot
- Security options are no longer committed to images

### Runtime
- Fix deadlock in `docker ps -f exited=1`
- Fix a bug when `--volumes-from` references a container that failed to start

### Registry
+ `--insecure-registry` now accepts CIDR notation such as 10.1.0.0/16
* Private registries whose IPs fall in the 127.0.0.0/8 range do no need the `--insecure-registry` flag
- Skip the experimental registry v2 API when mirroring is enabled

## 1.3.1 (2014-10-28)

### Security
* Prevent fallback to SSL protocols < TLS 1.0 for client, daemon and registry
+ Secure HTTPS connection to registries with certificate verification and without HTTP fallback unless `--insecure-registry` is specified

### Runtime
- Fix issue where volumes would not be shared

### Client
- Fix issue with `--iptables=false` not automatically setting `--ip-masq=false`
- Fix docker run output to non-TTY stdout

### Builder
- Fix escaping `$` for environment variables
- Fix issue with lowercase `onbuild` Dockerfile instruction
- Restrict environment variable expansion to `ENV`, `ADD`, `COPY`, `WORKDIR`, `EXPOSE`, `VOLUME` and `USER`

## 1.3.0 (2014-10-14)

### Notable features since 1.2.0
+ Docker `exec` allows you to run additional processes inside existing containers
+ Docker `create` gives you the ability to create a container via the CLI without executing a process
+ `--security-opts` options to allow user to customize container labels and apparmor profiles
+ Docker `ps` filters
- Wildcard support to COPY/ADD
+ Move production URLs to get.docker.com from get.docker.io
+ Allocate IP address on the bridge inside a valid CIDR
+ Use drone.io for PR and CI testing
+ Ability to setup an official registry mirror
+ Ability to save multiple images with docker `save`

## 1.2.0 (2014-08-20)

### Runtime
+ Make /etc/hosts /etc/resolv.conf and /etc/hostname editable at runtime
+ Auto-restart containers using policies
+ Use /var/lib/docker/tmp for large temporary files
+ `--cap-add` and `--cap-drop` to tweak what linux capability you want
+ `--device` to use devices in containers

### Client
+ `docker search` on private registries
+ Add `exited` filter to `docker ps --filter`
* `docker rm -f` now kills instead of stop
+ Support for IPv6 addresses in `--dns` flag

### Proxy
+ Proxy instances in separate processes
* Small bug fix on UDP proxy

## 1.1.2 (2014-07-23)

### Runtime
+ Fix port allocation for existing containers
+ Fix containers restart on daemon restart

### Packaging
+ Fix /etc/init.d/docker issue on Debian

## 1.1.1 (2014-07-09)

### Builder
* Fix issue with ADD

## 1.1.0 (2014-07-03)

### Notable features since 1.0.1
+ Add `.dockerignore` support
+ Pause containers during `docker commit`
+ Add `--tail` to `docker logs`

### Builder
+ Allow a tar file as context for `docker build`
* Fix issue with white-spaces and multi-lines in `Dockerfiles`

### Runtime
* Overall performance improvements
* Allow `/` as source of `docker run -v`
* Fix port allocation
* Fix bug in `docker save`
* Add links information to `docker inspect`

### Client
* Improve command line parsing for `docker commit`

### Remote API
* Improve status code for the `start` and `stop` endpoints

## 1.0.1 (2014-06-19)

### Notable features since 1.0.0
* Enhance security for the LXC driver

### Builder
* Fix `ONBUILD` instruction passed to grandchildren

### Runtime
* Fix events subscription
* Fix /etc/hostname file with host networking
* Allow `-h` and `--net=none`
* Fix issue with hotplug devices in `--privileged`

### Client
* Fix artifacts with events
* Fix a panic with empty flags
* Fix `docker cp` on Mac OS X

### Miscellaneous
* Fix compilation on Mac OS X
* Fix several races

## 1.0.0 (2014-06-09)

### Notable features since 0.12.0
* Production support

## 0.12.0 (2014-06-05)

### Notable features since 0.11.0
* 40+ various improvements to stability, performance and usability
* New `COPY` Dockerfile instruction to allow copying a local file from the context into the container without ever extracting if the file is a tar file
* Inherit file permissions from the host on `ADD`
* New `pause` and `unpause` commands to allow pausing and unpausing of containers using cgroup freezer
* The `images` command has a `-f`/`--filter` option to filter the list of images
* Add `--force-rm` to clean up after a failed build
* Standardize JSON keys in Remote API to CamelCase
* Pull from a docker run now assumes `latest` tag if not specified
* Enhance security on Linux capabilities and device nodes

## 0.11.1 (2014-05-07)

### Registry
- Fix push and pull to private registry

## 0.11.0 (2014-05-07)

### Notable features since 0.10.0

* SELinux support for mount and process labels
* Linked containers can be accessed by hostname
* Use the net `--net` flag to allow advanced network configuration such as host networking so that containers can use the host's network interfaces
* Add a ping endpoint to the Remote API to do healthchecks of your docker daemon
* Logs can now be returned with an optional timestamp
* Docker now works with registries that support SHA-512
* Multiple registry endpoints are supported to allow registry mirrors

## 0.10.0 (2014-04-08)

### Builder
- Fix printing multiple messages on a single line. Fixes broken output during builds.
- Follow symlinks inside container's root for ADD build instructions.
- Fix EXPOSE caching.

### Documentation
- Add the new options of `docker ps` to the documentation.
- Add the options of `docker restart` to the documentation.
- Update daemon docs and help messages for --iptables and --ip-forward.
- Updated apt-cacher-ng docs example.
- Remove duplicate description of --mtu from docs.
- Add missing -t and -v for `docker images` to the docs.
- Add fixes to the cli docs.
- Update libcontainer docs.
- Update images in docs to remove references to AUFS and LXC.
- Update the nodejs_web_app in the docs to use the new epel RPM address.
- Fix external link on security of containers.
- Update remote API docs.
- Add image size to history docs.
- Be explicit about binding to all interfaces in redis example.
- Document DisableNetwork flag in the 1.10 remote api.
- Document that `--lxc-conf` is lxc only.
- Add chef usage documentation.
- Add example for an image with multiple for `docker load`.
- Explain what `docker run -a` does in the docs.

### Contrib
- Add variable for DOCKER_LOGFILE to sysvinit and use append instead of overwrite in opening the logfile.
- Fix init script cgroup mounting workarounds to be more similar to cgroupfs-mount and thus work properly.
- Remove inotifywait hack from the upstart host-integration example because it's not necessary any more.
- Add check-config script to contrib.
- Fix fish shell completion.

### Hack
* Clean up "go test" output from "make test" to be much more readable/scannable.
* Exclude more "definitely not unit tested Go source code" directories from hack/make/test.
+ Generate md5 and sha256 hashes when building, and upload them via hack/release.sh.
- Include contributed completions in Ubuntu PPA.
+ Add cli integration tests.
* Add tweaks to the hack scripts to make them simpler.

### Remote API
+ Add TLS auth support for API.
* Move git clone from daemon to client.
- Fix content-type detection in docker cp.
* Split API into 2 go packages.

### Runtime
* Support hairpin NAT without going through Docker server.
- devicemapper: succeed immediately when removing non-existent devices.
- devicemapper: improve handling of devicemapper devices (add per device lock, increase sleep time and unlock while sleeping).
- devicemapper: increase timeout in waitClose to 10 seconds.
- devicemapper: ensure we shut down thin pool cleanly.
- devicemapper: pass info, rather than hash to activateDeviceIfNeeded, deactivateDevice, setInitialized, deleteDevice.
- devicemapper: avoid AB-BA deadlock.
- devicemapper: make shutdown better/faster.
- improve alpha sorting in mflag.
- Remove manual http cookie management because the cookiejar is being used.
- Use BSD raw mode on Darwin. Fixes nano, tmux and others.
- Add FreeBSD support for the client.
- Merge auth package into registry.
- Add deprecation warning for -t on `docker pull`.
- Remove goroutine leak on error.
- Update parseLxcInfo to comply with new lxc1.0 format.
- Fix attach exit on darwin.
- Improve deprecation message.
- Retry to retrieve the layer metadata up to 5 times for `docker pull`.
- Only unshare the mount namespace for execin.
- Merge existing config when committing.
- Disable daemon startup timeout.
- Fix issue #4681: add loopback interface when networking is disabled.
- Add failing test case for issue #4681.
- Send SIGTERM to child, instead of SIGKILL.
- Show the driver and the kernel version in `docker info` even when not in debug mode.
- Always symlink /dev/ptmx for libcontainer. This fixes console related problems.
- Fix issue caused by the absence of /etc/apparmor.d.
- Don't leave empty cidFile behind when failing to create the container.
- Mount cgroups automatically if they're not mounted already.
- Use mock for search tests.
- Update to double-dash everywhere.
- Move .dockerenv parsing to lxc driver.
- Move all bind-mounts in the container inside the namespace.
- Don't use separate bind mount for container.
- Always symlink /dev/ptmx for libcontainer.
- Don't kill by pid for other drivers.
- Add initial logging to libcontainer.
* Sort by port in `docker ps`.
- Move networking drivers into runtime top level package.
+ Add --no-prune to `docker rmi`.
+ Add time since exit in `docker ps`.
- graphdriver: add build tags.
- Prevent allocation of previously allocated ports & prevent improve port allocation.
* Add support for --since/--before in `docker ps`.
- Clean up container stop.
+ Add support for configurable dns search domains.
- Add support for relative WORKDIR instructions.
- Add --output flag for docker save.
- Remove duplication of DNS entries in config merging.
- Add cpuset.cpus to cgroups and native driver options.
- Remove docker-ci.
- Promote btrfs. btrfs is no longer considered experimental.
- Add --input flag to `docker load`.
- Return error when existing bridge doesn't match IP address.
- Strip comments before parsing line continuations to avoid interpreting instructions as comments.
- Fix TestOnlyLoopbackExistsWhenUsingDisableNetworkOption to ignore "DOWN" interfaces.
- Add systemd implementation of cgroups and make containers show up as systemd units.
- Fix commit and import when no repository is specified.
- Remount /var/lib/docker as --private to fix scaling issue.
- Use the environment's proxy when pinging the remote registry.
- Reduce error level from harmless errors.
* Allow --volumes-from to be individual files.
- Fix expanding buffer in StdCopy.
- Set error regardless of attach or stdin. This fixes #3364.
- Add support for --env-file to load environment variables from files.
- Symlink /etc/mtab and /proc/mounts.
- Allow pushing a single tag.
- Shut down containers cleanly at shutdown and wait forever for the containers to shut down. This makes container shutdown on daemon shutdown work properly via SIGTERM.
- Don't throw error when starting an already running container.
- Fix dynamic port allocation limit.
- remove setupDev from libcontainer.
- Add API version to `docker version`.
- Return correct exit code when receiving signal and make SIGQUIT quit without cleanup.
- Fix --volumes-from mount failure.
- Allow non-privileged containers to create device nodes.
- Skip login tests because of external dependency on a hosted service.
- Deprecate `docker images --tree` and `docker images --viz`.
- Deprecate `docker insert`.
- Include base abstraction for apparmor. This fixes some apparmor related problems on Ubuntu 14.04.
- Add specific error message when hitting 401 over HTTP on push.
- Fix absolute volume check.
- Remove volumes-from from the config.
- Move DNS options to hostconfig.
- Update the apparmor profile for libcontainer.
- Add deprecation notice for `docker commit -run`.

## 0.9.1 (2014-03-24)

### Builder
- Fix printing multiple messages on a single line. Fixes broken output during builds.

### Documentation
- Fix external link on security of containers.

### Contrib
- Fix init script cgroup mounting workarounds to be more similar to cgroupfs-mount and thus work properly.
- Add variable for DOCKER_LOGFILE to sysvinit and use append instead of overwrite in opening the logfile.

### Hack
- Generate md5 and sha256 hashes when building, and upload them via hack/release.sh.

### Remote API
- Fix content-type detection in `docker cp`.

### Runtime
- Use BSD raw mode on Darwin. Fixes nano, tmux and others.
- Only unshare the mount namespace for execin.
- Retry to retrieve the layer metadata up to 5 times for `docker pull`.
- Merge existing config when committing.
- Fix panic in monitor.
- Disable daemon startup timeout.
- Fix issue #4681: add loopback interface when networking is disabled.
- Add failing test case for issue #4681.
- Send SIGTERM to child, instead of SIGKILL.
- Show the driver and the kernel version in `docker info` even when not in debug mode.
- Always symlink /dev/ptmx for libcontainer. This fixes console related problems.
- Fix issue caused by the absence of /etc/apparmor.d.
- Don't leave empty cidFile behind when failing to create the container.
- Improve deprecation message.
- Fix attach exit on darwin.
- devicemapper: improve handling of devicemapper devices (add per device lock, increase sleep time, unlock while sleeping).
- devicemapper: succeed immediately when removing non-existent devices.
- devicemapper: increase timeout in waitClose to 10 seconds.
- Remove goroutine leak on error.
- Update parseLxcInfo to comply with new lxc1.0 format.

## 0.9.0 (2014-03-10)

### Builder
- Avoid extra mount/unmount during build. This fixes mount/unmount related errors during build.
- Add error to docker build --rm. This adds missing error handling.
- Forbid chained onbuild, `onbuild from` and  `onbuild maintainer` triggers.
- Make `--rm` the default for `docker build`.

### Documentation
- Download the docker client binary for Mac over https.
- Update the titles of the install instructions & descriptions.
* Add instructions for upgrading boot2docker.
* Add port forwarding example in OS X install docs.
- Attempt to disentangle repository and registry.
- Update docs to explain more about `docker ps`.
- Update sshd example to use a Dockerfile.
- Rework some examples, including the Python examples.
- Update docs to include instructions for a container's lifecycle.
- Update docs documentation to discuss the docs branch.
- Don't skip cert check for an example & use HTTPS.
- Bring back the memory and swap accounting section which was lost when the kernel page was removed.
- Explain DNS warnings and how to fix them on systems running and using a local nameserver.

### Contrib
- Add Tanglu support for mkimage-debootstrap.
- Add SteamOS support for mkimage-debootstrap.

### Hack
- Get package coverage when running integration tests.
- Remove the Vagrantfile. This is being replaced with boot2docker.
- Fix tests on systems where aufs isn't available.
- Update packaging instructions and remove the dependency on lxc.

### Remote API
* Move code specific to the API to the api package.
- Fix header content type for the API. Makes all endpoints use proper content type.
- Fix registry auth & remove ping calls from CmdPush and CmdPull.
- Add newlines to the JSON stream functions.

### Runtime
* Do not ping the registry from the CLI. All requests to registries flow through the daemon.
- Check for nil information return in the lxc driver. This fixes panics with older lxc versions.
- Devicemapper: cleanups and fix for unmount. Fixes two problems which were causing unmount to fail intermittently.
- Devicemapper: remove directory when removing device. Directories don't get left behind when removing the device.
* Devicemapper: enable skip_block_zeroing. Improves performance by not zeroing blocks.
- Devicemapper: fix shutdown warnings. Fixes shutdown warnings concerning pool device removal.
- Ensure docker cp stream is closed properly. Fixes problems with files not being copied by `docker cp`.
- Stop making `tcp://` default to `127.0.0.1:4243` and remove the default port for tcp.
- Fix `--run` in `docker commit`. This makes `docker commit --run` work again.
- Fix custom bridge related options. This makes custom bridges work again.
+ Mount-bind the PTY as container console. This allows tmux/screen to run.
+ Add the pure Go libcontainer library to make it possible to run containers using only features of the Linux kernel.
+ Add native exec driver which uses libcontainer and make it the default exec driver.
- Add support for handling extended attributes in archives.
* Set the container MTU to be the same as the host MTU.
+ Add simple sha256 checksums for layers to speed up `docker push`.
* Improve kernel version parsing.
* Allow flag grouping (`docker run -it`).
- Remove chroot exec driver.
- Fix divide by zero to fix panic.
- Rewrite `docker rmi`.
- Fix docker info with lxc 1.0.0.
- Fix fedora tty with apparmor.
* Don't always append env vars, replace defaults with vars from config.
* Fix a goroutine leak.
* Switch to Go 1.2.1.
- Fix unique constraint error checks.
* Handle symlinks for Docker's data directory and for TMPDIR.
- Add deprecation warnings for flags (-flag is deprecated in favor of --flag)
- Add apparmor profile for the native execution driver.
* Move system specific code from archive to pkg/system.
- Fix duplicate signal for `docker run -i -t` (issue #3336).
- Return correct process pid for lxc.
- Add a -G option to specify the group which unix sockets belong to.
+ Add `-f` flag to `docker rm` to force removal of running containers.
+ Kill ghost containers and restart all ghost containers when the docker daemon restarts.
+ Add `DOCKER_RAMDISK` environment variable to make Docker work when the root is on a ramdisk.

## 0.8.1 (2014-02-18)

### Builder

- Avoid extra mount/unmount during build. This removes an unneeded mount/unmount operation which was causing problems with devicemapper
- Fix regression with ADD of tar files. This stops Docker from decompressing tarballs added via ADD from the local file system
- Add error to `docker build --rm`. This adds a missing error check to ensure failures to remove containers are detected and reported

### Documentation

* Update issue filing instructions
* Warn against the use of symlinks for Docker's storage folder
* Replace the Firefox example with an IceWeasel example
* Rewrite the PostgreSQL example using a Dockerfile and add more details to it
* Improve the OS X documentation

### Remote API

- Fix broken images API for version less than 1.7
- Use the right encoding for all API endpoints which return JSON
- Move remote api client to api/
- Queue calls to the API using generic socket wait

### Runtime

- Fix the use of custom settings for bridges and custom bridges
- Refactor the devicemapper code to avoid many mount/unmount race conditions and failures
- Remove two panics which could make Docker crash in some situations
- Don't ping registry from the CLI client
- Enable skip_block_zeroing for devicemapper. This stops devicemapper from always zeroing entire blocks
- Fix --run in `docker commit`. This makes docker commit store `--run` in the image configuration
- Remove directory when removing devicemapper device. This cleans up leftover mount directories
- Drop NET_ADMIN capability for non-privileged containers. Unprivileged containers can't change their network configuration
- Ensure `docker cp` stream is closed properly
- Avoid extra mount/unmount during container registration. This removes an unneeded mount/unmount operation which was causing problems with devicemapper
- Stop allowing tcp:// as a default tcp bin address which binds to 127.0.0.1:4243 and remove the default port
+ Mount-bind the PTY as container console. This allows tmux and screen to run in a container
- Clean up archive closing. This fixes and improves archive handling
- Fix engine tests on systems where temp directories are symlinked
- Add test methods for save and load
- Avoid temporarily unmounting the container when restarting it. This fixes a race for devicemapper during restart
- Support submodules when building from a GitHub repository
- Quote volume path to allow spaces
- Fix remote tar ADD behavior. This fixes a regression which was causing Docker to extract tarballs

## 0.8.0 (2014-02-04)

### Notable features since 0.7.0

* Images and containers can be removed much faster
* Building an image from source with docker build is now much faster
* The Docker daemon starts and stops much faster
* The memory footprint of many common operations has been reduced, by streaming files instead of buffering them in memory, fixing memory leaks, and fixing various suboptimal memory allocations
* Several race conditions were fixed, making Docker more stable under very high concurrency load. This makes Docker more stable and less likely to crash and reduces the memory footprint of many common operations
* All packaging operations are now built on the Go language’s standard tar implementation, which is bundled with Docker itself. This makes packaging more portable across host distributions, and solves several issues caused by quirks and incompatibilities between different distributions of tar
* Docker can now create, remove and modify larger numbers of containers and images graciously thanks to more aggressive releasing of system resources. For example the storage driver API now allows Docker to do reference counting on mounts created by the drivers
With the ongoing changes to the networking and execution subsystems of docker testing these areas have been a focus of the refactoring.  By moving these subsystems into separate packages we can test, analyze, and monitor coverage and quality of these packages
* Many components have been separated into smaller sub-packages, each with a dedicated test suite. As a result the code is better-tested, more readable and easier to change

* The ADD instruction now supports caching, which avoids unnecessarily re-uploading the same source content again and again when it hasn’t changed
* The new ONBUILD instruction adds to your image a “trigger” instruction to be executed at a later time, when the image is used as the base for another build
* Docker now ships with an experimental storage driver which uses the BTRFS filesystem for copy-on-write
* Docker is officially supported on Mac OS X
* The Docker daemon supports systemd socket activation

## 0.7.6 (2014-01-14)

### Builder

* Do not follow symlink outside of build context

### Runtime

- Remount bind mounts when ro is specified
* Use https for fetching docker version

### Other

* Inline the test.docker.io fingerprint
* Add ca-certificates to packaging documentation

## 0.7.5 (2014-01-09)

### Builder

* Disable compression for build. More space usage but a much faster upload
- Fix ADD caching for certain paths
- Do not compress archive from git build

### Documentation

- Fix error in GROUP add example
* Make sure the GPG fingerprint is inline in the documentation
* Give more specific advice on setting up signing of commits for DCO

### Runtime

- Fix misspelled container names
- Do not add hostname when networking is disabled
* Return most recent image from the cache by date
- Return all errors from docker wait
* Add Content-Type Header "application/json" to GET /version and /info responses

### Other

* Update DCO to version 1.1
+ Update Makefile to use "docker:GIT_BRANCH" as the generated image name
* Update Travis to check for new 1.1 DCO version

## 0.7.4 (2014-01-07)

### Builder

- Fix ADD caching issue with . prefixed path
- Fix docker build on devicemapper by reverting sparse file tar option
- Fix issue with file caching and prevent wrong cache hit
* Use same error handling while unmarshalling CMD and ENTRYPOINT

### Documentation

* Simplify and streamline Amazon Quickstart
* Install instructions use unprefixed Fedora image
* Update instructions for mtu flag for Docker on GCE
+ Add Ubuntu Saucy to installation
- Fix for wrong version warning on master instead of latest

### Runtime

- Only get the image's rootfs when we need to calculate the image size
- Correctly handle unmapping UDP ports
* Make CopyFileWithTar use a pipe instead of a buffer to save memory on docker build
- Fix login message to say pull instead of push
- Fix "docker load" help by removing "SOURCE" prompt and mentioning STDIN
* Make blank -H option default to the same as no -H was sent
* Extract cgroups utilities to own submodule

### Other

+ Add Travis CI configuration to validate DCO and gofmt requirements
+ Add Developer Certificate of Origin Text
* Upgrade VBox Guest Additions
* Check standalone header when pinging a registry server

## 0.7.3 (2014-01-02)

### Builder

+ Update ADD to use the image cache, based on a hash of the added content
* Add error message for empty Dockerfile

### Documentation

- Fix outdated link to the "Introduction" on www.docker.io
+ Update the docs to get wider when the screen does
- Add information about needing to install LXC when using raw binaries
* Update Fedora documentation to disentangle the docker and docker.io conflict
* Add a note about using the new `-mtu` flag in several GCE zones
+ Add FrugalWare installation instructions
+ Add a more complete example of `docker run`
- Fix API documentation for creating and starting Privileged containers
- Add missing "name" parameter documentation on "/containers/create"
* Add a mention of `lxc-checkconfig` as a way to check for some of the necessary kernel configuration
- Update the 1.8 API documentation with some additions that were added to the docs for 1.7

### Hack

- Add missing libdevmapper dependency to the packagers documentation
* Update minimum Go requirement to a hard line at Go 1.2+
* Many minor improvements to the Vagrantfile
+ Add ability to customize dockerinit search locations when compiling (to be used very sparingly only by packagers of platforms who require a nonstandard location)
+ Add coverprofile generation reporting
- Add `-a` to our Go build flags, removing the need for recompiling the stdlib manually
* Update Dockerfile to be more canonical and have less spurious warnings during build
- Fix some miscellaneous `docker pull` progress bar display issues
* Migrate more miscellaneous packages under the "pkg" folder
* Update TextMate highlighting to automatically be enabled for files named "Dockerfile"
* Reorganize syntax highlighting files under a common "contrib/syntax" directory
* Update install.sh script (https://get.docker.io/) to not fail if busybox fails to download or run at the end of the Ubuntu/Debian installation
* Add support for container names in bash completion

### Packaging

+ Add an official Docker client binary for Darwin (Mac OS X)
* Remove empty "Vendor" string and added "License" on deb package
+ Add a stubbed version of "/etc/default/docker" in the deb package

### Runtime

* Update layer application to extract tars in place, avoiding file churn while handling whiteouts
- Fix permissiveness of mtime comparisons in tar handling (since GNU tar and Go tar do not yet support sub-second mtime precision)
* Reimplement `docker top` in pure Go to work more consistently, and even inside Docker-in-Docker (thus removing the shell injection vulnerability present in some versions of `lxc-ps`)
+ Update `-H unix://` to work similarly to `-H tcp://` by inserting the default values for missing portions
- Fix more edge cases regarding dockerinit and deleted or replaced docker or dockerinit files
* Update container name validation to include '.'
- Fix use of a symlink or non-absolute path as the argument to `-g` to work as expected
* Update to handle external mounts outside of LXC, fixing many small mounting quirks and making future execution backends and other features simpler
* Update to use proper box-drawing characters everywhere in `docker images -tree`
* Move MTU setting from LXC configuration to directly use netlink
* Add `-S` option to external tar invocation for more efficient spare file handling
+ Add arch/os info to User-Agent string, especially for registry requests
+ Add `-mtu` option to Docker daemon for configuring MTU
- Fix `docker build` to exit with a non-zero exit code on error
+ Add `DOCKER_HOST` environment variable to configure the client `-H` flag without specifying it manually for every invocation

## 0.7.2 (2013-12-16)

### Runtime

+ Validate container names on creation with standard regex
* Increase maximum image depth to 127 from 42
* Continue to move api endpoints to the job api
+ Add -bip flag to allow specification of dynamic bridge IP via CIDR
- Allow bridge creation when ipv6 is not enabled on certain systems
* Set hostname and IP address from within dockerinit
* Drop capabilities from within dockerinit
- Fix volumes on host when symlink is present the image
- Prevent deletion of image if ANY container is depending on it even if the container is not running
* Update docker push to use new progress display
* Use os.Lstat to allow mounting unix sockets when inspecting volumes
- Adjust handling of inactive user login
- Add missing defines in devicemapper for older kernels
- Allow untag operations with no container validation
- Add auth config to docker build

### Documentation

* Add more information about Docker logging
+ Add RHEL documentation
* Add a direct example for changing the CMD that is run in a container
* Update Arch installation documentation
+ Add section on Trusted Builds
+ Add Network documentation page

### Other

+ Add new cover bundle for providing code coverage reporting
* Separate integration tests in bundles
* Make Tianon the hack maintainer
* Update mkimage-debootstrap with more tweaks for keeping images small
* Use https to get the install script
* Remove vendored dotcloud/tar now that Go 1.2 has been released

## 0.7.1 (2013-12-05)

### Documentation

+ Add @SvenDowideit as documentation maintainer
+ Add links example
+ Add documentation regarding ambassador pattern
+ Add Google Cloud Platform docs
+ Add dockerfile best practices
* Update doc for RHEL
* Update doc for registry
* Update Postgres examples
* Update doc for Ubuntu install
* Improve remote api doc

### Runtime

+ Add hostconfig to docker inspect
+ Implement `docker log -f` to stream logs
+ Add env variable to disable kernel version warning
+ Add -format to `docker inspect`
+ Support bind-mount for files
- Fix bridge creation on RHEL
- Fix image size calculation
- Make sure iptables are called even if the bridge already exists
- Fix issue with stderr only attach
- Remove init layer when destroying a container
- Fix same port binding on different interfaces
- `docker build` now returns the correct exit code
- Fix `docker port` to display correct port
- `docker build` now check that the dockerfile exists client side
- `docker attach` now returns the correct exit code
- Remove the name entry when the container does not exist

### Registry

* Improve progress bars, add ETA for downloads
* Simultaneous pulls now waits for the first to finish instead of failing
- Tag only the top-layer image when pushing to registry
- Fix issue with offline image transfer
- Fix issue preventing using ':' in password for registry

### Other

+ Add pprof handler for debug
+ Create a Makefile
* Use stdlib tar that now includes fix
* Improve make.sh test script
* Handle SIGQUIT on the daemon
* Disable verbose during tests
* Upgrade to go1.2 for official build
* Improve unit tests
* The test suite now runs all tests even if one fails
* Refactor C in Go (Devmapper)
- Fix OS X compilation

## 0.7.0 (2013-11-25)

### Notable features since 0.6.0

* Storage drivers: choose from aufs, device-mapper, or vfs.
* Standard Linux support: docker now runs on unmodified Linux kernels and all major distributions.
* Links: compose complex software stacks by connecting containers to each other.
* Container naming: organize your containers by giving them memorable names.
* Advanced port redirects: specify port redirects per interface, or keep sensitive ports private.
* Offline transfer: push and pull images to the filesystem without losing information.
* Quality: numerous bugfixes and small usability improvements. Significant increase in test coverage.

## 0.6.7 (2013-11-21)

### Runtime

* Improve stability, fixes some race conditions
* Skip the volumes mounted when deleting the volumes of container.
* Fix layer size computation: handle hard links correctly
* Use the work Path for docker cp CONTAINER:PATH
* Fix tmp dir never cleanup
* Speedup docker ps
* More informative error message on name collisions
* Fix nameserver regex
* Always return long id's
* Fix container restart race condition
* Keep published ports on docker stop;docker start
* Fix container networking on Fedora
* Correctly express "any address" to iptables
* Fix network setup when reconnecting to ghost container
* Prevent deletion if image is used by a running container
* Lock around read operations in graph

### RemoteAPI

* Return full ID on docker rmi

### Client

+ Add -tree option to images
+ Offline image transfer
* Exit with status 2 on usage error and display usage on stderr
* Do not forward SIGCHLD to container
* Use string timestamp for docker events -since

### Other

* Update to go 1.2rc5
+ Add /etc/default/docker support to upstart

## 0.6.6 (2013-11-06)

### Runtime

* Ensure container name on register
* Fix regression in /etc/hosts
+ Add lock around write operations in graph
* Check if port is valid
* Fix restart runtime error with ghost container networking
+ Add some more colors and animals to increase the pool of generated names
* Fix issues in docker inspect
+ Escape apparmor confinement
+ Set environment variables using a file.
* Prevent docker insert to erase something
+ Prevent DNS server conflicts in CreateBridgeIface
+ Validate bind mounts on the server side
+ Use parent image config in docker build
* Fix regression in /etc/hosts

### Client

+ Add -P flag to publish all exposed ports
+ Add -notrunc and -q flags to docker history
* Fix docker commit, tag and import usage
+ Add stars, trusted builds and library flags in docker search
* Fix docker logs with tty

### RemoteAPI

* Make /events API send headers immediately
* Do not split last column docker top
+ Add size to history

### Other

+ Contrib: Desktop integration. Firefox usecase.
+ Dockerfile: bump to go1.2rc3

## 0.6.5 (2013-10-29)

### Runtime

+ Containers can now be named
+ Containers can now be linked together for service discovery
+ 'run -a', 'start -a' and 'attach' can forward signals to the container for better integration with process supervisors
+ Automatically start crashed containers after a reboot
+ Expose IP, port, and proto as separate environment vars for container links
* Allow ports to be published to specific ips
* Prohibit inter-container communication by default
- Ignore ErrClosedPipe for stdin in Container.Attach
- Remove unused field kernelVersion
* Fix issue when mounting subdirectories of /mnt in container
- Fix untag during removal of images
* Check return value of syscall.Chdir when changing working directory inside dockerinit

### Client

- Only pass stdin to hijack when needed to avoid closed pipe errors
* Use less reflection in command-line method invocation
- Monitor the tty size after starting the container, not prior
- Remove useless os.Exit() calls after log.Fatal

### Hack

+ Add initial init scripts library and a safer Ubuntu packaging script that works for Debian
* Add -p option to invoke debootstrap with http_proxy
- Update install.sh with $sh_c to get sudo/su for modprobe
* Update all the mkimage scripts to use --numeric-owner as a tar argument
* Update hack/release.sh process to automatically invoke hack/make.sh and bail on build and test issues

### Other

* Documentation: Fix the flags for nc in example
* Testing: Remove warnings and prevent mount issues
- Testing: Change logic for tty resize to avoid warning in tests
- Builder: Fix race condition in docker build with verbose output
- Registry: Fix content-type for PushImageJSONIndex method
* Contrib: Improve helper tools to generate debian and Arch linux server images

## 0.6.4 (2013-10-16)

### Runtime

- Add cleanup of container when Start() fails
* Add better comments to utils/stdcopy.go
* Add utils.Errorf for error logging
+ Add -rm to docker run for removing a container on exit
- Remove error messages which are not actually errors
- Fix `docker rm` with volumes
- Fix some error cases where an HTTP body might not be closed
- Fix panic with wrong dockercfg file
- Fix the attach behavior with -i
* Record termination time in state.
- Use empty string so TempDir uses the OS's temp dir automatically
- Make sure to close the network allocators
+ Autorestart containers by default
* Bump vendor kr/pty to commit 3b1f6487b `(syscall.O_NOCTTY)`
* lxc: Allow set_file_cap capability in container
- Move run -rm to the cli only
* Split stdout stderr
* Always create a new session for the container

### Testing

- Add aggregated docker-ci email report
- Add cleanup to remove leftover containers
* Add nightly release to docker-ci
* Add more tests around auth.ResolveAuthConfig
- Remove a few errors in tests
- Catch errClosing error when TCP and UDP proxies are terminated
* Only run certain tests with TESTFLAGS='-run TestName' make.sh
* Prevent docker-ci to test closing PRs
* Replace panic by log.Fatal in tests
- Increase TestRunDetach timeout

### Documentation

* Add initial draft of the Docker infrastructure doc
* Add devenvironment link to CONTRIBUTING.md
* Add `apt-get install curl` to Ubuntu docs
* Add explanation for export restrictions
* Add .dockercfg doc
* Remove Gentoo install notes about #1422 workaround
* Fix help text for -v option
* Fix Ping endpoint documentation
- Fix parameter names in docs for ADD command
- Fix ironic typo in changelog
* Various command fixes in postgres example
* Document how to edit and release docs
- Minor updates to `postgresql_service.rst`
* Clarify LGTM process to contributors
- Corrected error in the package name
* Document what `vagrant up` is actually doing
+ improve doc search results
* Cleanup whitespace in API 1.5 docs
* use angle brackets in MAINTAINER example email
* Update archlinux.rst
+ Changes to a new style for the docs. Includes version switcher.
* Formatting, add information about multiline json
* Improve registry and index REST API documentation
- Replace deprecated upgrading reference to docker-latest.tgz, which hasn't been updated since 0.5.3
* Update Gentoo installation documentation now that we're in the portage tree proper
* Cleanup and reorganize docs and tooling for contributors and maintainers
- Minor spelling correction of protocoll -> protocol

### Contrib

* Add vim syntax highlighting for Dockerfiles from @honza
* Add mkimage-arch.sh
* Reorganize contributed completion scripts to add zsh completion

### Hack

* Add vagrant user to the docker group
* Add proper bash completion for "docker push"
* Add xz utils as a runtime dep
* Add cleanup/refactor portion of #2010 for hack and Dockerfile updates
+ Add contrib/mkimage-centos.sh back (from #1621), and associated documentation link
* Add several of the small make.sh fixes from #1920, and make the output more consistent and contributor-friendly
+ Add @tianon to hack/MAINTAINERS
* Improve network performance for VirtualBox
* Revamp install.sh to be usable by more people, and to use official install methods whenever possible (apt repo, portage tree, etc.)
- Fix contrib/mkimage-debian.sh apt caching prevention
+ Add Dockerfile.tmLanguage to contrib
* Configured FPM to make /etc/init/docker.conf a config file
* Enable SSH Agent forwarding in Vagrant VM
* Several small tweaks/fixes for contrib/mkimage-debian.sh

### Other

- Builder: Abort build if mergeConfig returns an error and fix duplicate error message
- Packaging: Remove deprecated packaging directory
- Registry: Use correct auth config when logging in.
- Registry: Fix the error message so it is the same as the regex

## 0.6.3 (2013-09-23)

### Packaging

* Add 'docker' group on install for ubuntu package
* Update tar vendor dependency
* Download apt key over HTTPS

### Runtime

- Only copy and change permissions on non-bindmount volumes
* Allow multiple volumes-from
- Fix HTTP imports from STDIN

### Documentation

* Update section on extracting the docker binary after build
* Update development environment docs for new build process
* Remove 'base' image from documentation

### Other

- Client: Fix detach issue
- Registry: Update regular expression to match index

## 0.6.2 (2013-09-17)

### Runtime

+ Add domainname support
+ Implement image filtering with path.Match
* Remove unnecessary warnings
* Remove os/user dependency
* Only mount the hostname file when the config exists
* Handle signals within the `docker login` command
- UID and GID are now also applied to volumes
- `docker start` set error code upon error
- `docker run` set the same error code as the process started

### Builder

+ Add -rm option in order to remove intermediate containers
* Allow multiline for the RUN instruction

### Registry

* Implement login with private registry
- Fix push issues

### Other

+ Hack: Vendor all dependencies
* Remote API: Bump to v1.5
* Packaging: Break down hack/make.sh into small scripts, one per 'bundle': test, binary, ubuntu etc.
* Documentation: General improvements

## 0.6.1 (2013-08-23)

### Registry

* Pass "meta" headers in API calls to the registry

### Packaging

- Use correct upstart script with new build tool
- Use libffi-dev, don't build it from sources
- Remove duplicate mercurial install command

## 0.6.0 (2013-08-22)

### Runtime

+ Add lxc-conf flag to allow custom lxc options
+ Add an option to set the working directory
* Add Image name to LogEvent tests
+ Add -privileged flag and relevant tests, docs, and examples
* Add websocket support to /container/<name>/attach/ws
* Add warning when net.ipv4.ip_forwarding = 0
* Add hostname to environment
* Add last stable version in `docker version`
- Fix race conditions in parallel pull
- Fix Graph ByParent() to generate list of child images per parent image.
- Fix typo: fmt.Sprint -> fmt.Sprintf
- Fix small \n error un docker build
* Fix to "Inject dockerinit at /.dockerinit"
* Fix #910. print user name to docker info output
* Use Go 1.1.2 for dockerbuilder
* Use ranged for loop on channels
- Use utils.ParseRepositoryTag instead of strings.Split(name, ":") in server.ImageDelete
- Improve CMD, ENTRYPOINT, and attach docs.
- Improve connect message with socket error
- Load authConfig only when needed and fix useless WARNING
- Show tag used when image is missing
* Apply volumes-from before creating volumes
- Make docker run handle SIGINT/SIGTERM
- Prevent crash when .dockercfg not readable
- Install script should be fetched over https, not http.
* API, issue 1471: Use groups for socket permissions
- Correctly detect IPv4 forwarding
* Mount /dev/shm as a tmpfs
- Switch from http to https for get.docker.io
* Let userland proxy handle container-bound traffic
* Update the Docker CLI to specify a value for the "Host" header.
- Change network range to avoid conflict with EC2 DNS
- Reduce connect and read timeout when pinging the registry
* Parallel pull
- Handle ip route showing mask-less IP addresses
* Allow ENTRYPOINT without CMD
- Always consider localhost as a domain name when parsing the FQN repos name
* Refactor checksum

### Documentation

* Add MongoDB image example
* Add instructions for creating and using the docker group
* Add sudo to examples and installation to documentation
* Add ufw doc
* Add a reference to ps -a
* Add information about Docker's high level tools over LXC.
* Fix typo in docs for docker run -dns
* Fix a typo in the ubuntu installation guide
* Fix to docs regarding adding docker groups
* Update default -H docs
* Update readme with dependencies for building
* Update amazon.rst to explain that Vagrant is not necessary for running Docker on ec2
* PostgreSQL service example in documentation
* Suggest installing linux-headers by default.
* Change the twitter handle
* Clarify Amazon EC2 installation
* 'Base' image is deprecated and should no longer be referenced in the docs.
* Move note about officially supported kernel
- Solved the logo being squished in Safari

### Builder

+ Add USER instruction do Dockerfile
+ Add workdir support for the Buildfile
* Add no cache for docker build
- Fix docker build and docker events output
- Only count known instructions as build steps
- Make sure ENV instruction within build perform a commit each time
- Forbid certain paths within docker build ADD
- Repository name (and optionally a tag) in build usage
- Make sure ADD will create everything in 0755

### Remote API

* Sort Images by most recent creation date.
* Reworking opaque requests in registry module
* Add image name in /events
* Use mime pkg to parse Content-Type
* 650 http utils and user agent field

### Hack

+ Bash Completion: Limit commands to containers of a relevant state
* Add docker dependencies coverage testing into docker-ci

### Packaging

+ Docker-brew 0.5.2 support and memory footprint reduction
* Add new docker dependencies into docker-ci
- Revert "docker.upstart: avoid spawning a `sh` process"
+ Docker-brew and Docker standard library
+ Release docker with docker
* Fix the upstart script generated by get.docker.io
* Enabled the docs to generate manpages.
* Revert Bind daemon to 0.0.0.0 in Vagrant.

### Register

* Improve auth push
* Registry unit tests + mock registry

### Tests

* Improve TestKillDifferentUser to prevent timeout on buildbot
- Fix typo in TestBindMounts (runContainer called without image)
* Improve TestGetContainersTop so it does not rely on sleep
* Relax the lo interface test to allow iface index != 1
* Add registry functional test to docker-ci
* Add some tests in server and utils

### Other

* Contrib: bash completion script
* Client: Add docker cp command and copy api endpoint to copy container files/folders to the host
* Don't read from stdout when only attached to stdin

## 0.5.3 (2013-08-13)

### Runtime

* Use docker group for socket permissions
- Spawn shell within upstart script
- Handle ip route showing mask-less IP addresses
- Add hostname to environment

### Builder

- Make sure ENV instruction within build perform a commit each time

## 0.5.2 (2013-08-08)

* Builder: Forbid certain paths within docker build ADD
- Runtime: Change network range to avoid conflict with EC2 DNS
* API: Change daemon to listen on unix socket by default

## 0.5.1 (2013-07-30)

### Runtime

+ Add `ps` args to `docker top`
+ Add support for container ID files (pidfile like)
+ Add container=lxc in default env
+ Support networkless containers with `docker run -n` and `docker -d -b=none`
* Stdout/stderr logs are now stored in the same file as JSON
* Allocate a /16 IP range by default, with fallback to /24. Try 12 ranges instead of 3.
* Change .dockercfg format to json and support multiple auth remote
- Do not override volumes from config
- Fix issue with EXPOSE override

### API

+ Docker client now sets useragent (RFC 2616)
+ Add /events endpoint

### Builder

+ ADD command now understands URLs
+ CmdAdd and CmdEnv now respect Dockerfile-set ENV variables
- Create directories with 755 instead of 700 within ADD instruction

### Hack

* Simplify unit tests with helpers
* Improve docker.upstart event
* Add coverage testing into docker-ci

## 0.5.0 (2013-07-17)

### Runtime

+ List all processes running inside a container with 'docker top'
+ Host directories can be mounted as volumes with 'docker run -v'
+ Containers can expose public UDP ports (eg, '-p 123/udp')
+ Optionally specify an exact public port (eg. '-p 80:4500')
* 'docker login' supports additional options
- Don't save a container's hostname when committing an image.

### Registry

+ New image naming scheme inspired by Go packaging convention allows arbitrary combinations of registries
- Fix issues when uploading images to a private registry

### Builder

+ ENTRYPOINT instruction sets a default binary entry point to a container
+ VOLUME instruction marks a part of the container as persistent data
* 'docker build' displays the full output of a build by default

## 0.4.8 (2013-07-01)

+ Builder: New build operation ENTRYPOINT adds an executable entry point to the container.  - Runtime: Fix a bug which caused 'docker run -d' to no longer print the container ID.
- Tests: Fix issues in the test suite

## 0.4.7 (2013-06-28)

### Remote API

* The progress bar updates faster when downloading and uploading large files
- Fix a bug in the optional unix socket transport

### Runtime

* Improve detection of kernel version
+ Host directories can be mounted as volumes with 'docker run -b'
- fix an issue when only attaching to stdin
* Use 'tar --numeric-owner' to avoid uid mismatch across multiple hosts

### Hack

* Improve test suite and dev environment
* Remove dependency on unit tests on 'os/user'

### Other

* Registry: easier push/pull to a custom registry
+ Documentation: add terminology section

## 0.4.6 (2013-06-22)

- Runtime: fix a bug which caused creation of empty images (and volumes) to crash.

## 0.4.5 (2013-06-21)

+ Builder: 'docker build git://URL' fetches and builds a remote git repository
* Runtime: 'docker ps -s' optionally prints container size
* Tests: improved and simplified
- Runtime: fix a regression introduced in 0.4.3 which caused the logs command to fail.
- Builder: fix a regression when using ADD with single regular file.

## 0.4.4 (2013-06-19)

- Builder: fix a regression introduced in 0.4.3 which caused builds to fail on new clients.

## 0.4.3 (2013-06-19)

### Builder

+ ADD of a local file will detect tar archives and unpack them
* ADD improvements: use tar for copy + automatically unpack local archives
* ADD uses tar/untar for copies instead of calling 'cp -ar'
* Fix the behavior of ADD to be (mostly) reverse-compatible, predictable and well-documented.
- Fix a bug which caused builds to fail if ADD was the first command
* Nicer output for 'docker build'

### Runtime

* Remove bsdtar dependency
* Add unix socket and multiple -H support
* Prevent rm of running containers
* Use go1.1 cookiejar
- Fix issue detaching from running TTY container
- Forbid parallel push/pull for a single image/repo. Fixes `#311`
- Fix race condition within Run command when attaching.

### Client

* HumanReadable ProgressBar sizes in pull
* Fix docker version's git commit output

### API

* Send all tags on History API call
* Add tag lookup to history command. Fixes #882

### Documentation

- Fix missing command in irc bouncer example

## 0.4.2 (2013-06-17)

- Packaging: Bumped version to work around an Ubuntu bug

## 0.4.1 (2013-06-17)

### Remote Api

+ Add flag to enable cross domain requests
+ Add images and containers sizes in docker ps and docker images

### Runtime

+ Configure dns configuration host-wide with 'docker -d -dns'
+ Detect faulty DNS configuration and replace it with a public default
+ Allow docker run <name>:<id>
+ You can now specify public port (ex: -p 80:4500)
* Improve image removal to garbage-collect unreferenced parents

### Client

* Allow multiple params in inspect
* Print the container id before the hijack in `docker run`

### Registry

* Add regexp check on repo's name
* Move auth to the client
- Remove login check on pull

### Other

* Vagrantfile: Add the rest api port to vagrantfile's port_forward
* Upgrade to Go 1.1
- Builder: don`t ignore last line in Dockerfile when it doesn`t end with \n

## 0.4.0 (2013-06-03)

### Builder

+ Introducing Builder
+ 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile

### Remote API

+ Introducing Remote API
+ control Docker programmatically using a simple HTTP/json API

### Runtime

* Various reliability and usability improvements

## 0.3.4 (2013-05-30)

### Builder

+ 'docker build' builds a container, layer by layer, from a source repository containing a Dockerfile
+ 'docker build -t FOO' applies the tag FOO to the newly built container.

### Runtime

+ Interactive TTYs correctly handle window resize
* Fix how configuration is merged between layers

### Remote API

+ Split stdout and stderr on 'docker run'
+ Optionally listen on a different IP and port (use at your own risk)

### Documentation

* Improve install instructions.

## 0.3.3 (2013-05-23)

- Registry: Fix push regression
- Various bugfixes

## 0.3.2 (2013-05-09)

### Registry

* Improve the checksum process
* Use the size to have a good progress bar while pushing
* Use the actual archive if it exists in order to speed up the push
- Fix error 400 on push

### Runtime

* Store the actual archive on commit

## 0.3.1 (2013-05-08)

### Builder

+ Implement the autorun capability within docker builder
+ Add caching to docker builder
+ Add support for docker builder with native API as top level command
+ Implement ENV within docker builder
- Check the command existence prior create and add Unit tests for the case
* use any whitespaces instead of tabs

### Runtime

+ Add go version to debug infos
* Kernel version - don't show the dash if flavor is empty

### Registry

+ Add docker search top level command in order to search a repository
- Fix pull for official images with specific tag
- Fix issue when login in with a different user and trying to push
* Improve checksum - async calculation

### Images

+ Output graph of images to dot (graphviz)
- Fix ByParent function

### Documentation

+ New introduction and high-level overview
+ Add the documentation for docker builder
- CSS fix for docker documentation to make REST API docs look better.
- Fix CouchDB example page header mistake
- Fix README formatting
* Update www.docker.io website.

### Other

+ Website: new high-level overview
- Makefile: Swap "go get" for "go get -d", especially to compile on go1.1rc
* Packaging: packaging ubuntu; issue #510: Use golang-stable PPA package to build docker

## 0.3.0 (2013-05-06)

### Runtime

- Fix the command existence check
- strings.Split may return an empty string on no match
- Fix an index out of range crash if cgroup memory is not

### Documentation

* Various improvements
+ New example: sharing data between 2 couchdb databases

### Other

* Vagrant: Use only one deb line in /etc/apt
+ Registry: Implement the new registry

## 0.2.2 (2013-05-03)

+ Support for data volumes ('docker run -v=PATH')
+ Share data volumes between containers ('docker run -volumes-from')
+ Improve documentation
* Upgrade to Go 1.0.3
* Various upgrades to the dev environment for contributors

## 0.2.1 (2013-05-01)

+ 'docker commit -run' bundles a layer with default runtime options: command, ports etc.
* Improve install process on Vagrant
+ New Dockerfile operation: "maintainer"
+ New Dockerfile operation: "expose"
+ New Dockerfile operation: "cmd"
+ Contrib script to build a Debian base layer
+ 'docker -d -r': restart crashed containers at daemon startup
* Runtime: improve test coverage

## 0.2.0 (2013-04-23)

- Runtime: ghost containers can be killed and waited for
* Documentation: update install instructions
- Packaging: fix Vagrantfile
- Development: automate releasing binaries and ubuntu packages
+ Add a changelog
- Various bugfixes

## 0.1.8 (2013-04-22)

- Dynamically detect cgroup capabilities
- Issue stability warning on kernels <3.8
- 'docker push' buffers on disk instead of memory
- Fix 'docker diff' for removed files
- Fix 'docker stop' for ghost containers
- Fix handling of pidfile
- Various bugfixes and stability improvements

## 0.1.7 (2013-04-18)

- Container ports are available on localhost
- 'docker ps' shows allocated TCP ports
- Contributors can run 'make hack' to start a continuous integration VM
- Streamline ubuntu packaging & uploading
- Various bugfixes and stability improvements

## 0.1.6 (2013-04-17)

- Record the author an image with 'docker commit -author'

## 0.1.5 (2013-04-17)

- Disable standalone mode
- Use a custom DNS resolver with 'docker -d -dns'
- Detect ghost containers
- Improve diagnosis of missing system capabilities
- Allow disabling memory limits at compile time
- Add debian packaging
- Documentation: installing on Arch Linux
- Documentation: running Redis on docker
- Fix lxc 0.9 compatibility
- Automatically load aufs module
- Various bugfixes and stability improvements

## 0.1.4 (2013-04-09)

- Full support for TTY emulation
- Detach from a TTY session with the escape sequence `C-p C-q`
- Various bugfixes and stability improvements
- Minor UI improvements
- Automatically create our own bridge interface 'docker0'

## 0.1.3 (2013-04-04)

- Choose TCP frontend port with '-p :PORT'
- Layer format is versioned
- Major reliability improvements to the process manager
- Various bugfixes and stability improvements

## 0.1.2 (2013-04-03)

- Set container hostname with 'docker run -h'
- Selective attach at run with 'docker run -a [stdin[,stdout[,stderr]]]'
- Various bugfixes and stability improvements
- UI polish
- Progress bar on push/pull
- Use XZ compression by default
- Make IP allocator lazy

## 0.1.1 (2013-03-31)

- Display shorthand IDs for convenience
- Stabilize process management
- Layers can include a commit message
- Simplified 'docker attach'
- Fix support for re-attaching
- Various bugfixes and stability improvements
- Auto-download at run
- Auto-login on push
- Beefed up documentation

## 0.1.0 (2013-03-23)

Initial public release

- Implement registry in order to push/pull images
- TCP port allocation
- Fix termcaps on Linux
- Add documentation
- Add Vagrant support with Vagrantfile
- Add unit tests
- Add repository/tags to ease image management
- Improve the layer implementation


---

# Docker Engine security

*Sección: Engine*

There are four major areas to consider when reviewing Docker security:

 - The intrinsic security of the kernel and its support for
   namespaces and cgroups
 - The attack surface of the Docker daemon itself
 - Loopholes in the container configuration profile, either by default,
   or when customized by users.
 - The "hardening" security features of the kernel and how they
   interact with containers.

## Kernel namespaces

Docker containers are very similar to LXC containers, and they have
similar security features. When you start a container with
`docker run`, behind the scenes Docker creates a set of namespaces and control
groups for the container.

Namespaces provide the first and most straightforward form of
isolation. Processes running within a container cannot see, and even
less affect, processes running in another container, or in the host
system.

Each container also gets its own network stack, meaning that a
container doesn't get privileged access to the sockets or interfaces
of another container. Of course, if the host system is setup
accordingly, containers can interact with each other through their
respective network interfaces — just like they can interact with
external hosts. When you specify public ports for your containers or use
[links](../network/links.md)
then IP traffic is allowed between containers. They can ping each other,
send/receive UDP packets, and establish TCP connections, but that can be
restricted if necessary. From a network architecture point of view, all
containers on a given Docker host are sitting on bridge interfaces. This
means that they are just like physical machines connected through a
common Ethernet switch; no more, no less.

How mature is the code providing kernel namespaces and private
networking? Kernel namespaces were introduced [between kernel version
2.6.15 and
2.6.26](https://man7.org/linux/man-pages/man7/namespaces.7.html).
This means that since July 2008 (date of the 2.6.26 release
), namespace code has been exercised and scrutinized on a large
number of production systems. And there is more: the design and
inspiration for the namespaces code are even older. Namespaces are
actually an effort to reimplement the features of [OpenVZ](
https://en.wikipedia.org/wiki/OpenVZ) in such a way that they could be
merged within the mainstream kernel. And OpenVZ was initially released
in 2005, so both the design and the implementation are pretty mature.

## Control groups

Control Groups are another key component of Linux containers. They
implement resource accounting and limiting. They provide many
useful metrics, but they also help ensure that each container gets
its fair share of memory, CPU, disk I/O; and, more importantly, that a
single container cannot bring the system down by exhausting one of those
resources.

So while they do not play a role in preventing one container from
accessing or affecting the data and processes of another container, they
are essential to fend off some denial-of-service attacks. They are
particularly important on multi-tenant platforms, like public and
private PaaS, to guarantee a consistent uptime (and performance) even
when some applications start to misbehave.

Control Groups have been around for a while as well: the code was
started in 2006, and initially merged in kernel 2.6.24.

## Docker daemon attack surface

Running containers (and applications) with Docker implies running the
Docker daemon. This daemon requires `root` privileges unless you opt-in
to [Rootless mode](rootless.md), and you should therefore be aware of
some important details.

First of all, only trusted users should be allowed to control your
Docker daemon. This is a direct consequence of some powerful Docker
features. Specifically, Docker allows you to share a directory between
the Docker host and a guest container; and it allows you to do so
without limiting the access rights of the container. This means that you
can start a container where the `/host` directory is the `/` directory
on your host; and the container can alter your host filesystem
without any restriction. This is similar to how virtualization systems
allow filesystem resource sharing. Nothing prevents you from sharing your
root filesystem (or even your root block device) with a virtual machine.

This has a strong security implication: for example, if you instrument Docker
from a web server to provision containers through an API, you should be
even more careful than usual with parameter checking, to make sure that
a malicious user cannot pass crafted parameters causing Docker to create
arbitrary containers.

For this reason, the REST API endpoint (used by the Docker CLI to
communicate with the Docker daemon) changed in Docker 0.5.2, and now
uses a Unix socket instead of a TCP socket bound on 127.0.0.1 (the
latter being prone to cross-site request forgery attacks if you happen to run
Docker directly on your local machine, outside of a VM). You can then
use traditional Unix permission checks to limit access to the control
socket.

You can also expose the REST API over HTTP if you explicitly decide to do so.
However, if you do that, be aware of the above mentioned security implications.
Note that even if you have a firewall to limit accesses to the REST API 
endpoint from other hosts in the network, the endpoint can be still accessible
from containers, and it can easily result in the privilege escalation.
Therefore it is *mandatory* to secure API endpoints with 
[HTTPS and certificates](protect-access.md).
Exposing the daemon API over HTTP without TLS is not permitted,
and such a configuration causes the daemon to fail early on startup, see
[Unauthenticated TCP connections](../deprecated.md#unauthenticated-tcp-connections).
It is also recommended to ensure that it is reachable only from a trusted
network or VPN.

You can also use `DOCKER_HOST=ssh://USER@HOST` or `ssh -L /path/to/docker.sock:/var/run/docker.sock`
instead if you prefer SSH over TLS.

The daemon is also potentially vulnerable to other inputs, such as image
loading from either disk with `docker load`, or from the network with
`docker pull`. As of Docker 1.3.2, images are now extracted in a chrooted
subprocess on Linux/Unix platforms, being the first-step in a wider effort
toward privilege separation. As of Docker 1.10.0, all images are stored and
accessed by the cryptographic checksums of their contents, limiting the
possibility of an attacker causing a collision with an existing image.

Finally, if you run Docker on a server, it is recommended to run
exclusively Docker on the server, and move all other services within
containers controlled by Docker. Of course, it is fine to keep your
favorite admin tools (probably at least an SSH server), as well as
existing monitoring/supervision processes, such as NRPE and collectd.

## Linux kernel capabilities

By default, Docker starts containers with a restricted set of
capabilities. What does that mean?

Capabilities turn the binary "root/non-root" dichotomy into a
fine-grained access control system. Processes (like web servers) that
just need to bind on a port below 1024 do not need to run as root: they
can just be granted the `net_bind_service` capability instead. And there
are many other capabilities, for almost all the specific areas where root
privileges are usually needed. This means a lot for container security.

Typical servers run several processes as `root`, including the SSH daemon,
`cron` daemon, logging daemons, kernel modules, network configuration tools,
and more. A container is different, because almost all of those tasks are
handled by the infrastructure around the container:

 - SSH access are typically managed by a single server running on
   the Docker host
 - `cron`, when necessary, should run as a user
   process, dedicated and tailored for the app that needs its
   scheduling service, rather than as a platform-wide facility
 - Log management is also typically handed to Docker, or to
   third-party services like Loggly or Splunk
 - Hardware management is irrelevant, meaning that you never need to
   run `udevd` or equivalent daemons within
   containers
 - Network management happens outside of the containers, enforcing
   separation of concerns as much as possible, meaning that a container
   should never need to perform `ifconfig`,
   `route`, or ip commands (except when a container
   is specifically engineered to behave like a router or firewall, of
   course)

This means that in most cases, containers do not need "real" root
privileges at all* And therefore, containers can run with a reduced
capability set; meaning that "root" within a container has much less
privileges than the real "root". For instance, it is possible to:

 - Deny all "mount" operations
 - Deny access to raw sockets (to prevent packet spoofing)
 - Deny access to some filesystem operations, like creating new device
   nodes, changing the owner of files, or altering attributes (including
   the immutable flag)
 - Deny module loading

This means that even if an intruder manages to escalate to root within a
container, it is much harder to do serious damage, or to escalate
to the host.

This doesn't affect regular web apps, but reduces the vectors of attack by
malicious users considerably. By default Docker
drops all capabilities except [those
needed](https://github.com/moby/moby/blob/master/daemon/pkg/oci/caps/defaults.go#L6-L19),
an allowlist instead of a denylist approach. You can see a full list of
available capabilities in [Linux
manpages](https://man7.org/linux/man-pages/man7/capabilities.7.html).

One primary risk with running Docker containers is that the default set
of capabilities and mounts given to a container may provide incomplete
isolation, either independently, or when used in combination with
kernel vulnerabilities.

Docker supports the addition and removal of capabilities, allowing use
of a non-default profile. This may make Docker more secure through
capability removal, or less secure through the addition of capabilities.
The best practice for users would be to remove all capabilities except
those explicitly required for their processes.

## Docker Content Trust signature verification

Docker Engine can be configured to only run signed images. The Docker Content 
Trust signature verification feature is built directly into the `dockerd` binary.  
This is configured in the Dockerd configuration file. 

To enable this feature, trustpinning can be configured in `daemon.json`, whereby 
only repositories signed with a user-specified root key can be pulled and run.
  
This feature provides more insight to administrators than previously available with
the CLI for enforcing and performing image signature verification. 

For more information on configuring Docker Content Trust Signature Verification, go to 
[Content trust in Docker](trust/index.md).

## Other kernel security features

Capabilities are just one of the many security features provided by
modern Linux kernels. It is also possible to leverage existing,
well-known systems like TOMOYO, AppArmor, SELinux, GRSEC, etc. with
Docker.

While Docker currently only enables capabilities, it doesn't interfere
with the other systems. This means that there are many different ways to
harden a Docker host. Here are a few examples.

 - You can run a kernel with GRSEC and PAX. This adds many safety
   checks, both at compile-time and run-time; it also defeats many
   exploits, thanks to techniques like address randomization. It doesn't
   require Docker-specific configuration, since those security features
   apply system-wide, independent of containers.
 - If your distribution comes with security model templates for
   Docker containers, you can use them out of the box. For instance, we
   ship a template that works with AppArmor and Red Hat comes with SELinux
   policies for Docker. These templates provide an extra safety net (even
   though it overlaps greatly with capabilities).
 - You can define your own policies using your favorite access control
   mechanism.

Just as you can use third-party tools to augment Docker containers, including
special network topologies or shared filesystems, tools exist to harden Docker
containers without the need to modify Docker itself.

As of Docker 1.10 User Namespaces are supported directly by the docker
daemon. This feature allows for the root user in a container to be mapped
to a non uid-0 user outside the container, which can help to mitigate the
risks of container breakout. This facility is available but not enabled
by default.

Refer to the [daemon command](/reference/cli/dockerd.md#daemon-user-namespace-options)
in the command line reference for more information on this feature.
Additional information on the implementation of User Namespaces in Docker
can be found in
[this blog post](https://integratedcode.us/2015/10/13/user-namespaces-have-arrived-in-docker/).

## Conclusions

Docker containers are, by default, quite secure; especially if you
run your processes as non-privileged users inside the container.

You can add an extra layer of safety by enabling AppArmor, SELinux,
GRSEC, or another appropriate hardening system.

If you think of ways to make docker more secure, we welcome feature requests,
pull requests, or comments on the Docker community forums.

## Related information

* [Use trusted images](trust/index.md)
* [Seccomp security profiles for Docker](seccomp.md)
* [AppArmor security profiles for Docker](apparmor.md)
* [On the Security of Containers (2014)](https://medium.com/@ewindisch/on-the-security-of-containers-2c60ffe25a9e)
* [Docker swarm mode overlay network security model](../network/drivers/overlay.md)


---

# Antivirus software and Docker

*Sección: Engine*

When antivirus software scans files used by Docker, these files may be locked
in a way that causes Docker commands to hang.

One way to reduce these problems is to add the Docker data directory
(`/var/lib/docker` on Linux, `%ProgramData%\docker` on Windows Server, or `$HOME/Library/Containers/com.docker.docker/` on Mac) to the
antivirus's exclusion list. However, this comes with the trade-off that viruses
or malware in Docker images, writable layers of containers, or volumes are not
detected. If you do choose to exclude Docker's data directory from background
virus scanning, you may want to schedule a recurring task that stops Docker,
scans the data directory, and restarts Docker.


---

# AppArmor security profiles for Docker

*Sección: Engine*

AppArmor (Application Armor) is a Linux security module that protects an
operating system and its applications from security threats. To use it, a system
administrator associates an AppArmor security profile with each program. Docker
expects to find an AppArmor policy loaded and enforced.

Docker automatically generates and loads a default profile for containers named
`docker-default`. The Docker binary generates this profile in `tmpfs` and then
loads it into the kernel.

> [!NOTE]
>
> This profile is used on containers, not on the Docker daemon.

A profile for the Docker Engine daemon exists but it is not currently installed
with the `deb` packages. If you are interested in the source for the daemon
profile, it is located in
[contrib/apparmor](https://github.com/moby/moby/tree/master/contrib/apparmor)
in the Docker Engine source repository.

## Understand the policies

The `docker-default` profile is the default for running containers. It is
moderately protective while providing wide application compatibility. The
profile is generated from the following
[template](https://github.com/moby/profiles/blob/main/apparmor/template.go).

When you run a container, it uses the `docker-default` policy unless you
override it with the `security-opt` option. For example, the following
explicitly specifies the default policy:

```console
$ docker run --rm -it --security-opt apparmor=docker-default hello-world
```

## Customize the default profile

Starting with Docker Engine 29.8, you can configure the daemon to generate the
`docker-default` profile from a custom template.
This changes the policy for containers that use `docker-default`.
Privileged containers without an explicit AppArmor profile use `unconfined`,
and containers configured with another profile continue to use that setting.

The template uses Go [text/template](https://pkg.go.dev/text/template) syntax.
Docker renders and loads it when the daemon starts.
Use the built-in
[`baseTemplate`](https://github.com/moby/profiles/blob/main/apparmor/template.go)
as a starting point because it includes the rules and template substitutions
required for compatibility across supported hosts.

> [!CAUTION]
>
> A custom template can reduce container isolation. Review and test every
> change to the built-in policy.

### Create a template

Copy the contents between the `baseTemplate` backticks and save them as
`/etc/docker/apparmor/docker-default`.
The template isn't a complete AppArmor profile until Docker renders it.
Store the file outside the AppArmor profile directory (`/etc/apparmor.d`)
because the host AppArmor service can try to parse the template before Docker
renders it.

Modify the policy rules as needed. Docker provides the following template data:

- `.Abi`: `abi/3.0` when the host provides that AppArmor ABI, or an empty string
- `.Name`: the profile name, `docker-default`
- `.DaemonProfile`: the daemon's AppArmor profile, or `unconfined`
- `.Imports`: host-specific declarations and includes for the global scope
- `.InnerImports`: host-specific includes for the profile scope

Keep the `.Abi`, `.Name`, `.Imports`, and `.InnerImports` substitutions from the
built-in template.
Use `.DaemonProfile` in rules that permit signals from the daemon.

### Configure the daemon

Set `apparmor-profile` to the template path in the daemon configuration:

```json {title="/etc/docker/daemon.json"}
{
  "apparmor-profile": "/etc/apparmor.d/containers/my-custom-docker-profile.tpl"
}
```

You can instead pass the path with the
`dockerd --apparmor-profile=/etc/apparmor.d/containers/my-custom-docker-profile.tpl` flag.
Don't configure the option both as a flag and in `daemon.json`.

### Restart and verify

Restart the Docker daemon:

```console
$ sudo systemctl restart docker
```

Check the daemon logs for errors while loading the rendered profile:

```console
$ sudo journalctl -u docker.service --since "5 minutes ago" --no-pager
```

Confirm that the logs for the restart don't contain
`Failed to load default apparmor profile`.
If `apparmor_parser` rejects the rendered profile, the daemon continues running
and keeps the previously loaded `docker-default` profile.

Confirm that the daemon is configured to use the template path:

```console
$ docker info --format '{{json .SecurityOptions}}'
```

The output includes
`name=apparmor,profile=/etc/apparmor.d/containers/my-custom-docker-profile.tpl`.

## Load and unload profiles

To load a new profile into AppArmor for use with containers:

```console
$ apparmor_parser -r -W /path/to/your_profile
```

Then, run the custom profile with `--security-opt`:

```console
$ docker run --rm -it --security-opt apparmor=your_profile hello-world
```

To unload a profile from AppArmor:

```console
# unload the profile
$ apparmor_parser -R /path/to/profile
```

### Resources for writing profiles

The syntax for file globbing in AppArmor is a bit different than some other
globbing implementations. It is highly suggested you take a look at some of the
below resources with regard to AppArmor profile syntax.

- [Quick Profile Language](https://gitlab.com/apparmor/apparmor/wikis/QuickProfileLanguage)
- [Globbing Syntax](https://gitlab.com/apparmor/apparmor/wikis/AppArmor_Core_Policy_Reference#AppArmor_globbing_syntax)

## Nginx example profile

In this example, you create a custom AppArmor profile for Nginx. Below is the
custom profile.

```c
#include <tunables/global>


profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
  network inet udp,
  network inet icmp,

  deny network raw,

  deny network packet,

  file,
  umount,

  deny /bin/** wl,
  deny /boot/** wl,
  deny /dev/** wl,
  deny /etc/** wl,
  deny /home/** wl,
  deny /lib/** wl,
  deny /lib64/** wl,
  deny /media/** wl,
  deny /mnt/** wl,
  deny /opt/** wl,
  deny /proc/** wl,
  deny /root/** wl,
  deny /sbin/** wl,
  deny /srv/** wl,
  deny /tmp/** wl,
  deny /sys/** wl,
  deny /usr/** wl,

  audit /** w,

  /var/run/nginx.pid w,

  /usr/sbin/nginx ix,

  deny /bin/dash mrwklx,
  deny /bin/sh mrwklx,
  deny /usr/bin/top mrwklx,


  capability chown,
  capability dac_override,
  capability setuid,
  capability setgid,
  capability net_bind_service,

  deny @{PROC}/* w,   # deny write for all files directly in /proc (not in a subdir)
  # deny write to files not in /proc/<number>/** or /proc/sys/**
  deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
  deny @{PROC}/sys/[^k]** w,  # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
  deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w,  # deny everything except shm* in /proc/sys/kernel/
  deny @{PROC}/sysrq-trigger rwklx,
  deny @{PROC}/mem rwklx,
  deny @{PROC}/kmem rwklx,
  deny @{PROC}/kcore rwklx,

  deny mount,

  deny /sys/[^f]*/** wklx,
  deny /sys/f[^s]*/** wklx,
  deny /sys/fs/[^c]*/** wklx,
  deny /sys/fs/c[^g]*/** wklx,
  deny /sys/fs/cg[^r]*/** wklx,
  deny /sys/firmware/** rwklx,
  deny /sys/kernel/security/** rwklx,
}
```

1. Save the custom profile to disk in the
   `/etc/apparmor.d/containers/docker-nginx` file.

   The file path in this example is not a requirement. In production, you could
   use another.

2. Load the profile.

   ```console
   $ sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-nginx
   ```

3. Run a container with the profile.

   To run nginx in detached mode:

   ```console
   $ docker run --security-opt "apparmor=docker-nginx" \
        -p 80:80 -d --name apparmor-nginx nginx
   ```

4. Exec into the running container.

   ```console
   $ docker container exec -it apparmor-nginx bash
   ```

5. Try some operations to test the profile.

   ```console
   root@6da5a2a930b9:~# ping 8.8.8.8
   ping: Lacking privilege for raw socket.

   root@6da5a2a930b9:/# top
   bash: /usr/bin/top: Permission denied

   root@6da5a2a930b9:~# touch ~/thing
   touch: cannot touch 'thing': Permission denied

   root@6da5a2a930b9:/# sh
   bash: /bin/sh: Permission denied

   root@6da5a2a930b9:/# dash
   bash: /bin/dash: Permission denied
   ```


You just deployed a container secured with a custom apparmor profile.


## Debug AppArmor

You can use `dmesg` to debug problems and `aa-status` check the loaded profiles.

### Use dmesg

Here are some helpful tips for debugging any problems you might be facing with
regard to AppArmor.

AppArmor sends quite verbose messaging to `dmesg`. Usually an AppArmor line
looks like the following:

```text
[ 5442.864673] audit: type=1400 audit(1453830992.845:37): apparmor="ALLOWED" operation="open" profile="/usr/bin/docker" name="/home/jessie/docker/man/man1/docker-attach.1" pid=10923 comm="docker" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
```

In the above example, you can see `profile=/usr/bin/docker`. This means the
user has the `docker-engine` (Docker Engine daemon) profile loaded.

Look at another log line:

```text
[ 3256.689120] type=1400 audit(1405454041.341:73): apparmor="DENIED" operation="ptrace" profile="docker-default" pid=17651 comm="docker" requested_mask="receive" denied_mask="receive"
```

This time the profile is `docker-default`, which is run on containers by
default unless in `privileged` mode. This line shows that apparmor has denied
`ptrace` in the container. This is exactly as expected.

### Use aa-status

If you need to check which profiles are loaded,  you can use `aa-status`. The
output looks like:

```console
$ sudo aa-status
apparmor module is loaded.
14 profiles are loaded.
1 profiles are in enforce mode.
   docker-default
13 profiles are in complain mode.
   /usr/bin/docker
   /usr/bin/docker///bin/cat
   /usr/bin/docker///bin/ps
   /usr/bin/docker///sbin/apparmor_parser
   /usr/bin/docker///sbin/auplink
   /usr/bin/docker///sbin/blkid
   /usr/bin/docker///sbin/iptables
   /usr/bin/docker///sbin/mke2fs
   /usr/bin/docker///sbin/modprobe
   /usr/bin/docker///sbin/tune2fs
   /usr/bin/docker///sbin/xtables-multi
   /usr/bin/docker///sbin/zfs
   /usr/bin/docker///usr/bin/xz
38 processes have profiles defined.
37 processes are in enforce mode.
   docker-default (6044)
   ...
   docker-default (31899)
1 processes are in complain mode.
   /usr/bin/docker (29756)
0 processes are unconfined but have a profile defined.
```

The above output shows that the `docker-default` profile running on various
container PIDs is in `enforce` mode. This means AppArmor is actively blocking
and auditing in `dmesg` anything outside the bounds of the `docker-default`
profile.

The output above also shows the `/usr/bin/docker` (Docker Engine daemon) profile
is running in `complain` mode. This means AppArmor only logs to `dmesg`
activity outside the bounds of the profile. (Except in the case of Ubuntu
Trusty, where some interesting behaviors are enforced.)

## Contribute to Docker's AppArmor code

Advanced users and package managers can find a profile for `/usr/bin/docker`
(Docker Engine daemon) underneath
[contrib/apparmor](https://github.com/moby/moby/tree/master/contrib/apparmor)
in the Docker Engine source repository.

The `docker-default` profile for containers lives in
[profiles/apparmor](https://github.com/moby/profiles/blob/main/apparmor).


---

# Verify repository client with certificates

*Sección: Engine*

In [Running Docker with HTTPS](protect-access.md), you learned that, by default,
Docker runs via a non-networked Unix socket and TLS must be enabled in order
to have the Docker client and the daemon communicate securely over HTTPS.  TLS ensures authenticity of the registry endpoint and that traffic to/from registry is encrypted.

This article demonstrates how to ensure the traffic between the Docker registry
server and the Docker daemon (a client of the registry server) is encrypted and
properly authenticated using certificate-based client-server authentication.

We show you how to install a Certificate Authority (CA) root certificate
for the registry and how to set the client TLS certificate for verification.

## Understand the configuration

A custom certificate is configured by creating a directory under the daemon's
certificate root using the same name as the registry's hostname, such as
`localhost`. All `*.crt` files are added to this directory as CA roots.

Where that certificate root lives depends on the platform:

- Native Linux Engine: `/etc/docker/certs.d/`
- Rootless Linux: `$XDG_CONFIG_HOME/docker/certs.d` (defaults to
  `~/.config/docker/certs.d`), not `/etc/docker/certs.d`
- Native Windows Engine (Windows containers):
  `%PROGRAMDATA%\docker\certs.d` (normally `C:\ProgramData\docker\certs.d`).
  If the registry address includes a port, strip the colon from the directory
  name because Windows filenames cannot contain `:`. For example,
  `registry.example.com:5000` becomes `registry.example.com5000`.
- Docker Desktop with Linux containers: put client certificates in
  `~/.docker/certs.d` on the host. Docker Desktop copies them into the VM;
  don't configure `/etc/docker/certs.d` inside the VM yourself. Trusted CAs
  can also come from the host certificate store (on Windows, the Windows
  certificate store).

> [!NOTE]
>
> On Linux any root certificates authorities are merged with the system defaults,
> including the host's root CA set. If you are running Docker on Windows Server,
> or Docker Desktop for Windows with Windows containers, the system default
> certificates are only used when no custom root certificates are configured.

The presence of one or more `<filename>.key/cert` pairs indicates to Docker
that there are custom certificates required for access to the desired
repository.

> [!NOTE]
>
> If multiple certificates exist, each is tried in alphabetical
> order. If there is a 4xx-level or 5xx-level authentication error, Docker
> continues to try with the next certificate.

The following illustrates a configuration with custom certificates:

```text
    /etc/docker/certs.d/        <-- Certificate directory
    └── localhost:5000          <-- Hostname:port
       ├── client.cert          <-- Client certificate
       ├── client.key           <-- Client key
       └── ca.crt               <-- Root CA that signed
                                    the registry certificate, in PEM
```

The preceding example is operating-system specific and is for illustrative
purposes only. You should consult your operating system documentation for
creating an os-provided bundled certificate chain.


## Create the client certificates

Use OpenSSL's `genrsa` and `req` commands to first generate an RSA
key and then use the key to create the certificate.   

```console
$ openssl genrsa -out client.key 4096
$ openssl req -new -x509 -text -key client.key -out client.cert
```

> [!NOTE]
>
> These TLS commands only generate a working set of certificates on Linux.
> The version of OpenSSL in macOS is incompatible with the type of
> certificate Docker requires.

## Troubleshooting tips

The Docker daemon interprets `.crt` files as CA certificates and `.cert` files
as client certificates. If a CA certificate is accidentally given the extension
`.cert` instead of the correct `.crt` extension, the Docker daemon logs the
following error message:

```text
Missing key KEY_NAME for client certificate CERT_NAME. CA certificates should use the extension .crt.
```

If the Docker registry is accessed without a port number, do not add the port to the directory name.  The following shows the configuration for a registry on default port 443 which is accessed with `docker login my-https.registry.example.com`:

```text
    /etc/docker/certs.d/
    └── my-https.registry.example.com          <-- Hostname without port
       ├── client.cert
       ├── client.key
       └── ca.crt
```

## Related information

* [Use trusted images](trust/index.md)
* [Protect the Docker daemon socket](protect-access.md)


---

# Readme

*Sección: Engine*

This is an initial attempt to make it easier to test the TLS (HTTPS) examples in the protect-access.md
doc.

At this point, it is a manual thing, and I've been running it in boot2docker.

My process is as following:

    $ boot2docker ssh
    root@boot2docker:/# git clone https://github.com/moby/moby
    root@boot2docker:/# cd docker/docs/articles/https
    root@boot2docker:/# make cert

lots of things to see and manually answer, as openssl wants to be interactive

> [!NOTE]: make sure you enter the hostname (`boot2docker` in my case) when prompted for `Computer Name`)

    root@boot2docker:/# sudo make run

Start another terminal:

    $ boot2docker ssh
    root@boot2docker:/# cd docker/docs/articles/https
    root@boot2docker:/# make client

The last connects first with `--tls` and then with `--tlsverify`, both should succeed.


---

# Docker security non-events

*Sección: Engine*

This page lists security vulnerabilities which Docker mitigated, such that
processes run in Docker containers were never vulnerable to the bug—even before
it was fixed. This assumes containers are run without adding extra capabilities
or not run as `--privileged`.

The list below is not even remotely complete. Rather, it is a sample of the few
bugs we've actually noticed to have attracted security review and publicly
disclosed vulnerabilities. In all likelihood, the bugs that haven't been
reported far outnumber those that have. Luckily, since Docker's approach to
secure by default through apparmor, seccomp, and dropping capabilities, it
likely mitigates unknown bugs just as well as it does known ones.

Bugs mitigated:

* [CVE-2013-1956](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1956),
[1957](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1957),
[1958](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1958),
[1959](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1959),
[1979](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-1979),
[CVE-2014-4014](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4014),
[5206](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-5206),
[5207](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-5207),
[7970](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-7970),
[7975](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-7975),
[CVE-2015-2925](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-2925),
[8543](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-8543),
[CVE-2016-3134](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3134),
[3135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3135), etc.:
The introduction of unprivileged user namespaces lead to a huge increase in the
attack surface available to unprivileged users by giving such users legitimate
access to previously root-only system calls like `mount()`. All of these CVEs
are examples of security vulnerabilities due to introduction of user namespaces.
Docker can use user namespaces to set up containers, but then disallows the
process inside the container from creating its own nested namespaces through the
default seccomp profile, rendering these vulnerabilities unexploitable.
* [CVE-2014-0181](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0181),
[CVE-2015-3339](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3339):
These are bugs that require the presence of a setuid binary. Docker disables
setuid binaries inside containers via the `NO_NEW_PRIVS` process flag and
other mechanisms.
* [CVE-2014-4699](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-4699):
A bug in `ptrace()` could allow privilege escalation. Docker disables `ptrace()`
inside the container using apparmor, seccomp and by dropping `CAP_PTRACE`.
Three times the layers of protection there!
* [CVE-2014-9529](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-9529):
A series of crafted `keyctl()` calls could cause kernel DoS / memory corruption.
Docker disables `keyctl()` inside containers using seccomp.
* [CVE-2015-3214](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3214),
[4036](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-4036): These are
bugs in common virtualization drivers which could allow a guest OS user to
execute code on the host OS. Exploiting them requires access to virtualization
devices in the guest. Docker hides direct access to these devices when run
without `--privileged`. Interestingly, these seem to be cases where containers
are "more secure" than a VM, going against common wisdom that VMs are
"more secure" than containers.
* [CVE-2016-0728](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-0728):
Use-after-free caused by crafted `keyctl()` calls could lead to privilege
escalation. Docker disables `keyctl()` inside containers using the default
seccomp profile.
* [CVE-2016-2383](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2383):
A bug in eBPF -- the special in-kernel DSL used to express things like seccomp
filters -- allowed arbitrary reads of kernel memory. The `bpf()` system call
is blocked inside Docker containers using (ironically) seccomp.
* [CVE-2016-3134](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-3134),
[4997](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4997),
[4998](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-4998):
A bug in setsockopt with `IPT_SO_SET_REPLACE`, `ARPT_SO_SET_REPLACE`,  and
`ARPT_SO_SET_REPLACE` causing memory corruption / local privilege escalation.
These arguments are blocked by `CAP_NET_ADMIN`, which Docker does not allow by
default.


Bugs not mitigated:

* [CVE-2015-3290](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3290),
[5157](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-5157): Bugs in
the kernel's non-maskable interrupt handling allowed privilege escalation.
Can be exploited in Docker containers because the `modify_ldt()` system call is
not currently blocked using seccomp.
* [CVE-2016-5195](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-5195):
A race condition was found in the way the Linux kernel's memory subsystem
handled the copy-on-write (COW) breakage of private read-only memory mappings,
which allowed unprivileged local users to gain write access to read-only memory.
Also known as "dirty COW."
*Partial mitigations:* on some operating systems this vulnerability is mitigated
by the combination of seccomp filtering of `ptrace` and the fact that `/proc/self/mem` is read-only.


---

# Protect the Docker daemon socket

*Sección: Engine*

By default, Docker runs through a non-networked UNIX socket. It can also
optionally communicate using SSH or a TLS (HTTPS) socket.

## Use SSH to protect the Docker daemon socket

> [!NOTE]
>
> The given `USERNAME` must have permissions to access the docker socket on the
> remote machine. Refer to [manage Docker as a non-root user](../install/linux-postinstall.md#manage-docker-as-a-non-root-user)
> to learn how to give a non-root user access to the docker socket.

The following example creates a [`docker context`](../manage-resources/contexts.md)
to connect with a remote `dockerd` daemon on `host1.example.com` using SSH, and
as the `docker-user` user on the remote machine:

```console
$ docker context create \
    --docker host=ssh://docker-user@host1.example.com \
    --description="Remote engine" \
    my-remote-engine

my-remote-engine
Successfully created context "my-remote-engine"
```

After creating the context, use `docker context use` to switch the `docker` CLI
to use it, and to connect to the remote engine:

```console
$ docker context use my-remote-engine
my-remote-engine
Current context is now "my-remote-engine"

$ docker info
<prints output of the remote engine>
```

Use the `default` context to switch back to the default (local) daemon:

```console
$ docker context use default
default
Current context is now "default"
```

Alternatively, use the `DOCKER_HOST` environment variable to temporarily switch
the `docker` CLI to connect to the remote host using SSH. This does not require
creating a context, and can be useful to create an ad-hoc connection with a different
engine:

```console
$ export DOCKER_HOST=ssh://docker-user@host1.example.com
$ docker info
<prints output of the remote engine>
```

### SSH Tips

For the best user experience with SSH, configure `~/.ssh/config` as follows to allow
reusing a SSH connection for multiple invocations of the `docker` CLI:

```text
ControlMaster     auto
ControlPath       ~/.ssh/control-%C
ControlPersist    yes
```

## Use TLS (HTTPS) to protect the Docker daemon socket

If you need Docker to be reachable through HTTP rather than SSH in a safe manner,
you can enable TLS (HTTPS) by specifying the `tlsverify` flag and pointing Docker's
`tlscacert` flag to a trusted CA certificate.

In the daemon mode, it only allows connections from clients
authenticated by a certificate signed by that CA. In the client mode,
it only connects to servers with a certificate signed by that CA.

> [!IMPORTANT]
>
> Using TLS and managing a CA is an advanced topic. Familiarize yourself
> with OpenSSL, x509, and TLS before using it in production.

### Create a CA, server and client keys with OpenSSL

> [!NOTE]
>
> Replace all instances of `$HOST` in the following example with the
> DNS name of your Docker daemon's host.

First, on the Docker daemon's host machine, generate CA private and public keys:

```console
$ openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
..............................................................................++
........++
e is 65537 (0x10001)
Enter pass phrase for ca-key.pem:
Verifying - Enter pass phrase for ca-key.pem:

$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:Queensland
Locality Name (eg, city) []:Brisbane
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Docker Inc
Organizational Unit Name (eg, section) []:Sales
Common Name (e.g. server FQDN or YOUR name) []:$HOST
Email Address []:Sven@home.org.au
```

Now that you have a CA, you can create a server key and certificate
signing request (CSR). Make sure that "Common Name" matches the hostname you use
to connect to Docker:

> [!NOTE]
>
> Replace all instances of `$HOST` in the following example with the
> DNS name of your Docker daemon's host.

```console
$ openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
.....................................................................++
.................................................................................................++
e is 65537 (0x10001)

$ openssl req -subj "/CN=$HOST" -sha256 -new -key server-key.pem -out server.csr
```

Next, we're going to sign the public key with our CA:

Since TLS connections can be made through IP address as well as DNS name, the IP addresses
need to be specified when creating the certificate. For example, to allow connections
using `10.10.10.20` and `127.0.0.1`:

```console
$ echo subjectAltName = DNS:$HOST,IP:10.10.10.20,IP:127.0.0.1 >> extfile.cnf
```

Set the Docker daemon key's extended usage attributes to be used only for
server authentication:

```console
$ echo extendedKeyUsage = serverAuth >> extfile.cnf
```

Now, generate the signed certificate:

```console
$ openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=/CN=your.host.com
Getting CA Private Key
Enter pass phrase for ca-key.pem:
```

[Authorization plugins](/engine/extend/plugins_authorization/) offer more
fine-grained control to supplement authentication from mutual TLS. In addition
to other information described in the above document, authorization plugins
running on a Docker daemon receive the certificate information for connecting
Docker clients.

For client authentication, create a client key and certificate signing
request:

> [!NOTE]
>
> For simplicity of the next couple of steps, you may perform this
> step on the Docker daemon's host machine as well.

```console
$ openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
.........................................................++
................++
e is 65537 (0x10001)

$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr
```

To make the key suitable for client authentication, create a new extensions
config file:

```console
$ echo extendedKeyUsage = clientAuth > extfile-client.cnf
```

Now, generate the signed certificate:

```console
$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
  -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=/CN=client
Getting CA Private Key
Enter pass phrase for ca-key.pem:
```

After generating `cert.pem` and `server-cert.pem` you can safely remove the
two certificate signing requests and extensions config files:

```console
$ rm -v client.csr server.csr extfile.cnf extfile-client.cnf
```

With a default `umask` of 022, your secret keys are *world-readable* and
writable for you and your group.

To protect your keys from accidental damage, remove their
write permissions. To make them only readable by you, change file modes as follows:

```console
$ chmod -v 0400 ca-key.pem key.pem server-key.pem
```

Certificates can be world-readable, but you might want to remove write access to
prevent accidental damage:

```console
$ chmod -v 0444 ca.pem server-cert.pem cert.pem
```

Now you can make the Docker daemon only accept connections from clients
providing a certificate trusted by your CA:

```console
$ dockerd \
    --tlsverify \
    --tlscacert=ca.pem \
    --tlscert=server-cert.pem \
    --tlskey=server-key.pem \
    -H=0.0.0.0:2376
```

To connect to Docker and validate its certificate, provide your client keys,
certificates and trusted CA:

> [!TIP]
>
> This step should be run on your Docker client machine. As such, you
> need to copy your CA certificate, your server certificate, and your client
> certificate to that machine.

> [!NOTE]
>
> Replace all instances of `$HOST` in the following example with the
> DNS name of your Docker daemon's host.

```console
$ docker --tlsverify \
    --tlscacert=ca.pem \
    --tlscert=cert.pem \
    --tlskey=key.pem \
    -H=$HOST:2376 version
```

> [!NOTE]
>
> Docker over TLS should run on TCP port 2376.

> [!WARNING]
>
> As shown in the example above, you don't need to run the `docker` client
> with `sudo` or the `docker` group when you use certificate authentication.
> That means anyone with the keys can give any instructions to your Docker
> daemon, giving them root access to the machine hosting the daemon. Guard
> these keys as you would a root password!

### Secure by default

If you want to secure your Docker client connections by default, you can move
the files to the `.docker` directory in your home directory --- and set the
`DOCKER_HOST` and `DOCKER_TLS_VERIFY` variables as well (instead of passing
`-H=tcp://$HOST:2376` and `--tlsverify` on every call).

```console
$ mkdir -pv ~/.docker
$ cp -v {ca,cert,key}.pem ~/.docker

$ export DOCKER_HOST=tcp://$HOST:2376 DOCKER_TLS_VERIFY=1
```

Docker now connects securely by default:

    $ docker ps

### Other modes

If you don't want to have complete two-way authentication, you can run
Docker in various other modes by mixing the flags.

#### Daemon modes

 - `tlsverify`, `tlscacert`, `tlscert`, `tlskey` set: Authenticate clients
 - `tls`, `tlscert`, `tlskey`: Do not authenticate clients

#### Client modes

 - `tls`: Authenticate server based on public/default CA pool
 - `tlsverify`, `tlscacert`: Authenticate server based on given CA
 - `tls`, `tlscert`, `tlskey`: Authenticate with client certificate, do not
   authenticate server based on given CA
 - `tlsverify`, `tlscacert`, `tlscert`, `tlskey`: Authenticate with client
   certificate and authenticate server based on given CA

If found, the client sends its client certificate, so you just need
to drop your keys into `~/.docker/{ca,cert,key}.pem`. Alternatively,
if you want to store your keys in another location, you can specify that
location using the environment variable `DOCKER_CERT_PATH`.

```console
$ export DOCKER_CERT_PATH=~/.docker/zone1/
$ docker --tlsverify ps
```

#### Connecting to the secure Docker port using `curl`

To use `curl` to make test API requests, you need to use three extra command line
flags:

```console
$ curl https://$HOST:2376/images/json \
  --cert ~/.docker/cert.pem \
  --key ~/.docker/key.pem \
  --cacert ~/.docker/ca.pem
```

## Related information

* [Using certificates for repository client verification](certificates.md)
* [Use trusted images](trust/index.md)


---

# Rootless mode

*Sección: Engine*

Rootless mode lets you run the Docker daemon and containers as a non-root
user to mitigate potential vulnerabilities in the daemon and
the container runtime.

Rootless mode does not require root privileges even during the installation of
the Docker daemon, as long as the [prerequisites](#prerequisites) are met.

## How it works

Rootless mode executes the Docker daemon and containers inside a user namespace.
This is similar to [`userns-remap` mode](../userns-remap.md), except that
with `userns-remap` mode, the daemon itself is running with root privileges,
whereas in rootless mode, both the daemon and the container are running without
root privileges.

The two modes also differ in how they map container UIDs and GIDs to the
host: see [UID/GID mapping](uid-gid-mapping/) for details.

Rootless mode does not use binaries with `SETUID` bits or file capabilities,
except `newuidmap` and `newgidmap`, which are needed to allow multiple
UIDs/GIDs to be used in the user namespace.


## Prerequisites

-  You must install `newuidmap` and `newgidmap` on the host. These commands
  are provided by the `uidmap` package on most distributions.

- `/etc/subuid` and `/etc/subgid` should contain at least 65,536 subordinate
  UIDs/GIDs for the user. In the following example, the user `testuser` has
  65,536 subordinate UIDs/GIDs (231072-296607).

```console
$ id -u
1001
$ whoami
testuser
$ grep ^$(whoami): /etc/subuid
testuser:231072:65536
$ grep ^$(whoami): /etc/subgid
testuser:231072:65536
```

The `dockerd-rootless-setuptool.sh install` script (see following) automatically shows help
when the prerequisites are not satisfied.

## Install

> [!NOTE]
>
> If the system-wide Docker daemon is already running, consider disabling it:
>```console
>$ sudo systemctl disable --now docker.service docker.socket
>$ sudo rm /var/run/docker.sock
>```
> Should you choose not to shut down the `docker` service and socket, you will need to use the `--force`
> parameter in the next section. There are no known issues, but until you shutdown and disable you're
> still running rootful Docker. 

{{< tabs >}}
{{< tab name="With packages (RPM/DEB)" >}}

If you installed Docker 20.10 or later with [RPM/DEB packages](/engine/install), you should have `dockerd-rootless-setuptool.sh` in `/usr/bin`.

Run `dockerd-rootless-setuptool.sh install` as a non-root user to set up the daemon:

```console
$ dockerd-rootless-setuptool.sh install
[INFO] Creating /home/testuser/.config/systemd/user/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 testuser`

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
export PATH=/usr/bin:$PATH

[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1000/docker.sock
```

If `dockerd-rootless-setuptool.sh` is not present, you may need to install the `docker-ce-rootless-extras` package manually, e.g.,

```console
$ sudo apt-get install -y docker-ce-rootless-extras
```

{{< /tab >}}
{{< tab name="Without packages" >}}

If you do not have permission to run package managers like `apt-get` and `dnf`,
consider using the installation script available at [https://get.docker.com/rootless](https://get.docker.com/rootless).
Since static packages are not available for `s390x`, hence it is not supported for `s390x`.

```console
$ curl -fsSL https://get.docker.com/rootless | sh
...
[INFO] Creating /home/testuser/.config/systemd/user/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 testuser`

[INFO] Creating CLI context "rootless"
Successfully created context "rootless"
[INFO] Using CLI context "rootless"
Current context is now "rootless"

[INFO] Make sure the following environment variable(s) are set (or add them to ~/.bashrc):
export PATH=/home/testuser/bin:$PATH

[INFO] Some applications may require the following environment variable too:
export DOCKER_HOST=unix:///run/user/1000/docker.sock
```

The binaries will be installed at `~/bin`.

{{< /tab >}}
{{< /tabs >}}

Run `docker info` to confirm that the `docker` client is connecting to the Rootless daemon:
```console
$ docker info
Client: Docker Engine - Community
 Version:    28.3.3
 Context:    rootless
...
Server:
...
 Security Options:
  seccomp
   Profile: builtin
  rootless
  cgroupns
...
```

See [Troubleshooting](troubleshoot.md) if you faced an error.


---

# Tips

*Sección: Engine*

## Advanced usage

### Daemon

{{< tabs >}}
{{< tab name="With systemd (Highly recommended)" >}}

The systemd unit file is installed as  `~/.config/systemd/user/docker.service`.

Use `systemctl --user` to manage the lifecycle of the daemon:

```console
$ systemctl --user start docker
```

To launch the daemon on system startup, enable the systemd service and lingering:

```console
$ systemctl --user enable docker
$ sudo loginctl enable-linger $(whoami)
```

Starting Rootless Docker as a systemd-wide service (`/etc/systemd/system/docker.service`)
is not supported, even with the `User=` directive.

{{< /tab >}}
{{< tab name="Without systemd" >}}

To run the daemon directly without systemd, you need to run `dockerd-rootless.sh` instead of `dockerd`.

The following environment variables must be set:
- `$HOME`: the home directory
- `$XDG_RUNTIME_DIR`: an ephemeral directory that is only accessible by the expected user, e,g, `~/.docker/run`.
  The directory should be removed on every host shutdown.
  The directory can be on tmpfs, however, should not be under `/tmp`.
  Locating this directory under `/tmp` might be vulnerable to TOCTOU attack.

{{< /tab >}}
{{< /tabs >}}

It's important to note that with directory paths:

- The socket path is set to `$XDG_RUNTIME_DIR/docker.sock` by default.
  `$XDG_RUNTIME_DIR` is typically set to `/run/user/$UID`.
- The data dir is set to `~/.local/share/docker` by default.
  The data dir should not be on NFS.
- The daemon config dir is set to `~/.config/docker` by default.
  This directory is different from `~/.docker` that is used by the client.

### Client

Since Docker Engine v23.0, `dockerd-rootless-setuptool.sh install` automatically configures
the `docker` CLI to use the `rootless` context.

Prior to Docker Engine v23.0, a user had to specify either the socket path or the CLI context explicitly.

To specify the socket path using `$DOCKER_HOST`:

```console
$ export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
$ docker run -d -p 8080:80 nginx
```

To specify the CLI context using `docker context`:

```console
$ docker context use rootless
rootless
Current context is now "rootless"
$ docker run -d -p 8080:80 nginx
```

## Best practices

### Rootless Docker in Docker

To run Rootless Docker inside "rootful" Docker, use the `docker:<version>-dind-rootless`
image instead of `docker:<version>-dind`.

```console
$ docker run -d --name dind-rootless --privileged docker:25.0-dind-rootless
```

The `docker:<version>-dind-rootless` image runs as a non-root user (UID 1000).
However, `--privileged` is required for disabling seccomp, AppArmor, and mount
masks.

### Expose Docker API socket through TCP

To expose the Docker API socket through TCP, you need to launch `dockerd-rootless.sh`
with `DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="-p 0.0.0.0:2376:2376/tcp"`.

```console
$ DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="-p 0.0.0.0:2376:2376/tcp" \
  dockerd-rootless.sh \
  -H tcp://0.0.0.0:2376 \
  --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem
```

### Expose Docker API socket through SSH

To expose the Docker API socket through SSH, you need to make sure `$DOCKER_HOST`
is set on the remote host.

```console
$ ssh -l <REMOTEUSER> <REMOTEHOST> 'echo $DOCKER_HOST'
unix:///run/user/1001/docker.sock
$ docker -H ssh://<REMOTEUSER>@<REMOTEHOST> run ...
```

### Routing ping packets

On some distributions, `ping` does not work by default.

Add `net.ipv4.ping_group_range = 0   2147483647` to `/etc/sysctl.conf` (or
`/etc/sysctl.d`) and run `sudo sysctl --system` to allow using `ping`.

### Exposing privileged ports

To expose privileged ports (< 1024), set `CAP_NET_BIND_SERVICE` on `rootlesskit` binary and restart the daemon.

```console
$ sudo setcap cap_net_bind_service=ep $(which rootlesskit)
$ systemctl --user restart docker
```

Or add `net.ipv4.ip_unprivileged_port_start=0` to `/etc/sysctl.conf` (or
`/etc/sysctl.d`) and run `sudo sysctl --system`.

### Limiting resources

Limiting resources with cgroup-related `docker run` flags such as `--cpus`, `--memory`, `--pids-limit`
is supported only when running with cgroup v2 and systemd.
See [Changing cgroup version](../../containers/runmetrics.md) to enable cgroup v2.

If `docker info` shows `none` as `Cgroup Driver`, the conditions are not satisfied.
When these conditions are not satisfied, rootless mode ignores the cgroup-related `docker run` flags.
See [Limiting resources without cgroup](#limiting-resources-without-cgroup) for workarounds.

If `docker info` shows `systemd` as `Cgroup Driver`, the conditions are satisfied.
However, typically, only `memory` and `pids` controllers are delegated to non-root users by default.

```console
$ cat /sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers
memory pids
```

To allow delegation of all controllers, change the systemd configuration:

```console
$ sudo mkdir -p /etc/systemd/system/user@.service.d
```

Create `/etc/systemd/system/user@.service.d/delegate.conf`:

```ini
[Service]
Delegate=cpu cpuset io memory pids
```

Then reload systemd:

```console
$ sudo systemctl daemon-reload
```

> [!NOTE]
>
> Delegating `cpuset` requires systemd 244 or later.

#### Limiting resources without cgroup

Even when cgroup is not available, you can still use the traditional `ulimit` and [`cpulimit`](https://github.com/opsengine/cpulimit),
though they work in process-granularity rather than in container-granularity,
and can be arbitrarily disabled by the container process.

For example:

- To limit CPU usage to 0.5 cores (similar to `docker run --cpus 0.5`):
  `docker run <IMAGE> cpulimit --limit=50 --include-children <COMMAND>`
- To limit max VSZ to 64MiB (similar to `docker run --memory 64m`):
  `docker run <IMAGE> sh -c "ulimit -v 65536; <COMMAND>"`

- To limit max number of processes to 100 per namespaced UID 2000
  (similar to `docker run --pids-limit=100`):
  `docker run --user 2000 --ulimit nproc=100 <IMAGE> <COMMAND>`


---

# Troubleshooting

*Sección: Engine*

### Distribution-specific hint

{{< tabs >}}
{{< tab name="Ubuntu" >}}
- Ubuntu 24.04 and later enables restricted unprivileged user namespaces by
  default, which prevents unprivileged processes in creating user namespaces
  unless an AppArmor profile is configured to allow programs to use
  unprivileged user namespaces.

  If you install `docker-ce-rootless-extras` using the deb package (`apt-get
  install docker-ce-rootless-extras`), then the AppArmor profile for
  `rootlesskit` is already bundled with the `apparmor` deb package. With this
  installation method, you don't need to add any manual the AppArmor
  configuration. If you install the rootless extras using the [installation
  script](https://get.docker.com/rootless), however, you must add an AppArmor
  profile for `rootlesskit` manually:

  1. Create and install the currently logged-in user's AppArmor profile:

     ```console
     $ filename=$(echo $HOME/bin/rootlesskit | sed -e 's@^/@@' -e 's@/@.@g')
     $ [ ! -z "${filename}" ] && sudo cat <<EOF > /etc/apparmor.d/${filename}
     abi <abi/4.0>,
     include <tunables/global>

     "$HOME/bin/rootlesskit" flags=(unconfined) {
       userns,

       include if exists <local/${filename}>
     }
     EOF
     ```
  2. Restart AppArmor.

     ```console
     $ systemctl restart apparmor.service
     ```

{{< /tab >}}
{{< tab name="Arch Linux" >}}
- Add `kernel.unprivileged_userns_clone=1` to `/etc/sysctl.conf` (or
  `/etc/sysctl.d`) and run `sudo sysctl --system`
{{< /tab >}}
{{< tab name="openSUSE and SLES" >}}
- `sudo modprobe ip_tables iptable_mangle iptable_nat iptable_filter` is required.
  This might be required on other distributions as well depending on the configuration.

- Known to work on openSUSE 15 and SLES 15.
{{< /tab >}}
{{< tab name="CentOS, RHEL, and Fedora" >}}
- For RHEL 8 and similar distributions, installing `fuse-overlayfs` is recommended. Run `sudo dnf install -y fuse-overlayfs`.
  This step is not required on RHEL 9 and similar distributions.

- You might need `sudo dnf install -y iptables`.
{{< /tab >}}
{{< /tabs >}}

## Known limitations

- Only the following storage drivers are supported:
  - `overlay2` (only if running with kernel 5.11 or later)
  - `fuse-overlayfs` (only if running with kernel 4.18 or later, and `fuse-overlayfs` is installed)
  - `btrfs` (only if running with kernel 4.18 or later, or `~/.local/share/docker` is mounted with `user_subvol_rm_allowed` mount option)
  - `vfs`
- cgroup is supported only when running with cgroup v2 and systemd. See [Limiting resources](tips.md#limiting-resources).
- Following features are not supported:
  - AppArmor
  - Checkpoint
  - Overlay network
  - Exposing SCTP ports
- To use the `ping` command, see [Routing ping packets](tips.md#routing-ping-packets).
- To expose privileged TCP/UDP ports (< 1024), see [Exposing privileged ports](tips.md#exposing-privileged-ports).
- `IPAddress` shown in `docker inspect` is namespaced inside RootlessKit's network namespace.
  This means the IP address is not reachable from the host without `nsenter`-ing into the network namespace.
- Port forwarding with `docker run -p` does not propagate source IP addresses by default.
  See [`docker run -p` does not propagate source IP addresses](#docker-run--p-does-not-propagate-source-ip-addresses) to enable source IP propagation.
- NFS mounts as the docker "data-root" is not supported. This limitation is not specific to rootless mode.
- Capabilities added with `--cap-add` apply only to resources governed by the
  container's user namespace. They don't grant privileges over host or other
  global resources. As a result, operations that require capabilities in the
  [initial user namespace](https://man7.org/linux/man-pages/man7/user_namespaces.7.html)
  can still fail.

### Historical limitations

#### Until Docker Engine v29.5

- Host network (`docker run --net=host`) was namespaced inside RootlessKit.
  This meant that ports listened by containers with `--net=host` were not reachable from the real host network namespace.

## Troubleshooting

### Unable to install with systemd when systemd is present on the system

``` console
$ dockerd-rootless-setuptool.sh install
[INFO] systemd not detected, dockerd-rootless.sh needs to be started manually:
...
```
`rootlesskit` cannot detect systemd properly if you switch to your user via `sudo su`. For users which cannot be logged-in, you must use the `machinectl` command which is part of the `systemd-container` package. After installing `systemd-container` switch to `myuser` with the following command:
``` console
$ sudo machinectl shell myuser@
```
Where `myuser@` is your desired username and @ signifies this machine.

### Errors when starting the Docker daemon

**\[rootlesskit:parent\] error: failed to start the child: fork/exec /proc/self/exe: operation not permitted**

This error occurs mostly when the value of `/proc/sys/kernel/unprivileged_userns_clone` is set to 0:

```console
$ cat /proc/sys/kernel/unprivileged_userns_clone
0
```

To fix this issue, add  `kernel.unprivileged_userns_clone=1` to
`/etc/sysctl.conf` (or `/etc/sysctl.d`) and run `sudo sysctl --system`.

**\[rootlesskit:parent\] error: failed to start the child: fork/exec /proc/self/exe: no space left on device**

This error occurs mostly when the value of `/proc/sys/user/max_user_namespaces` is too small:

```console
$ cat /proc/sys/user/max_user_namespaces
0
```

To fix this issue, add  `user.max_user_namespaces=28633` to
`/etc/sysctl.conf` (or `/etc/sysctl.d`) and run `sudo sysctl --system`.

**\[rootlesskit:parent\] error: failed to setup UID/GID map: failed to compute uid/gid map: No subuid ranges found for user 1001 ("testuser")**

This error occurs when `/etc/subuid` and `/etc/subgid` are not configured. See [Prerequisites](index.md#prerequisites).

**could not get XDG_RUNTIME_DIR**

This error occurs when `$XDG_RUNTIME_DIR` is not set.

On a non-systemd host, you need to create a directory and then set the path:

```console
$ export XDG_RUNTIME_DIR=$HOME/.docker/xrd
$ rm -rf $XDG_RUNTIME_DIR
$ mkdir -p $XDG_RUNTIME_DIR
$ dockerd-rootless.sh
```

> [!NOTE]
>
> You must remove the directory every time you log out.

On a systemd host, log into the host using `pam_systemd` (see below).
The value is automatically set to `/run/user/$UID` and cleaned up on every logout.

**`systemctl --user` fails with "Failed to connect to bus: No such file or directory"**

This error occurs mostly when you switch from the root user to a non-root user with `sudo`:

```console
# sudo -iu testuser
$ systemctl --user start docker
Failed to connect to bus: No such file or directory
```

Instead of `sudo -iu <USERNAME>`, you need to log in using `pam_systemd`. For example:

- Log in through the graphic console
- `ssh <USERNAME>@localhost`
- `machinectl shell <USERNAME>@`

**The daemon does not start up automatically**

You need `sudo loginctl enable-linger $(whoami)` to enable the daemon to start
up automatically. See [Advanced Usage](./tips.md/#advanced-usage).

### `docker pull` errors

**docker: failed to register layer: Error processing tar file(exit status 1): lchown &lt;FILE&gt;: invalid argument**

This error occurs when the number of available entries in `/etc/subuid` or
`/etc/subgid` is not sufficient. The number of entries required vary across
images. However, 65,536 entries are sufficient for most images. See
[Prerequisites](index.md#prerequisites).

**docker: failed to register layer: ApplyLayer exit status 1 stdout:  stderr: lchown &lt;FILE&gt;: operation not permitted**

This error occurs mostly when `~/.local/share/docker` is located on NFS.

A workaround is to specify non-NFS `data-root` directory in `~/.config/docker/daemon.json` as follows:
```json
{"data-root":"/somewhere-out-of-nfs"}
```

### `docker run` errors

**docker: Error response from daemon: OCI runtime create failed: ...: read unix @-&gt;/run/systemd/private: read: connection reset by peer: unknown.**

This error occurs on cgroup v2 hosts mostly when the dbus daemon is not running for the user.

```console
$ systemctl --user is-active dbus
inactive

$ docker run hello-world
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:385: applying cgroup configuration for process caused: error while starting unit "docker
-931c15729b5a968ce803784d04c7421f791d87e5ca1891f34387bb9f694c488e.scope" with properties [{Name:Description Value:"libcontainer container 931c15729b5a968ce803784d04c7421f791d87e5ca1891f34387bb9f694c488e"} {Name:Slice Value:"use
r.slice"} {Name:PIDs Value:@au [4529]} {Name:Delegate Value:true} {Name:MemoryAccounting Value:true} {Name:CPUAccounting Value:true} {Name:IOAccounting Value:true} {Name:TasksAccounting Value:true} {Name:DefaultDependencies Val
ue:false}]: read unix @->/run/systemd/private: read: connection reset by peer: unknown.
```

To fix the issue, run `sudo apt-get install -y dbus-user-session` or `sudo dnf install -y dbus-daemon`, and then relogin.

If the error still occurs, try running `systemctl --user enable --now dbus` (without sudo).

**`--cpus`, `--memory`, and `--pids-limit` are ignored**

This is an expected behavior on cgroup v1 mode.
To use these flags, the host needs to be configured for enabling cgroup v2.
For more information, see [Limiting resources](tips.md#limiting-resources).

### Networking errors

This section provides troubleshooting tips for networking in rootless mode.

Networking in rootless mode is supported via network and port drivers in
RootlessKit. Network performance and characteristics depend on the combination
of network and port driver you use. If you're experiencing unexpected behavior
or performance related to networking, review the following table which shows
the configurations supported by RootlessKit, and how they compare:

| Network driver | Port driver          | Net throughput | Port throughput | Source IP propagation | No SUID | Note                                                                         |
| -------------- | -------------------- | -------------- | --------------- | --------------------- | ------- | ---------------------------------------------------------------------------- |
| `gvisor-tap-vsock`| `builtin`         | Slow           | Fast ✅         | ✅ (*)                | ✅      | Default when slirp4netns is not installed                                    |
| `slirp4netns`     | `builtin`         | Slow           | Fast ✅         | ✅ (*)                | ✅      | Default when slirp4netns is installed                                        |
| `vpnkit`          | `builtin`         | Slow           | Fast ✅         | ✅ (*)                | ✅      | Legacy                                                                       |
| `gvisor-tap-vsock`| `gvisor-tap-vsock`| Slow           | Slow            | ❌                    | ✅      | Not recommended. Use `builtin` port driver instead.                          |
| `slirp4netns`     | `slirp4netns`     | Slow           | Slow            | ✅                    | ✅      |                                                                              |
| `pasta`           | `implicit`        | Slow           | Fast ✅         | ✅                    | ✅      | Experimental; Needs pasta version 2023_12_04 or later                        |
| `pasta`           | `pesto`           | —              | —               | —                     | —       | IPv4 only; needs Docker Engine 29.8+                                         |
| `lxc-user-nic`    | `builtin`         | Fast ✅        | Fast ✅         | ✅ (*)                | ❌      | Experimental                                                                 |
| `bypass4netns`    | `bypass4netns`    | Fast ✅        | Fast ✅         | ✅                    | ✅      | **Note:** Not integrated to RootlessKit as it needs a custom seccomp profile |

(*) Applicable since RootlessKit v3.0. Also requires `userland-proxy` to be disabled.

For information about troubleshooting specific networking issues, see:

- [`docker run -p` fails with `cannot expose privileged port`](#docker-run--p-fails-with-cannot-expose-privileged-port)
- [Ping doesn't work](#ping-doesnt-work)
- [`IPAddress` shown in `docker inspect` is unreachable](#ipaddress-shown-in-docker-inspect-is-unreachable)
- [`--net=host` doesn't listen ports on the host network namespace](#--nethost-doesnt-listen-ports-on-the-host-network-namespace)
- [Network is slow](#network-is-slow)
- [`docker run -p` does not propagate source IP addresses](#docker-run--p-does-not-propagate-source-ip-addresses)

#### `docker run -p` fails with `cannot expose privileged port`

`docker run -p` fails with this error when a privileged port (< 1024) is specified as the host port.

```console
$ docker run -p 80:80 nginx:alpine
docker: Error response from daemon: driver failed programming external connectivity on endpoint focused_swanson (9e2e139a9d8fc92b37c36edfa6214a6e986fa2028c0cc359812f685173fa6df7): Error starting userland proxy: error while calling PortManager.AddPort(): cannot expose privileged port 80, you might need to add "net.ipv4.ip_unprivileged_port_start=0" (currently 1024) to /etc/sysctl.conf, or set CAP_NET_BIND_SERVICE on rootlesskit binary, or choose a larger port number (>= 1024): listen tcp 0.0.0.0:80: bind: permission denied.
```

When you experience this error, consider using an unprivileged port instead. For example, 8080 instead of 80.

```console
$ docker run -p 8080:80 nginx:alpine
```

To allow exposing privileged ports, see [Exposing privileged ports](tips.md#exposing-privileged-ports).

#### Ping doesn't work

Ping does not work when `/proc/sys/net/ipv4/ping_group_range` is set to `1 0`:

```console
$ cat /proc/sys/net/ipv4/ping_group_range
1       0
```

For details, see [Routing ping packets](tips.md#routing-ping-packets).

#### `IPAddress` shown in `docker inspect` is unreachable

This is an expected behavior, as the daemon is namespaced inside RootlessKit's
network namespace. Use `docker run -p` instead.

#### `--net=host` doesn't listen ports on the host network namespace

This was an expected behavior until Docker Engine v29.5, as the daemon was namespaced inside RootlessKit's
network namespace. Use `docker run -p` instead, or upgrade to Docker Engine v29.5 or later.

#### Network is slow

Docker with rootless mode uses a TCP/IP stack running in user mode, such as:
- [slirp4netns](https://github.com/rootless-containers/slirp4netns) (default when slirp4netns is installed)
- [pasta](https://passt.top/passt/about/)
- [VPNKit](https://github.com/moby/vpnkit)
- [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock) (default when none of the above is installed)

The TCP/IP stack in user mode is generally slower than the one in kernel mode, and the performance may vary depending on the network driver used.

See [RootlessKit documentation](https://github.com/rootless-containers/rootlesskit/blob/v3.0.0/docs/network.md)
for more information.

##### Workaround 1: bypass user-mode TCP/IP stack

Use `docker run --net=host` to bypass the user-mode TCP/IP stack.
This is applicable since Docker Engine v29.5.
However, this requires the container to share the host network namespace, which may not be desirable for security reasons.

##### Workaround 2: disable user-mode TCP/IP stack

Alternatively, you can use the `lxc-user-nic` network driver (experimental) to disable the user-mode TCP/IP stack entirely.
However, this requires configuring `/etc/lxc/lxc-usernet` for enabling the privileged helper.

```bash
sudo apt-get install -y lxc
sudo mkdir -p /etc/lxc
cat <<EOF | sudo tee /etc/lxc/lxc-usernet
# USERNAME TYPE BRIDGE COUNT
$USER veth lxcbr0 10
EOF
```

Also, make sure that the rootful daemon is not running, as its iptables rules may interfere with the `lxc-user-nic` driver.
```console
$ systemctl is-active docker.service
inactive

$ systemctl is-active docker.socket
inactive
```

The network driver can be specified by creating `~/.config/systemd/user/docker.service.d/override.conf` with the following content:

```systemd
[Service]
Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=lxc-user-nic"
# Optional: specify MTU (may affect throughput)
# Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_MTU=<INTEGER>"
```

And then restart the daemon:
```bash
systemctl --user daemon-reload
systemctl --user restart docker
```

#### `docker run -p` does not propagate source IP addresses

{{< tabs >}}
{{< tab name="RootlessKit v3.0 or later" >}}
This is because Docker Engine's `userland-proxy` is incompatible with RootlessKit's source IP propagation.

To disable userland-proxy, add the following configuration to `~/.config/docker/daemon.json`:

```json
{"userland-proxy": false}
```

Then restart the daemon:

```bash
systemctl --user restart docker
```

You may also need to load `br_netfilter` kernel module:

```bash
sudo tee /etc/modules-load.d/docker.conf <<EOF >/dev/null
br_netfilter
EOF

sudo systemctl restart systemd-modules-load.service
```
{{< /tab >}}
{{< tab name="Prior versions" >}}
This is because RootlessKit's `builtin` port didn't support source IP propagation until v3.0. To enable
source IP propagation, you can:

- Use the `slirp4netns` RootlessKit port driver
- Use the `pasta` RootlessKit network driver, with the `implicit` port driver

The `pasta` network driver is experimental, but provides improved throughput
performance compared to the `slirp4netns` port driver. The `pasta` driver
requires Docker Engine version 25.0 or later.

To change the RootlessKit networking configuration:

1. Create a file at `~/.config/systemd/user/docker.service.d/override.conf`.
2. Add the following contents, depending on which configuration you would like to use:

   - `slirp4netns`

      ```systemd
      [Service]
      Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
      Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
      ```

   - `pasta` network driver with `implicit` port driver

      ```systemd
      [Service]
      Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=pasta"
      Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=implicit"
      ```

3. Restart the daemon:

   ```console
   $ systemctl --user daemon-reload
   $ systemctl --user restart docker
   ```
{{< /tab >}}
{{< /tabs >}}

For more information about networking options for RootlessKit, see:

- [Network drivers](https://github.com/rootless-containers/rootlesskit/blob/v3.0.0/docs/network.md)
- [Port drivers](https://github.com/rootless-containers/rootlesskit/blob/v3.0.0/docs/port.md)

### Tips for debugging

**Entering into `dockerd` namespaces**

The `dockerd-rootless.sh` script executes `dockerd` in its own user, mount, and network namespaces.

For debugging, you can enter the namespaces by running
`nsenter -U --preserve-credentials -n -m -t $(cat $XDG_RUNTIME_DIR/docker.pid)`.

## Uninstall

To remove the systemd service of the Docker daemon, run `dockerd-rootless-setuptool.sh uninstall`:

```console
$ dockerd-rootless-setuptool.sh uninstall
+ systemctl --user stop docker.service
+ systemctl --user disable docker.service
Removed /home/testuser/.config/systemd/user/default.target.wants/docker.service.
[INFO] Uninstalled docker.service
[INFO] This uninstallation tool does NOT remove Docker binaries and data.
[INFO] To remove data, run: `/usr/bin/rootlesskit rm -rf /home/testuser/.local/share/docker`
```

Unset environment variables PATH and DOCKER_HOST if you have added them to `~/.bashrc`.

To remove the data directory, run `rootlesskit rm -rf ~/.local/share/docker`.

To remove the binaries, remove `docker-ce-rootless-extras` package if you installed Docker with package managers.
If you installed Docker with https://get.docker.com/rootless ([Install without packages](index.md#install)),
remove the binary files under `~/bin`:
```console
$ cd ~/bin
$ rm -f containerd containerd-shim containerd-shim-runc-v2 ctr docker docker-init docker-proxy dockerd dockerd-rootless-setuptool.sh dockerd-rootless.sh rootlesskit rootlesskit-docker-proxy runc vpnkit
```


---

# UID/GID mapping

*Sección: Engine*

Rootless mode and [`userns-remap` mode](../userns-remap.md) map container UIDs
and GIDs to the host differently.

- In `userns-remap` mode, container UID `0` is mapped to the first subordinate
  UID listed in `/etc/subuid` for the remap user, and container UID `n` is
  mapped to `subuid + n`.
- In rootless mode, container UID `0` is mapped to the host UID of the user
  running rootless Docker (the result of `id -u`); container UID `n` (for
  `n >= 1`) is mapped to `subuid + (n - 1)`.

GIDs follow the same rules using `/etc/subgid`.

This difference matters when setting file permissions on bind-mounted
directories: in rootless mode, files owned by your host user appear as owned
by `root` inside the container.


---

# Seccomp security profiles for Docker

*Sección: Engine*

Secure computing mode (`seccomp`) is a Linux kernel feature. You can use it to
restrict the actions available within the container. The `seccomp()` system
call operates on the seccomp state of the calling process. You can use this
feature to restrict your application's access.

This feature is available only if Docker has been built with `seccomp` and the
kernel is configured with `CONFIG_SECCOMP` enabled. To check if your kernel
supports `seccomp`:

```console
$ grep CONFIG_SECCOMP= /boot/config-$(uname -r)
CONFIG_SECCOMP=y
```

## Pass a profile for a container

The [default `seccomp` profile](https://github.com/moby/profiles/blob/main/seccomp/default.json)
provides a sane default for running containers with seccomp and disables around
44 system calls out of 300+. It is moderately protective while providing wide
application compatibility.

In effect, the profile is an allowlist that denies access to system calls by
default and then allows specific system calls. The profile works by defining a
`defaultAction` of `SCMP_ACT_ERRNO` and overriding that action only for specific
system calls. The effect of `SCMP_ACT_ERRNO` is to cause a `Permission Denied`
error. Next, the profile defines a specific list of system calls which are fully
allowed, because their `action` is overridden to be `SCMP_ACT_ALLOW`. Finally,
some specific rules are for individual system calls such as `personality`, and others,
to allow variants of those system calls with specific arguments.

`seccomp` is instrumental for running Docker containers with least privilege. It
is not recommended to change the default `seccomp` profile.

When you run a container, it uses the default profile unless you override it
with the `--security-opt` option. For example, the following explicitly
specifies a policy:

```console
$ docker run --rm \
             -it \
             --security-opt seccomp=/path/to/seccomp/profile.json \
             hello-world
```

The Docker CLI resolves a relative profile path from the working directory
where you invoke `docker`. The CLI reads the profile and sends its contents to
the daemon, so the profile must be available on the client host when the client
and daemon run on separate hosts.

### Significant syscalls blocked by the default profile

Docker's default seccomp profile is an allowlist which specifies the calls that
are allowed. The table below lists the significant (but not all) syscalls that
are effectively blocked because they are not on the allowlist. The table includes
the reason each syscall is blocked rather than white-listed.

| Syscall             | Description                                                                                                                                                                                                                                    |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `acct`              | Accounting syscall which could let containers disable their own resource limits or process accounting. Also gated by `CAP_SYS_PACCT`.                                                                                                          |
| `add_key`           | Prevent containers from using the kernel keyring, which is not namespaced.                                                                                                                                                                     |
| `bpf`               | Deny loading potentially persistent BPF programs into kernel, already gated by `CAP_SYS_ADMIN`.                                                                                                                                                |
| `clock_adjtime`     | Time/date is not namespaced. Also gated by `CAP_SYS_TIME`.                                                                                                                                                                                     |
| `clock_settime`     | Time/date is not namespaced. Also gated by `CAP_SYS_TIME`.                                                                                                                                                                                     |
| `clone`             | Deny cloning new namespaces. Also gated by `CAP_SYS_ADMIN` for CLONE\_\* flags, except `CLONE_NEWUSER`.                                                                                                                                        |
| `create_module`     | Deny manipulation and functions on kernel modules. Obsolete. Also gated by `CAP_SYS_MODULE`.                                                                                                                                                   |
| `delete_module`     | Deny manipulation and functions on kernel modules. Also gated by `CAP_SYS_MODULE`.                                                                                                                                                             |
| `finit_module`      | Deny manipulation and functions on kernel modules. Also gated by `CAP_SYS_MODULE`.                                                                                                                                                             |
| `get_kernel_syms`   | Deny retrieval of exported kernel and module symbols. Obsolete.                                                                                                                                                                                |
| `get_mempolicy`     | Syscall that modifies kernel memory and NUMA settings. Already gated by `CAP_SYS_NICE`.                                                                                                                                                        |
| `init_module`       | Deny manipulation and functions on kernel modules. Also gated by `CAP_SYS_MODULE`.                                                                                                                                                             |
| `ioperm`            | Prevent containers from modifying kernel I/O privilege levels. Already gated by `CAP_SYS_RAWIO`.                                                                                                                                               |
| `iopl`              | Prevent containers from modifying kernel I/O privilege levels. Already gated by `CAP_SYS_RAWIO`.                                                                                                                                               |
| `io_uring_enter`    | Blocked due to security vulnerabilities that can be exploited to break out of containers. See [moby/moby#46762](https://github.com/moby/moby/pull/46762).                                                                                      |
| `io_uring_register` | Blocked due to security vulnerabilities that can be exploited to break out of containers. See [moby/moby#46762](https://github.com/moby/moby/pull/46762).                                                                                      |
| `io_uring_setup`    | Blocked due to security vulnerabilities that can be exploited to break out of containers. See [moby/moby#46762](https://github.com/moby/moby/pull/46762).                                                                                      |
| `kcmp`              | Restrict process inspection capabilities, already blocked by dropping `CAP_SYS_PTRACE`.                                                                                                                                                        |
| `kexec_file_load`   | Sister syscall of `kexec_load` that does the same thing, slightly different arguments. Also gated by `CAP_SYS_BOOT`.                                                                                                                           |
| `kexec_load`        | Deny loading a new kernel for later execution. Also gated by `CAP_SYS_BOOT`.                                                                                                                                                                   |
| `keyctl`            | Prevent containers from using the kernel keyring, which is not namespaced.                                                                                                                                                                     |
| `lookup_dcookie`    | Tracing/profiling syscall, which could leak a lot of information on the host. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                   |
| `mbind`             | Syscall that modifies kernel memory and NUMA settings. Already gated by `CAP_SYS_NICE`.                                                                                                                                                        |
| `mount`             | Deny mounting, already gated by `CAP_SYS_ADMIN`.                                                                                                                                                                                               |
| `move_pages`        | Syscall that modifies kernel memory and NUMA settings.                                                                                                                                                                                         |
| `nfsservctl`        | Deny interaction with the kernel NFS daemon. Obsolete since Linux 3.1.                                                                                                                                                                         |
| `open_by_handle_at` | Cause of an old container breakout. Also gated by `CAP_DAC_READ_SEARCH`.                                                                                                                                                                       |
| `perf_event_open`   | Tracing/profiling syscall, which could leak a lot of information on the host.                                                                                                                                                                  |
| `personality`       | Prevent container from enabling BSD emulation. Not inherently dangerous, but poorly tested, potential for a lot of kernel vulnerabilities.                                                                                                     |
| `pivot_root`        | Deny `pivot_root`, should be privileged operation.                                                                                                                                                                                             |
| `process_vm_readv`  | Restrict process inspection capabilities, already blocked by dropping `CAP_SYS_PTRACE`.                                                                                                                                                        |
| `process_vm_writev` | Restrict process inspection capabilities, already blocked by dropping `CAP_SYS_PTRACE`.                                                                                                                                                        |
| `ptrace`            | Tracing/profiling syscall. Blocked in Linux kernel versions before 4.8 to avoid seccomp bypass. Tracing/profiling arbitrary processes is already blocked by dropping `CAP_SYS_PTRACE`, because it could leak a lot of information on the host. |
| `query_module`      | Deny manipulation and functions on kernel modules. Obsolete.                                                                                                                                                                                   |
| `quotactl`          | Quota syscall which could let containers disable their own resource limits or process accounting. Also gated by `CAP_SYS_ADMIN`.                                                                                                               |
| `reboot`            | Don't let containers reboot the host. Also gated by `CAP_SYS_BOOT`.                                                                                                                                                                            |
| `request_key`       | Prevent containers from using the kernel keyring, which is not namespaced.                                                                                                                                                                     |
| `set_mempolicy`     | Syscall that modifies kernel memory and NUMA settings. Already gated by `CAP_SYS_NICE`.                                                                                                                                                        |
| `setns`             | Deny associating a thread with a namespace. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                     |
| `settimeofday`      | Time/date is not namespaced. Also gated by `CAP_SYS_TIME`.                                                                                                                                                                                     |
| `stime`             | Time/date is not namespaced. Also gated by `CAP_SYS_TIME`.                                                                                                                                                                                     |
| `socket`            | Blocked for `AF_ALG` to prevent in-container privilege escalation via the kernel cryptographic API ([CVE-2026-31431](https://nvd.nist.gov/vuln/detail/CVE-2026-31431)). Also blocked for `AF_VSOCK`. These do not cover `socketcall(2)`, which can be easily bypassed. `AF_ALG` is denied on both paths by the default AppArmor profile (`deny network alg,`) or the SELinux policy module; `AF_VSOCK` has no equivalent LSM rule. See [moby/moby#52494](https://github.com/moby/moby/pull/52494). |
| `swapon`            | Deny start/stop swapping to file/device. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                        |
| `swapoff`           | Deny start/stop swapping to file/device. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                        |
| `sysfs`             | Obsolete syscall.                                                                                                                                                                                                                              |
| `_sysctl`           | Obsolete, replaced by /proc/sys.                                                                                                                                                                                                               |
| `umount`            | Should be a privileged operation. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                               |
| `umount2`           | Should be a privileged operation. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                               |
| `unshare`           | Deny cloning new namespaces for processes. Also gated by `CAP_SYS_ADMIN`, with the exception of `unshare --user`.                                                                                                                              |
| `uselib`            | Older syscall related to shared libraries, unused for a long time.                                                                                                                                                                             |
| `userfaultfd`       | Userspace page fault handling, largely needed for process migration.                                                                                                                                                                           |
| `ustat`             | Obsolete syscall.                                                                                                                                                                                                                              |
| `vm86`              | In kernel x86 real mode virtual machine. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                        |
| `vm86old`           | In kernel x86 real mode virtual machine. Also gated by `CAP_SYS_ADMIN`.                                                                                                                                                                        |

## Run without the default seccomp profile

You can pass `unconfined` to run a container without the default seccomp
profile.

```console
$ docker run --rm -it --security-opt seccomp=unconfined debian:latest \
    unshare --map-root-user --user sh -c whoami
```


---

# Content trust in Docker

*Sección: Engine*

When transferring data among networked systems, trust is a central concern. In
particular, when communicating over an untrusted medium such as the internet, it
is critical to ensure the integrity and the publisher of all the data a system
operates on. You use Docker Engine to push and pull images (data) to a
public or private registry. Content trust gives you the ability to verify both
the integrity and the publisher of all the data received from a registry over
any channel.

## About Docker Content Trust (DCT)

Docker Content Trust (DCT) provides the ability to use digital signatures for
data sent to and received from remote Docker registries. These signatures allow
client-side or runtime verification of the integrity and publisher of specific
image tags.

Through DCT, image publishers can sign their images and image consumers can
ensure that the images they pull are signed. Publishers could be individuals
or organizations manually signing their content or automated software supply
chains signing content as part of their release process.

> [!WARNING]
>
> Docker Content Trust (DCT) is being retired. The Notary v1 service at
> `notary.docker.io` will shut down on December 8, 2026. For more information, see
> [Docker Content Trust (DCT)](../../../retired.md#docker-content-trust-dct).

### Image tags and DCT

An individual image record has the following identifier:

```text
[REGISTRY_HOST[:REGISTRY_PORT]/]REPOSITORY[:TAG]
```

A particular image `REPOSITORY` can have multiple tags. For example, `latest` and
 `3.1.2` are both tags on the `mongo` image. An image publisher can build an image
 and tag combination many times changing the image with each build.

DCT is associated with the `TAG` portion of an image. Each image repository has
a set of keys that image publishers use to sign an image tag. Image publishers
have discretion on which tags they sign.

An image repository can contain an image with one tag that is signed and another
tag that is not. For example, consider [the Mongo image
repository](https://hub.docker.com/_/mongo/tags/). The `latest`
tag could be unsigned while the `3.1.6` tag could be signed. It is the
responsibility of the image publisher to decide if an image tag is signed or
not. In this representation, some image tags are signed, others are not:

![Signed tags](images/tag_signing.png)

Publishers can choose to sign a specific tag or not. As a result, the content of
an unsigned tag and that of a signed tag with the same name may not match. For
example, a publisher can push a tagged image `someimage:latest` and sign it.
Later, the same publisher can push an unsigned `someimage:latest` image. This second
push replaces the last unsigned tag `latest` but does not affect the signed `latest` version.
The ability to choose which tags they can sign, allows publishers to iterate over
the unsigned version of an image before officially signing it.

Image consumers can enable DCT to ensure that images they use were signed. If a
consumer enables DCT, they can only pull, run, or build with trusted images.
Enabling DCT is a bit like applying a "filter" to your registry. Consumers "see"
only signed image tags and the less desirable, unsigned image tags are
"invisible" to them.

![Trust view](images/trust_view.png)

To the consumer who has not enabled DCT, nothing about how they work with Docker
images changes. Every image is visible regardless of whether it is signed or
not.

### Docker Content Trust Keys

Trust for an image tag is managed through the use of signing keys. A key set is
created when an operation using DCT is first invoked. A key set consists
of the following classes of keys:

- An offline key that is the root of DCT for an image tag
- Repository or tagging keys that sign tags
- Server-managed keys such as the timestamp key, which provides freshness
	security guarantees for your repository

The following image depicts the various signing keys and their relationships:

![Content Trust components](images/trust_components.png)

> [!WARNING]
>
>The root key once lost is not recoverable. If you lose any other key, send an email to [Docker Hub Support](mailto:hub-support@docker.com). This loss also requires manual intervention from every
consumer that used a signed tag from this repository prior to the loss.

You should back up the root key somewhere safe. Given that it is only required
to create new repositories, it is a good idea to store it offline in hardware.
For details on securing, and backing up your keys, make sure you
read how to [manage keys for DCT](trust-key-mng.md).

## Signing images with Docker Content Trust

Within the Docker CLI we can sign and push a container image with the
`$ docker trust` command syntax. This is built on top of the Notary feature
set. For more information, see the [Notary GitHub repository](https://github.com/theupdateframework/notary).

A prerequisite for signing an image is a Docker Registry with a Notary server (such as Docker Hub) attached.
Refer to [Deploying Notary](/engine/security/trust/deploying_notary/) for instructions.

To sign a Docker Image you will need a delegation key pair. These keys
can be generated locally using `$ docker trust key generate` or generated
by a certificate authority.

First we will add the delegation private key to the local Docker trust
repository. (By default this is stored in `~/.docker/trust/`). If you are
generating delegation keys with `$ docker trust key generate`, the private key
is automatically added to the local trust store. If you are importing a separate
key, you will need to use the
`$ docker trust key load` command.

```console
$ docker trust key generate jeff
Generating key for jeff...
Enter passphrase for new jeff key with ID 9deed25:
Repeat passphrase for new jeff key with ID 9deed25:
Successfully generated and loaded private key. Corresponding public key available: /home/ubuntu/Documents/mytrustdir/jeff.pub
```

Or if you have an existing key:

```console
$ docker trust key load key.pem --name jeff
Loading key from "key.pem"...
Enter passphrase for new jeff key with ID 8ae710e:
Repeat passphrase for new jeff key with ID 8ae710e:
Successfully imported key from key.pem
```

Next we will need to add the delegation public key to the Notary server;
this is specific to a particular image repository in Notary known as a Global
Unique Name (GUN). If this is the first time you are adding a delegation to that
repository, this command will also initiate the repository, using a local Notary
canonical root key. To understand more about initiating a repository, and the
role of delegations, head to
[delegations for content trust](trust-delegation.md).

```console
$ docker trust signer add --key cert.pem jeff registry.example.com/admin/demo
Adding signer "jeff" to registry.example.com/admin/demo...
Enter passphrase for new repository key with ID 10b5e94:
```

Finally, we will use the delegation private key to sign a particular tag and
push it up to the registry.

```console
$ docker trust sign registry.example.com/admin/demo:1
Signing and pushing trust data for local image registry.example.com/admin/demo:1, may overwrite remote trust data
The push refers to repository [registry.example.com/admin/demo]
7bff100f35cb: Pushed
1: digest: sha256:3d2e482b82608d153a374df3357c0291589a61cc194ec4a9ca2381073a17f58e size: 528
Signing and pushing trust metadata
Enter passphrase for signer key with ID 8ae710e:
Successfully signed registry.example.com/admin/demo:1
```

Alternatively, once the keys have been imported an image can be pushed with the
`$ docker push` command, by exporting the DCT environmental variable.

```console
$ export DOCKER_CONTENT_TRUST=1

$ docker push registry.example.com/admin/demo:1
The push refers to repository [registry.example.com/admin/demo:1]
7bff100f35cb: Pushed
1: digest: sha256:3d2e482b82608d153a374df3357c0291589a61cc194ec4a9ca2381073a17f58e size: 528
Signing and pushing trust metadata
Enter passphrase for signer key with ID 8ae710e:
Successfully signed registry.example.com/admin/demo:1
```

Remote trust data for a tag or a repository can be viewed by the
`$ docker trust inspect` command:

```console
$ docker trust inspect --pretty registry.example.com/admin/demo:1

Signatures for registry.example.com/admin/demo:1

SIGNED TAG          DIGEST                                                             SIGNERS
1                   3d2e482b82608d153a374df3357c0291589a61cc194ec4a9ca2381073a17f58e   jeff

List of signers and their keys for registry.example.com/admin/demo:1

SIGNER              KEYS
jeff                8ae710e3ba82

Administrative keys for registry.example.com/admin/demo:1

  Repository Key:	10b5e94c916a0977471cc08fa56c1a5679819b2005ba6a257aa78ce76d3a1e27
  Root Key:	84ca6e4416416d78c4597e754f38517bea95ab427e5f95871f90d460573071fc
```

Remote Trust data for a tag can be removed by the `$ docker trust revoke` command:

```console
$ docker trust revoke registry.example.com/admin/demo:1
Enter passphrase for signer key with ID 8ae710e:
Successfully deleted signature for registry.example.com/admin/demo:1
```

## Client enforcement with Docker Content Trust

Content trust is disabled by default in the Docker Client. To enable
it, set the `DOCKER_CONTENT_TRUST` environment variable to `1`. This prevents
users from working with tagged images unless they contain a signature.

When DCT is enabled in the Docker client, `docker` CLI commands that operate on
tagged images must either have content signatures or explicit content hashes.
The commands that operate with DCT are:

* `push`
* `build`
* `create`
* `pull`
* `run`

For example, with DCT enabled a `docker pull someimage:latest` only
succeeds if `someimage:latest` is signed. However, an operation with an explicit
content hash always succeeds as long as the hash exists:

```console
$ docker pull registry.example.com/user/image:1
Error: remote trust data does not exist for registry.example.com/user/image: registry.example.com does not have trust data for registry.example.com/user/image

$ docker pull registry.example.com/user/image@sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a
sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1: Pulling from user/image
ff3a5c916c92: Pull complete
a59a168caba3: Pull complete
Digest: sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1
Status: Downloaded newer image for registry.example.com/user/image@sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1
```

## Related information

* [Delegations for content trust](trust-delegation.md)
* [Automation with content trust](trust-automation.md)
* [Manage keys for content trust](trust-key-mng.md)
* [Play in a content trust sandbox](trust-sandbox.md)


---

# Deploy Notary Server with Compose

*Sección: Engine*

The easiest way to deploy Notary Server is by using Docker Compose. To follow the procedure on this page, you must have already [installed Docker Compose](../../../compose/install/index.md).

1. Clone the Notary repository.
   
   ```console
   $ git clone https://github.com/theupdateframework/notary.git
   ```

2. Build and start Notary Server with the sample certificates.

   ```console
   $ docker compose up -d 
   ```

   For more detailed documentation about how to deploy Notary Server, see the [instructions to run a Notary service](https://github.com/theupdateframework/notary/blob/master/docs/running_a_service.md) as well as [the Notary repository](https://github.com/theupdateframework/notary) for more information.

3. Make sure that your Docker or Notary client trusts Notary Server's certificate before you try to interact with the Notary server.

See the instructions for [Docker](/reference/cli/docker/#notary) or
for [Notary](https://github.com/docker/notary#using-notary) depending on which one you are using.

## If you want to use Notary in production

The Compose sample on this page is for local testing and uses sample
certificates. For a production deployment, follow the upstream
[instructions to run a Notary service](https://github.com/theupdateframework/notary/blob/master/docs/running_a_service.md)
and the rest of [the Notary repository](https://github.com/theupdateframework/notary).


---

# Automation with content trust

*Sección: Engine*

It is very common for Docker Content Trust to be built into existing automation
systems. To allow tools to wrap Docker and push trusted content, there are 
environment variables that can be passed through to the client. 

This guide follows the steps as described in
[Signing images with Docker Content Trust](../../../reference/api/ai-governance/index.md#signing-images-with-docker-content-trust). Make sure you understand and follow the prerequisites.

When working directly with the Notary client, it uses its [own set of environment variables](https://github.com/theupdateframework/notary/blob/master/docs/reference/client-config.md#environment-variables-optional).

## Add a delegation private key

To automate importing a delegation private key to the local Docker trust store, we 
need to pass a passphrase for the new key. This passphrase will be required
every time that delegation signs a tag.

```console
$ export DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE="mypassphrase123"

$ docker trust key load delegation.key --name jeff
Loading key from "delegation.key"...
Successfully imported key from delegation.key
```

## Add a delegation public key

If you initialize a repository at the same time as adding a delegation
public key, then you will need to use the local Notary Canonical Root Key's 
passphrase to create the repositories trust data. If the repository has already 
been initiated then you only need the repositories passphrase. 

```console
# Export the Local Root Key Passphrase if required.
$ export DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE="rootpassphrase123"

# Export the Repository Passphrase
$ export DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE="repopassphrase123"

# Initialize Repo and Push Delegation
$ docker trust signer add --key delegation.crt jeff registry.example.com/admin/demo
Adding signer "jeff" to registry.example.com/admin/demo...
Initializing signed repository for registry.example.com/admin/demo...
Successfully initialized "registry.example.com/admin/demo"
Successfully added signer: registry.example.com/admin/demo
```

## Sign an image

Finally when signing an image, we will need to export the passphrase of the 
signing key. This was created when the key was loaded into the local Docker 
trust store with `$ docker trust key load`.

```console
$ export DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE="mypassphrase123"

$ docker trust sign registry.example.com/admin/demo:1
Signing and pushing trust data for local image registry.example.com/admin/demo:1, may overwrite remote trust data
The push refers to repository [registry.example.com/admin/demo]
428c97da766c: Layer already exists
2: digest: sha256:1a6fd470b9ce10849be79e99529a88371dff60c60aab424c077007f6979b4812 size: 524
Signing and pushing trust metadata
Successfully signed registry.example.com/admin/demo:1
```

## Build with content trust

You can also build with content trust. Before running the `docker build` command, 
you should set the environment variable `DOCKER_CONTENT_TRUST` either manually or 
in a scripted fashion. Consider the simple Dockerfile below.

```dockerfile
# syntax=docker/dockerfile:1
FROM docker/trusttest:latest
RUN echo
```

The `FROM` tag is pulling a signed image. You cannot build an image that has a
`FROM` that is not either present locally or signed. Given that content trust
data exists for the tag `latest`, the following build should succeed:

```console
$  docker build -t docker/trusttest:testing .
Using default tag: latest
latest: Pulling from docker/trusttest

b3dbab3810fc: Pull complete
a9539b34a6ab: Pull complete
Digest: sha256:d149ab53f871
```

If content trust is enabled, building from a Dockerfile that relies on tag 
without trust data, causes the build command to fail:

```console
$  docker build -t docker/trusttest:testing .
unable to process Dockerfile: No trust data for notrust
```

## Related information

* [Delegations for content trust](trust-delegation.md)
* [Content trust in Docker](../../../reference/api/ai-governance/index.md)
* [Manage keys for content trust](trust-key-mng.md)
* [Play in a content trust sandbox](trust-sandbox.md)


---

# Delegations for content trust

*Sección: Engine*

Delegations in Docker Content Trust (DCT) allow you to control who can and cannot sign
an image tag. A delegation will have a pair of private and public delegation keys. A delegation 
could contain multiple pairs of keys and contributors in order to a) allow multiple users 
to be part of a delegation, and b) to support key rotation.  

The most important delegation within Docker Content Trust is `targets/releases`.
This is seen as the canonical source of a trusted image tag, and without a 
contributor's key being under this delegation, they will be unable to sign a tag.

Fortunately when using the `$ docker trust` commands, we will automatically 
initialize a repository, manage the repository keys, and add a collaborator's key to the 
`targets/releases` delegation via `docker trust signer add`. 

## Configuring the Docker client

By default, the `$ docker trust` commands expect the notary server URL to be the
same as the registry URL specified in the image tag (following a similar logic to
`$ docker push`). When using Docker Hub or DTR, the notary
server URL is the same as the registry URL. However, for self-hosted
environments or 3rd party registries, you will need to specify an alternative
URL of the notary server. This is done with:

```console
$ export DOCKER_CONTENT_TRUST_SERVER=https://<URL>:<PORT>
```

If you do not export this variable in self-hosted environments, you may see 
errors such as: 

```console
$ docker trust signer add --key cert.pem jeff registry.example.com/admin/demo
Adding signer "jeff" to registry.example.com/admin/demo...
<...>
Error: trust data missing for remote repository registry.example.com/admin/demo or remote repository not found: timestamp key trust data unavailable.  Has a notary repository been initialized?

$ docker trust inspect registry.example.com/admin/demo --pretty
WARN[0000] Error while downloading remote metadata, using cached timestamp - this might not be the latest version available remotely
<...>
```

If you have enabled authentication for your notary server, or are using DTR, you will need to log in 
before you can push data to the notary server. 

```console
$ docker login registry.example.com/user/repo
Username: admin
Password:

Login Succeeded

$ docker trust signer add --key cert.pem jeff registry.example.com/user/repo
Adding signer "jeff" to registry.example.com/user/repo...
Initializing signed repository for registry.example.com/user/repo...
Successfully initialized "registry.example.com/user/repo"
Successfully added signer: jeff to registry.example.com/user/repo
```

If you do not log in, you will see:

```console
$ docker trust signer add --key cert.pem jeff registry.example.com/user/repo
Adding signer "jeff" to registry.example.com/user/repo...
Initializing signed repository for registry.example.com/user/repo...
you are not authorized to perform this operation: server returned 401.

Failed to add signer to: registry.example.com/user/repo
```

## Configuring the Notary client

Some of the more advanced features of DCT require the Notary CLI. To install and 
configure the Notary CLI:

1. Download the [client](https://github.com/theupdateframework/notary/releases) and ensure that it is available on your path.

2. Create a configuration file at `~/.notary/config.json` with the following content:

```json
{
  "trust_dir" : "~/.docker/trust",
  "remote_server": {
    "url": "https://registry.example.com",
    "root_ca": "../.docker/ca.pem"
  }
}
```

The newly created configuration file contains information about the location of your local Docker trust data and the notary server URL.

For more detailed information about how to use notary outside of the
Docker Content Trust use cases, refer to the [Notary CLI documentation](https://github.com/theupdateframework/notary/blob/master/docs/command_reference.md) 

## Creating delegation keys

A prerequisite to adding your first contributor is a pair of delegation keys. 
These keys can either be generated locally using `$ docker trust`, generated by 
a certificate authority.

### Using Docker Trust to generate keys

Docker trust has a built-in generator for a delegation key pair, 
`$ docker trust generate <name>`. Running this command will automatically load 
the delegation private key in to the local Docker trust store. 

```console
$ docker trust key generate jeff

Generating key for jeff...
Enter passphrase for new jeff key with ID 9deed25: 
Repeat passphrase for new jeff key with ID 9deed25: 
Successfully generated and loaded private key. Corresponding public key available: /home/ubuntu/Documents/mytrustdir/jeff.pub
```

### Manually generating keys

If you need to manually generate a private key (either RSA or ECDSA) and an X.509
certificate containing the public key, you can use local tools like openssl or 
cfssl along with a local or company-wide Certificate Authority. 

Here is an example of how to generate a 2048-bit RSA portion key (all RSA keys
must be at least 2048 bits):

```console
$ openssl genrsa -out delegation.key 2048

Generating RSA private key, 2048 bit long modulus
....................................................+++
............+++
e is 65537 (0x10001)
```

They should keep `delegation.key` private because it is used to sign tags.

Then they need to generate an x509 certificate containing the public key, which is
what you need from them. Here is the command to generate a CSR (certificate
signing request):

```console
$ openssl req -new -sha256 -key delegation.key -out delegation.csr
```

Then they can send it to whichever CA you trust to sign certificates, or they
can self-sign the certificate (in this example, creating a certificate that is
valid for 1 year):

```console
$ openssl x509 -req -sha256 -days 365 -in delegation.csr -signkey delegation.key -out delegation.crt
```

Then they need to give you `delegation.crt`, whether it is self-signed or signed
by a CA.

Finally you will need to add the private key into your local Docker trust store.

```console
$ docker trust key load delegation.key --name jeff

Loading key from "delegation.key"...
Enter passphrase for new jeff key with ID 8ae710e: 
Repeat passphrase for new jeff key with ID 8ae710e: 
Successfully imported key from delegation.key
```

### Viewing local delegation keys 

To list the keys that have been imported in to the local Docker trust store we 
can use the Notary CLI.

```console
$ notary key list

ROLE       GUN                          KEY ID                                                              LOCATION
----       ---                          ------                                                              --------
root                                    f6c6a4b00fefd8751f86194c7d87a3bede444540eb3378c4a11ce10852ab1f96    /home/ubuntu/.docker/trust/private
jeff                                    9deed251daa1aa6f9d5f9b752847647cf8d705da0763aa5467650d0987ed5306    /home/ubuntu/.docker/trust/private
```

## Managing delegations in a Notary Server

When the first delegation is added to the Notary Server using `$ docker trust`,
we automatically initiate trust data for the repository. This includes creating 
the notary target and snapshots keys, and rotating the snapshot key to be 
managed by the notary server. More information on these keys can be found in
[Manage keys for content trust](trust-key-mng.md).

When initiating a repository, you will need the key and the passphrase of a local
Notary Canonical Root Key. If you have not initiated a repository before, and 
therefore don't have a Notary root key, `$ docker trust` will create one for you.

> [!IMPORTANT]
>
> Be sure to protect and back up your [Notary Canonical Root Key](trust-key-mng.md).

### Initiating the repository

To upload the first key to a delegation, at the same time initiating a 
repository, you can use the `$ docker trust signer add` command. This will add 
the contributor's public key to the `targets/releases` delegation, and create a 
second `targets/<name>` delegation. 

For DCT the name of the second delegation, in the below example
`jeff`, is there to help you keep track of the owner of the keys. In more 
advanced use cases of Notary additional delegations are used for hierarchy. 

```console
$ docker trust signer add --key cert.pem jeff registry.example.com/admin/demo

Adding signer "jeff" to registry.example.com/admin/demo...
Initializing signed repository for registry.example.com/admin/demo...
Enter passphrase for root key with ID f6c6a4b: 
Enter passphrase for new repository key with ID b0014f8: 
Repeat passphrase for new repository key with ID b0014f8: 
Successfully initialized "registry.example.com/admin/demo"
Successfully added signer: jeff to registry.example.com/admin/demo
```

You can see which keys have been pushed to the Notary server for each repository
with the `$ docker trust inspect` command. 

```console
$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures for registry.example.com/admin/demo


List of signers and their keys for registry.example.com/admin/demo

SIGNER              KEYS
jeff                1091060d7bfd

Administrative keys for registry.example.com/admin/demo

  Repository Key:	b0014f8e4863df2d028095b74efcb05d872c3591de0af06652944e310d96598d
  Root Key:	64d147e59e44870311dd2d80b9f7840039115ef3dfa5008127d769a5f657a5d7
```

You could also use the Notary CLI to list delegations and keys. Here you can 
clearly see the keys were attached to `targets/releases` and `targets/jeff`.

```console
$ notary delegation list registry.example.com/admin/demo

ROLE                PATHS             KEY IDS                                                             THRESHOLD
----                -----             -------                                                             ---------
targets/jeff        "" <all paths>    1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    1
                                          
targets/releases    "" <all paths>    1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    1 
```

### Adding additional signers

Docker Trust allows you to configure multiple delegations per repository, 
allowing you to manage the lifecycle of delegations. When adding additional 
delegations with `$ docker trust` the collaborators key is once again added to 
the `targets/release` role.

> Note you will need the passphrase for the repository key; this would have been
> configured when you first initiated the repository.

```console
$ docker trust signer add --key ben.pub ben registry.example.com/admin/demo

Adding signer "ben" to registry.example.com/admin/demo...
Enter passphrase for repository key with ID b0014f8: 
Successfully added signer: ben to registry.example.com/admin/demo
```

Check to prove that there are now 2 delegations (Signer).

```console
$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures for registry.example.com/admin/demo

List of signers and their keys for registry.example.com/admin/demo

SIGNER              KEYS
ben                 afa404703b25
jeff                1091060d7bfd

Administrative keys for registry.example.com/admin/demo

  Repository Key:	b0014f8e4863df2d028095b74efcb05d872c3591de0af06652944e310d96598d
  Root Key:	64d147e59e44870311dd2d80b9f7840039115ef3dfa5008127d769a5f657a5d7
```

### Adding keys to an existing delegation

To support things like key rotation and expiring / retiring keys you can publish
multiple contributor keys per delegation. The only prerequisite here is to make
sure you use the same the delegation name, in this case `jeff`. Docker trust 
will automatically handle adding this new key to `targets/releases`. 

> [!NOTE]
>
> You will need the passphrase for the repository key; this would have been
> configured when you first initiated the repository.

```console
$ docker trust signer add --key cert2.pem jeff registry.example.com/admin/demo

Adding signer "jeff" to registry.example.com/admin/demo...
Enter passphrase for repository key with ID b0014f8: 
Successfully added signer: jeff to registry.example.com/admin/demo
```

Check to prove that the delegation (Signer) now contains multiple Key IDs. 

```console
$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures for registry.example.com/admin/demo


List of signers and their keys for registry.example.com/admin/demo

SIGNER              KEYS
jeff                1091060d7bfd, 5570b88df073

Administrative keys for registry.example.com/admin/demo

  Repository Key:	b0014f8e4863df2d028095b74efcb05d872c3591de0af06652944e310d96598d
  Root Key:	64d147e59e44870311dd2d80b9f7840039115ef3dfa5008127d769a5f657a5d7
```

### Removing a delegation

If you need to remove a delegation, including the contributor keys that are 
attached to the `targets/releases` role, you can use the 
`$ docker trust signer remove` command.

> [!NOTE]
>
> Tags that were signed by the removed delegation will need to be resigned 
> by an active delegation

```console
$ docker trust signer remove ben registry.example.com/admin/demo
Removing signer "ben" from registry.example.com/admin/demo...
Enter passphrase for repository key with ID b0014f8: 
Successfully removed ben from registry.example.com/admin/demo
```

#### Troubleshooting

1) If you see an error that there are no usable keys in `targets/releases`, you 
   will need to add additional delegations using `docker trust signer add` before 
   resigning images.

   ```text
   WARN[0000] role targets/releases has fewer keys than its threshold of 1; it will not be usable until keys are added to it
   ```

2) If you have added additional delegations already and are seeing an error 
   message that there are no valid signatures in `targets/releases`, you will need
   to resign the `targets/releases` delegation file with the Notary CLI.

   ```text
   WARN[0000] Error getting targets/releases: valid signatures did not meet threshold for targets/releases 
   ```

   Resigning the delegation file is done with the `$ notary witness` command

   ```console
   $ notary witness registry.example.com/admin/demo targets/releases --publish
   ```

   For more information on the `notary witness` command, refer to the
   [Notary client advanced usage guide](https://github.com/theupdateframework/notary/blob/master/docs/advanced_usage.md#recovering-a-delegation)

### Removing a contributor's key from a delegation

As part of rotating keys for a delegation, you may want to remove an individual 
key but retain the delegation. This can be done with the Notary CLI.

Remember you will have to remove the key from both the `targets/releases` role 
and the role specific to that signer `targets/<name>`.

1) We will need to grab the Key ID from the Notary Server

   ```console
   $ notary delegation list registry.example.com/admin/demo

   ROLE                PATHS             KEY IDS                                                             THRESHOLD
   ----                -----             -------                                                             ---------
   targets/jeff        "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1
                                         1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    
   targets/releases    "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1
                                         1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    
   ```

2) Remove from the `targets/releases` delegation

   ```console
   $ notary delegation remove registry.example.com/admin/demo targets/releases 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 --publish
   
   Auto-publishing changes to registry.example.com/admin/demo
   Enter username: admin
   Enter password: 
   Enter passphrase for targets key with ID b0014f8: 
   Successfully published changes for repository registry.example.com/admin/demo
   ```

3) Remove from the `targets/<name>` delegation

   ```console
   $ notary delegation remove registry.example.com/admin/demo targets/jeff 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 --publish
   
   Removal of delegation role targets/jeff with keys [5570b88df0736c468493247a07e235e35cf3641270c944d0e9e8899922fc6f99], to repository "registry.example.com/admin/demo" staged for next publish.
   
   Auto-publishing changes to registry.example.com/admin/demo
   Enter username: admin    
   Enter password: 
   Enter passphrase for targets key with ID b0014f8: 
   Successfully published changes for repository registry.example.com/admin/demo
   ```

4) Check the remaining delegation list 

   ```console
   $ notary delegation list registry.example.com/admin/demo
   
   ROLE                PATHS             KEY IDS                                                             THRESHOLD
   ----                -----             -------                                                             ---------
   targets/jeff        "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1    
   targets/releases    "" <all paths>    8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    1    
   ```

### Removing a local delegation private key

As part of rotating delegation keys, you may need to remove a local delegation
key from the local Docker trust store. This is done with the Notary CLI, using
the `$ notary key remove` command.

1) We will need to get the Key ID from the local Docker Trust store

   ```console
   $ notary key list
   
   ROLE       GUN                          KEY ID                                                              LOCATION
   ----       ---                          ------                                                              --------
   root                                    f6c6a4b00fefd8751f86194c7d87a3bede444540eb3378c4a11ce10852ab1f96    /home/ubuntu/.docker/trust/private
   admin                                   8fb597cbaf196f0781628b2f52bff6b3912e4e8075720378fda60d17232bbcf9    /home/ubuntu/.docker/trust/private
   jeff                                    1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1    /home/ubuntu/.docker/trust/private
   targets    ...example.com/admin/demo    c819f2eda8fba2810ec6a7f95f051c90276c87fddfc3039058856fad061c009d    /home/ubuntu/.docker/trust/private
   ```

2) Remove the key from the local Docker Trust store

   ```console
   $ notary key remove 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1
   
   Are you sure you want to remove 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 (role jeff) from /home/ubuntu/.docker/trust/private?  (yes/no)  y
   
   Deleted 1091060d7bfd938dfa5be703fa057974f9322a4faef6f580334f3d6df44c02d1 (role jeff) from /home/ubuntu/.docker/trust/private.
   ```

## Removing all trust data from a repository

You can remove all trust data from a repository, including repository, target, 
snapshot and all delegations keys using the Notary CLI.

This is often required by a container registry before a particular repository
can be deleted. 

```console
$ notary delete registry.example.com/admin/demo --remote

Deleting trust data for repository registry.example.com/admin/demo
Enter username: admin
Enter password: 
Successfully deleted local and remote trust data for repository registry.example.com/admin/demo

$ docker trust inspect --pretty registry.example.com/admin/demo

No signatures or cannot access registry.example.com/admin/demo
```

## Related information

* [Content trust in Docker](../../../reference/api/ai-governance/index.md)
* [Manage keys for content trust](trust-key-mng.md)
* [Automation with content trust](trust-automation.md)
* [Play in a content trust sandbox](trust-sandbox.md)


---

# Manage keys for content trust

*Sección: Engine*

Trust for an image tag is managed through the use of keys. Docker's content
trust makes use of five different types of keys:

| Key        | Description |                                                                                                                                                                                                                         
|:-----------|:----------- |
| root key   | Root of content trust for an image tag. When content trust is enabled, you create the root key once. Also known as the offline key, because it should be kept offline. |
| targets    | This key allows you to sign image tags, to manage delegations including delegated keys or permitted delegation paths. Also known as the repository key, since this key determines what tags can be signed into an image repository. |
| snapshot   | This key signs the current collection of image tags, preventing mix and match attacks. |                                                                                                                                         
| timestamp  | This key allows Docker image repositories to have freshness security guarantees without requiring periodic content refreshes on the client's side. |
| delegation | Delegation keys are optional tagging keys and allow you to delegate signing image tags to other publishers without having to share your targets key. |

When doing a `docker push` with Content Trust enabled for the first time, the
root, targets, snapshot, and timestamp keys are generated automatically for
the image repository:

- The root and targets key are generated and stored locally client-side.

- The timestamp and snapshot keys are safely generated and stored in a signing server
	that is deployed alongside the Docker registry. These keys are generated in a backend
	service that isn't directly exposed to the internet and are encrypted at rest. Use the Notary CLI to [manage your snapshot key locally](https://github.com/theupdateframework/notary/blob/master/docs/advanced_usage.md#rotate-keys).

Delegation keys are optional, and not generated as part of the normal `docker`
workflow. They need to be
[manually generated and added to the repository](trust-delegation.md#creating-delegation-keys).

## Choose a passphrase

The passphrases you chose for both the root key and your repository key should
be randomly generated and stored in a password manager. Having the repository key
allows users to sign image tags on a repository. Passphrases are used to encrypt
your keys at rest and ensure that a lost laptop or an unintended backup doesn't
put the private key material at risk.

## Back up your keys

All the Docker trust keys are stored encrypted using the passphrase you provide
on creation. Even so, you should still take care of the location where you back them up.
Good practice is to create two encrypted USB keys.

> [!WARNING]
>
> It is very important that you back up your keys to a safe, secure location.
The loss of the repository key is recoverable, but the loss of the root key is not.

The Docker client stores the keys in the `~/.docker/trust/private` directory.
Before backing them up, you should `tar` them into an archive:

```console
$ umask 077; tar -zcvf private_keys_backup.tar.gz ~/.docker/trust/private; umask 022
```

## Hardware storage and signing

Docker Content Trust can store and sign with root keys from a Yubikey 4. The
Yubikey is prioritized over keys stored in the filesystem. When you initialize a
new repository with content trust, Docker Engine looks for a root key locally. If a
key is not found and the Yubikey 4 exists, Docker Engine creates a root key in the
Yubikey 4. Consult the [Notary documentation](https://github.com/theupdateframework/notary/blob/master/docs/advanced_usage.md#use-a-yubikey)
for more details.

Prior to Docker Engine 1.11, this feature was only in the experimental branch.

## Key loss

> [!WARNING]
>
> If a publisher loses keys it means losing the ability to sign images for the repositories in
question. If you lose a key, send an email to [Docker Hub Support](mailto:hub-support@docker.com).
As a reminder, the loss of a root key is not recoverable.

This loss also requires manual intervention from every consumer that used a signed
tag from this repository prior to the loss.  
Image consumers get the following error for content previously downloaded from the affected repo(s):

```console
Warning: potential malicious behavior - trust data has insufficient signatures for remote repository docker.io/my/image: valid signatures did not meet threshold
```

To correct this, they need to download a new image tag that is signed with
the new key.

## Related information

* [Content trust in Docker](../../../reference/api/ai-governance/index.md)
* [Automation with content trust](trust-automation.md)
* [Delegations for content trust](trust-delegation.md)
* [Play in a content trust sandbox](trust-sandbox.md)


---

# Play in a content trust sandbox

*Sección: Engine*

This page explains how to set up and use a sandbox for experimenting with trust.
The sandbox allows you to configure and try trust operations locally without
impacting your production images.

Before working through this sandbox, you should have read through the
[trust overview](../../../reference/api/ai-governance/index.md).

## Prerequisites

These instructions assume you are running in Linux or macOS. You can run
this sandbox on a local machine or on a virtual machine. You need to
have privileges to run docker commands on your local machine or in the VM.

This sandbox requires a current Docker Engine and Docker Compose install. To
install Docker Engine, choose from the
[list of supported platforms](../../install/index.md). To install Docker
Compose, see the
[Compose install instructions](../../../compose/install/index.md).

## What is in the sandbox?

If you are just using trust out-of-the-box you only need your Docker Engine
client and access to the Docker Hub. The sandbox mimics a
production trust environment, and sets up these additional components.

| Container       | Description                                                                                                                                 |
|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| trustsandbox    | A container with the latest version of Docker Engine and with some preconfigured certificates. This is your sandbox where you can use the `docker` client to test trust operations. |
| Registry server | A local registry service.                                                                                                                 |
| Notary server   | The service that does all the heavy-lifting of managing trust                                                                               |

This means you run your own content trust (Notary) server and registry.
If you work exclusively with the Docker Hub, you would not need these components.
They are built into the Docker Hub for you. For the sandbox, however, you build
your own entire, mock production environment.

Within the `trustsandbox` container, you interact with your local registry rather
than the Docker Hub. This means your everyday image repositories are not used.
They are protected while you play.

When you play in the sandbox, you also create root and repository keys. The
sandbox is configured to store all the keys and files inside the `trustsandbox`
container. Since the keys you create in the sandbox are for play only,
destroying the container destroys them as well.

By using a `docker-in-docker` image for the `trustsandbox` container, you also
don't pollute your real Docker daemon cache with any images you push and pull.
The images are stored in an anonymous volume attached to this container,
and can be destroyed after you destroy the container.

## Build the sandbox

In this section, you use Docker Compose to specify how to set up and link together
the `trustsandbox` container, the Notary server, and the Registry server.


1. Create a new `trustsandbox` directory and change into it.

   ```console
   $ mkdir trustsandbox
   $ cd trustsandbox
   ```

2. Create a file called `compose.yaml` with your favorite editor.  For example, using vim:

   ```console
   $ touch compose.yaml
   $ vim compose.yaml
   ```

3. Add the following to the new file.

   ```yaml
   version: "2"
   services:
     notaryserver:
       image: dockersecurity/notary_autobuilds:server-v0.5.1
       volumes:
         - notarycerts:/var/lib/notary/fixtures
       networks:
         - sandbox
       environment:
         - NOTARY_SERVER_STORAGE_TYPE=memory
         - NOTARY_SERVER_TRUST_SERVICE_TYPE=local
     sandboxregistry:
       image: registry:3
       networks:
         - sandbox
       container_name: sandboxregistry
     trustsandbox:
       image: docker:dind
       networks:
         - sandbox
       volumes:
         - notarycerts:/notarycerts
       privileged: true
       container_name: trustsandbox
       entrypoint: ""
       command: |-
           sh -c '
               cp /notarycerts/root-ca.crt /usr/local/share/ca-certificates/root-ca.crt &&
               update-ca-certificates &&
               dockerd-entrypoint.sh --insecure-registry sandboxregistry:5000'
   volumes:
     notarycerts:
       external: false
   networks:
     sandbox:
       external: false
   ```
4. Save and close the file.

5. Run the containers on your local system.

   ```console
   $ docker compose up -d
   ```

   The first time you run this, the `docker-in-docker`, Notary server, and registry
   images are downloaded from Docker Hub.


## Play in the sandbox

Now that everything is setup, you can go into your `trustsandbox` container and
start testing Docker content trust. From your host machine, obtain a shell
in the `trustsandbox` container.

```console
$ docker container exec -it trustsandbox sh
/ #
```

### Test some trust operations

Now, pull some images from within the `trustsandbox` container.

1. Download a `docker` image to test with.

   ```console
   / # docker pull docker/trusttest
   docker pull docker/trusttest
   Using default tag: latest
   latest: Pulling from docker/trusttest   
   b3dbab3810fc: Pull complete
   a9539b34a6ab: Pull complete
   Digest: sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a
   Status: Downloaded newer image for docker/trusttest:latest
   ```

2. Tag it to be pushed to your sandbox registry:

   ```console
   / # docker tag docker/trusttest sandboxregistry:5000/test/trusttest:latest
   ```

3. Enable content trust.

   ```console
   / # export DOCKER_CONTENT_TRUST=1
   ```

4. Identify the trust server.

   ```console
   / # export DOCKER_CONTENT_TRUST_SERVER=https://notaryserver:4443
   ```

    This step is only necessary because the sandbox is using its own server.
    Normally, if you are using the Docker Public Hub this step isn't necessary.

5. Pull the test image.

   ```console
   / # docker pull sandboxregistry:5000/test/trusttest
   Using default tag: latest
   Error: remote trust data does not exist for sandboxregistry:5000/test/trusttest: notaryserver:4443 does not have trust data for      sandboxregistry:5000/test/trusttest
   ```
      You see an error, because this content doesn't exist on the `notaryserver` yet.

6. Push and sign the trusted image.
   ```console
   / # docker push sandboxregistry:5000/test/trusttest:latest
   The push refers to a repository [sandboxregistry:5000/test/trusttest]
   5f70bf18a086: Pushed
   c22f7bc058a9: Pushed
   latest: digest: sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926 size: 734
   Signing and pushing trust metadata
   You are about to create a new root signing key passphrase. This passphrase
   will be used to protect the most sensitive key in your signing system. Please
   choose a long, complex passphrase and be careful to keep the password and the
   key file itself secure and backed up. It is highly recommended that you use a
   password manager to generate the passphrase and keep it safe. There will be no
   way to recover this key. You can find the key in your config directory.
   Enter passphrase for new root key with ID 27ec255:
   Repeat passphrase for new root key with ID 27ec255:
   Enter passphrase for new repository key with ID 58233f9 (sandboxregistry:5000/test/trusttest):
   Repeat passphrase for new repository key with ID 58233f9 (sandboxregistry:5000/test/trusttest):
   Finished initializing "sandboxregistry:5000/test/trusttest"
   Successfully signed "sandboxregistry:5000/test/trusttest":latest
   ```

    Because you are pushing this repository for the first time, Docker creates
    new root and repository keys and asks you for passphrases with which to
    encrypt them. If you push again after this, it only asks you for repository
    passphrase so it can decrypt the key and sign again.

7. Try pulling the image you just pushed:

   ```console
   / # docker pull sandboxregistry:5000/test/trusttest
   Using default tag: latest
   Pull (1 of 1): sandboxregistry:5000/test/trusttest:latest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
   sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926: Pulling from test/trusttest
   Digest: sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
   Status: Downloaded newer image for sandboxregistry:5000/test/trusttest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
   Tagging sandboxregistry:5000/test/trusttest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926 as sandboxregistry:5000   test/trusttest:latest
   ```


### Test with malicious images

What happens when data is corrupted and you try to pull it when trust is
enabled? In this section, you go into the `sandboxregistry` and tamper with some
data. Then, you try and pull it.

1. Leave the `trustsandbox` shell and container running.

2. Open a new interactive terminal from your host, and obtain a shell into the
   `sandboxregistry` container.

   ```console
   $ docker container exec -it sandboxregistry bash
   root@65084fc6f047:/#
   ```

3. List the layers for the `test/trusttest` image you pushed:

    ```console
    root@65084fc6f047:/# ls -l /var/lib/registry/docker/registry/v2/repositories/test/trusttest/_layers/sha256
    total 12
    drwxr-xr-x 2 root root 4096 Jun 10 17:26 a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
    drwxr-xr-x 2 root root 4096 Jun 10 17:26 aac0c133338db2b18ff054943cee3267fe50c75cdee969aed88b1992539ed042
    drwxr-xr-x 2 root root 4096 Jun 10 17:26 cc7629d1331a7362b5e5126beb5bf15ca0bf67eb41eab994c719a45de53255cd
    ```

4. Change into the registry storage for one of those layers (this is in a different directory):

   ```console
   root@65084fc6f047:/# cd /var/lib/registry/docker/registry/v2/blobs/sha256/aa/aac0c133338db2b18ff054943cee3267fe50c75cdee969aed88b1992539ed042
   ```

5. Add malicious data to one of the `trusttest` layers:

   ```console
   root@65084fc6f047:/# echo "Malicious data" > data
   ```

6. Go back to your `trustsandbox` terminal.

7. List the `trusttest` image.

   ```console
   / # docker image ls | grep trusttest
   REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
   docker/trusttest                      latest              cc7629d1331a        11 months ago       5.025 MB
   sandboxregistry:5000/test/trusttest   latest              cc7629d1331a        11 months ago       5.025 MB
   sandboxregistry:5000/test/trusttest   <none>              cc7629d1331a        11 months ago       5.025 MB
   ```

8. Remove the `trusttest:latest` image from your local cache.

   ```console
   / # docker image rm -f cc7629d1331a
   Untagged: docker/trusttest:latest
   Untagged: sandboxregistry:5000/test/trusttest:latest
   Untagged: sandboxregistry:5000/test/trusttest@sha256:ebf59c538accdf160ef435f1a19938ab8c0d6bd96aef8d4ddd1b379edf15a926
   Deleted: sha256:cc7629d1331a7362b5e5126beb5bf15ca0bf67eb41eab994c719a45de53255cd
   Deleted: sha256:2a1f6535dc6816ffadcdbe20590045e6cbf048d63fd4cc753a684c9bc01abeea
   Deleted: sha256:c22f7bc058a9a8ffeb32989b5d3338787e73855bf224af7aa162823da015d44c
   ```

   Docker does not re-download images that it already has cached, but you want
   Docker to attempt to download the tampered image from the registry and reject
   it because it is invalid.

9. Pull the image again. This downloads the image from the registry, because you don't have it cached.

   ```console
   / # docker pull sandboxregistry:5000/test/trusttest
   Using default tag: latest
   Pull (1 of 1): sandboxregistry:5000/test/trusttest:latest@sha256:35d5bc26fd358da8320c137784fe590d8fcf9417263ef261653e8e1c7f15672e
   sha256:35d5bc26fd358da8320c137784fe590d8fcf9417263ef261653e8e1c7f15672e: Pulling from test/trusttest

   aac0c133338d: Retrying in 5 seconds
   a3ed95caeb02: Download complete
   error pulling image configuration: unexpected EOF
   ```

   The pull did not complete because the trust system couldn't verify the
   image.

## More play in the sandbox

Now, you have a full Docker content trust sandbox on your local system,
feel free to play with it and see how it behaves. If you find any security
issues with Docker, feel free to send us an email at <security@docker.com>.


## Clean up your sandbox

When you are done, and want to clean up all the services you've started and any
anonymous volumes that have been created, just run the following command in the
directory where you've created your Docker Compose file:

   ```console
   $ docker compose down -v
   ```


---

# Isolate containers with a user namespace

*Sección: Engine*

Linux namespaces provide isolation for running processes, limiting their access
to system resources without the running process being aware of the limitations.
For more information on Linux namespaces, see
[Linux namespaces](https://www.linux.com/news/understanding-and-securing-linux-namespaces).

The best way to prevent privilege-escalation attacks from within a container is
to configure your container's applications to run as unprivileged users. For
containers whose processes must run as the `root` user within the container, you
can re-map this user to a less-privileged user on the Docker host. The mapped
user is assigned a range of UIDs which function within the namespace as normal
UIDs from 0 to 65536, but have no privileges on the host machine itself.

> [!NOTE]
>
> With `userns-remap`, the Docker daemon still runs as root. To run both the
> daemon and containers without root privileges, see [Rootless mode](rootless/index.md)
> instead.

## About remapping and subordinate user and group IDs

The remapping itself is handled by two files: `/etc/subuid` and `/etc/subgid`.
Each file works the same, but one is concerned with the user ID range, and the
other with the group ID range. Consider the following entry in `/etc/subuid`:

```text
testuser:231072:65536
```

This means that `testuser` is assigned a subordinate user ID range of `231072`
and the next 65536 integers in sequence. UID `231072` is mapped within the
namespace (within the container, in this case) as UID `0` (`root`). UID `231073`
is mapped as UID `1`, and so forth. If a process attempts to escalate privilege
outside of the namespace, the process is running as an unprivileged high-number
UID on the host, which does not even map to a real user. This means the process
has no privileges on the host system at all.

> [!NOTE]
>
> It is possible to assign multiple subordinate ranges for a given user or group
> by adding multiple non-overlapping mappings for the same user or group in the
> `/etc/subuid` or `/etc/subgid` file. In this case, Docker uses only the first
> five mappings, in accordance with the kernel's limitation of only five entries
> in `/proc/self/uid_map` and `/proc/self/gid_map`.

When you configure Docker to use the `userns-remap` feature, you can optionally
specify an existing user and/or group, or you can specify `default`. If you
specify `default`, a user and group `dockremap` is created and used for this
purpose.

> [!WARNING]
>
> Some distributions do not automatically add the new group to the
> `/etc/subuid` and `/etc/subgid` files. If that's the case, you may have
> to manually edit these files and assign non-overlapping ranges. This step is
> covered in [Prerequisites](#prerequisites).

It is very important that the ranges do not overlap, so that a process cannot gain
access in a different namespace. On most Linux distributions, system utilities
manage the ranges for you when you add or remove users.

This re-mapping is transparent to the container, but introduces some
configuration complexity in situations where the container needs access to
resources on the Docker host, such as bind mounts into areas of the filesystem
that the system user cannot write to. From a security standpoint, it is best to
avoid these situations.

## Prerequisites

1.  The subordinate UID and GID ranges must be associated with an existing user,
    even though the association is an implementation detail. The user owns
    the namespaced storage directories under `/var/lib/docker/`. If you don't
    want to use an existing user, Docker can create one for you and use that. If
    you want to use an existing username or user ID, it must already exist.
    Typically, this means that the relevant entries need to be in
    `/etc/passwd` and `/etc/group`, but if you are using a different
    authentication back-end, this requirement may translate differently.

    To verify this, use the `id` command:

    ```console
    $ id testuser

    uid=1001(testuser) gid=1001(testuser) groups=1001(testuser)
    ```

2.  The way the namespace remapping is handled on the host is using two files,
    `/etc/subuid` and `/etc/subgid`. These files are typically managed
    automatically when you add or remove users or groups, but on some
    distributions, you may need to manage these files manually.

    Each file contains three fields: the username or ID of the user, followed by
    a beginning UID or GID (which is treated as UID or GID 0 within the namespace)
    and a maximum number of UIDs or GIDs available to the user. For instance,
    given the following entry:

    ```text
    testuser:231072:65536
    ```

    This means that user-namespaced processes started by `testuser` are
    owned by host UID `231072` (which looks like UID `0` inside the
    namespace) through 296607 (231072 + 65536 - 1). These ranges should not overlap,
    to ensure that namespaced processes cannot access each other's namespaces.

    After adding your user, check `/etc/subuid` and `/etc/subgid` to see if your
    user has an entry in each. If not, you need to add it, being careful to
    avoid overlap.

    If you want to use the `dockremap` user automatically created by Docker,
    check for the `dockremap` entry in these files after
    configuring and restarting Docker.

3.  If there are any locations on the Docker host where the unprivileged
    user needs to write, adjust the permissions of those locations
    accordingly. This is also true if you want to use the `dockremap` user
    automatically created by Docker, but you can't modify the
    permissions until after configuring and restarting Docker.

4.  Enabling `userns-remap` effectively masks existing image and container
    layers, as well as other Docker objects within `/var/lib/docker/`. This is
    because Docker needs to adjust the ownership of these resources and actually
    stores them in a subdirectory within `/var/lib/docker/`. It is best to enable
    this feature on a new Docker installation rather than an existing one.

    Along the same lines, if you disable `userns-remap` you can't access any
    of the resources created while it was enabled.

5.  Check the [limitations](#user-namespace-known-limitations) on user
    namespaces to be sure your use case is possible.

## Enable userns-remap on the daemon

You can start `dockerd` with the `--userns-remap` flag or follow this
procedure to configure the daemon using the `daemon.json` configuration file.
The `daemon.json` method is recommended. If you use the flag, use the following
command as a model:

```console
$ dockerd --userns-remap="testuser:testuser"
```

1.  Edit `/etc/docker/daemon.json`. Assuming the file was previously empty, the
    following entry enables `userns-remap` using user and group called
    `testuser`. You can address the user and group by ID or name. You only need to
    specify the group name or ID if it is different from the user name or ID. If
    you provide both the user and group name or ID, separate them by a colon
    (`:`) character. The following formats all work for the value, assuming
    the UID and GID of `testuser` are `1001`:

    - `testuser`
    - `testuser:testuser`
    - `1001`
    - `1001:1001`
    - `testuser:1001`
    - `1001:testuser`

    ```json
    {
      "userns-remap": "testuser"
    }
    ```

    > [!NOTE]
    >
    > To use the `dockremap` user and have Docker create it for you,
    > set the value to `default` rather than `testuser`.

    Save the file and restart Docker.

2.  If you are using the `dockremap` user, verify that Docker created it using
    the `id` command.

    ```console
    $ id dockremap

    uid=112(dockremap) gid=116(dockremap) groups=116(dockremap)
    ```

    Verify that the entry has been added to `/etc/subuid` and `/etc/subgid`:

    ```console
    $ grep dockremap /etc/subuid

    dockremap:231072:65536

    $ grep dockremap /etc/subgid

    dockremap:231072:65536
    ```

    If these entries are not present, edit the files as the `root` user and
    assign a starting UID and GID that is the highest-assigned one plus the
    offset (in this case, `65536`). Be careful not to allow any overlap in the
    ranges.

3.  Verify that previous images are not available using the `docker image ls`
    command. The output should be empty.

4.  Start a container from the `hello-world` image.

    ```console
    $ docker run hello-world
    ```

5.  Verify that a namespaced directory exists within `/var/lib/docker/` named
    with the UID and GID of the namespaced user, owned by that UID and GID,
    and not group-or-world-readable. Some of the subdirectories are still
    owned by `root` and have different permissions.

    ```console
    $ sudo ls -ld /var/lib/docker/231072.231072/

    drwx------ 11 231072 231072 11 Jun 21 21:19 /var/lib/docker/231072.231072/

    $ sudo ls -l /var/lib/docker/231072.231072/

    total 14
    drwx------ 5 231072 231072 5 Jun 21 21:19 aufs
    drwx------ 3 231072 231072 3 Jun 21 21:21 containers
    drwx------ 3 root   root   3 Jun 21 21:19 image
    drwxr-x--- 3 root   root   3 Jun 21 21:19 network
    drwx------ 4 root   root   4 Jun 21 21:19 plugins
    drwx------ 2 root   root   2 Jun 21 21:19 swarm
    drwx------ 2 231072 231072 2 Jun 21 21:21 tmp
    drwx------ 2 root   root   2 Jun 21 21:19 trust
    drwx------ 2 231072 231072 3 Jun 21 21:19 volumes
    ```

    Your directory listing may have some differences, especially if you
    use a different container storage driver than `aufs`.

    The directories which are owned by the remapped user are used instead
    of the same directories directly beneath `/var/lib/docker/` and the
    unused versions (such as `/var/lib/docker/tmp/` in the example here)
    can be removed. Docker does not use them while `userns-remap` is
    enabled.

## Disable namespace remapping for a container

If you enable user namespaces on the daemon, all containers are started with
user namespaces enabled by default. In some situations, such as privileged
containers, you may need to disable user namespaces for a specific container.
See
[user namespace known limitations](#user-namespace-known-limitations)
for some of these limitations.

To disable user namespaces for a specific container, add the `--userns=host`
flag to the `docker container create`, `docker container run`, or `docker container exec` command.

There is a side effect when using this flag: user remapping will not be enabled for that container but, because the read-only (image) layers are shared between containers, ownership of the containers filesystem will still be remapped.

What this means is that the whole container filesystem will belong to the user specified in the `--userns-remap` daemon config (`231072` in the example above). This can lead to unexpected behavior of programs inside the container. For instance `sudo` (which checks that its binaries belong to user `0`) or binaries with a `setuid` flag.

## User namespace known limitations

The following standard Docker features are incompatible with running a Docker
daemon with user namespaces enabled:

- Sharing PID or NET namespaces with the host (`--pid=host` or `--network=host`).
- External (volume or storage) drivers which are unaware or incapable of using
  daemon user mappings.
- Using the `--privileged` mode flag on `docker run` without also specifying
  `--userns=host`.

User namespaces are an advanced feature and require coordination with other
capabilities. For example, if volumes are mounted from the host, file ownership
must be pre-arranged if you need read or write access to the volume contents.

While the root user inside a user-namespaced container process has many of the
expected privileges of the superuser within the container, the Linux kernel
imposes restrictions based on internal knowledge that this is a user-namespaced
process. One notable restriction is the inability to use the `mknod` command.
Permission is denied for device creation within the container when run by
the `root` user.


---

# Storage

*Sección: Engine*

Docker storage covers two different concepts:

**Container data persistence** (this page): How to store application data
outside containers using volumes, bind mounts, and tmpfs mounts. This data
persists independently of container lifecycle.

**Daemon storage backends** ([containerd image store](containerd.md) and
[storage drivers](drivers/)): How the daemon stores image layers and container
writable layers on disk.

This page focuses on container data persistence. For information about how
Docker stores images and container layers, see
[containerd image store](containerd.md) or [Storage drivers](drivers/).

## Container layer basics

By default all files created inside a container are stored on a writable
container layer that sits on top of the read-only, immutable image layers.

Data written to the container layer doesn't persist when the container is
destroyed. This means that it can be difficult to get the data out of the
container if another process needs it.

The writable layer is unique per container. You can't easily extract the data
from the writeable layer to the host, or to another container.

## Storage mount options

Docker supports the following types of storage mounts for storing data outside
of the writable layer of the container:

- [Volume mounts](#volume-mounts)
- [Bind mounts](#bind-mounts)
- [tmpfs mounts](#tmpfs-mounts)
- [Image mounts](#image-mounts)
- [Named pipes](#named-pipes)

No matter which type of mount you choose to use, the data looks the same from
within the container. It is exposed as either a directory or an individual file
in the container's filesystem.

### Volume mounts

Volumes are persistent storage mechanisms managed by the Docker daemon. They
retain data even after the containers using them are removed. Volume data is
stored on the filesystem on the host, but in order to interact with the data in
the volume, you must mount the volume to a container. Directly accessing or
interacting with the volume data is unsupported, undefined behavior, and may
result in the volume or its data breaking in unexpected ways.

Volumes are ideal for performance-critical data processing and long-term
storage needs. Since the storage location is managed on the daemon host,
volumes provide the same raw file performance as accessing the host filesystem
directly.

### Bind mounts

Bind mounts create a direct link between a host system path and a container,
allowing access to files or directories stored anywhere on the host. Since they
aren't isolated by Docker, both non-Docker processes on the host and container
processes can modify the mounted files simultaneously.

Use bind mounts when you need to be able to access files from both the
container and the host.

### tmpfs mounts

A tmpfs mount stores files directly in the host machine's memory, ensuring the
data is not written to disk. This storage is ephemeral: the data is lost when
the container is stopped or restarted, or when the host is rebooted. tmpfs
mounts do not persist data either on the Docker host or within the container's
filesystem.

These mounts are suitable for scenarios requiring temporary, in-memory storage,
such as caching intermediate data, handling sensitive information like
credentials, or reducing disk I/O. Use tmpfs mounts only when the data does not
need to persist beyond the current container session.

### Image mounts

An image mount makes the contents of another image available inside a container
at a path you choose. The mounted image is read-only and isn't part of the
container's own image, so you can bring in tools or assets from one image
without rebuilding another.

Use image mounts when you need to consume files packaged as an image, such as
mounting a tool-rich image to debug a minimal container, or sharing read-only
assets across containers running different images. Image mounts require the
[containerd image store](containerd.md).

### Named pipes

[Named pipes](https://docs.microsoft.com/en-us/windows/desktop/ipc/named-pipes)
can be used for communication between the Docker host and a container. Common
use case is to run a third-party tool inside of a container and connect to the
Docker Engine API using a named pipe.

## Next steps

Learn more about container data persistence:

- [Volumes](volumes.md)
- [Bind mounts](bind-mounts.md)
- [tmpfs mounts](tmpfs.md)
- [Image mounts](image-mounts.md)

Learn more about daemon storage backends:

- [containerd image store](containerd.md)
- [Storage drivers](drivers/)


---

# Bind mounts

*Sección: Engine*

When you use a bind mount, a file or directory on the host machine is mounted
from the host into a container. By contrast, when you use a volume, a new
directory is created within Docker's storage directory on the host machine.
Docker creates and maintains this storage location, but containers access it
directly using standard filesystem operations.

## When to use bind mounts

Bind mounts are appropriate for the following types of use case:

- Sharing source code or build artifacts between a development environment on
  the Docker host and a container.

- When you want to create or generate files in a container and persist the
  files onto the host's filesystem.

- Sharing configuration files from the host machine to containers. This is how
  Docker provides DNS resolution to containers by default, by mounting
  `/etc/resolv.conf` from the host machine into each container.

Bind mounts are also available for builds: you can bind mount source code from
the host into the build container to test, lint, or compile a project.

## Bind-mounting over existing data

If you bind mount file or directory into a directory in the container in which
files or directories exist, the pre-existing files are obscured by the mount.
This is similar to if you were to save files into `/mnt` on a Linux host, and
then mounted a USB drive into `/mnt`. The contents of `/mnt` would be obscured
by the contents of the USB drive until the USB drive was unmounted.

With containers, there's no straightforward way of removing a mount to reveal
the obscured files again. Your best option is to recreate the container without
the mount.

## Considerations and constraints

- Bind mounts have write access to files on the host by default.

  One side effect of using bind mounts is that you can change the host
  filesystem via processes running in a container, including creating,
  modifying, or deleting important system files or directories. This capability
  can have security implications. For example, it may affect non-Docker
  processes on the host system.

  You can use the `readonly` or `ro` option to prevent the container from
  writing to the mount.

- Bind mounts are created to the Docker daemon host, not the client.

  If you're using a remote Docker daemon, you can't create a bind mount to
  access files on the client machine in a container.

  For Docker Desktop, the daemon runs inside a Linux VM, not directly on the
  native host. Docker Desktop has built-in mechanisms that transparently handle
  bind mounts, allowing you to share native host filesystem paths with
  containers running in the virtual machine.

- Containers with bind mounts are strongly tied to the host.

  Bind mounts rely on the host machine's filesystem having a specific directory
  structure available. This reliance means that containers with bind mounts may
  fail if run on a different host without the same directory structure.

## Syntax

To create a bind mount, you can use either the `--mount` or `--volume` flag.

```console
$ docker run --mount type=bind,src=<host-path>,dst=<container-path>
$ docker run --volume <host-path>:<container-path>
```

In general, `--mount` is preferred. The main difference is that the `--mount`
flag is more explicit and supports all the available options.

If you use `--volume` to bind-mount a file or directory that does not yet
exist on the Docker host, Docker automatically creates the directory on the
host for you. It's always created as a directory. If the Docker daemon doesn't
have permission to create the source directory, create it before starting the
container.

By default, `--mount` does not automatically create a directory if the specified mount
path does not exist on the host. Instead, it produces an error:

```console
$ docker run --mount type=bind,src=/dev/noexist,dst=/mnt/foo alpine
docker: Error response from daemon: invalid mount config for type "bind": bind source path does not exist: /dev/noexist.
```

You can use the `bind-create-src` option to automatically create the source directory
on the host if it doesn't exist:

```console
$ docker run --mount type=bind,src=/home/user/mydir,dst=/mnt/foo,bind-create-src alpine
```

### Options for --mount

The `--mount` flag consists of multiple key-value pairs, separated by commas
and each consisting of a `<key>=<value>` tuple. The order of the keys isn't
significant.

```console
$ docker run --mount type=bind,src=<host-path>,dst=<container-path>[,<key>=<value>...]
```

Valid options for `--mount type=bind` include:

| Option                         | Description                                                                                                                                                         |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source`, `src`                | The location of the file or directory on the host. This can be an absolute or relative path.                                                                        |
| `destination`, `dst`, `target` | The path where the file or directory is mounted in the container. Must be an absolute path.                                                                         |
| `readonly`, `ro`               | If present, causes the bind mount to be [mounted into the container as read-only](#use-a-read-only-bind-mount).                                                     |
| `bind-propagation`             | If present, changes the [bind propagation](#configure-bind-propagation).                                                                                            |
| `bind-create-src`              | Automatically creates the source directory on the host if it doesn't exist. By default, `--mount` produces an error if the source path doesn't exist on the daemon. |

```console {title="Example"}
$ docker run --mount type=bind,src=.,dst=/project,ro,bind-propagation=rshared
```

### Options for --volume

The `--volume` or `-v` flag consists of three fields, separated by colon
characters (`:`). The fields must be in the correct order.

```console
$ docker run -v <host-path>:<container-path>[:opts]
```

The first field is the path on the host to bind mount into the container. The
second field is the path where the file or directory is mounted in the
container.

The third field is optional, and is a comma-separated list of options. Valid
options for `--volume` with a bind mount include:

| Option               | Description                                                                                                        |
| -------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `readonly`, `ro`     | If present, causes the bind mount to be [mounted into the container as read-only](#use-a-read-only-bind-mount).    |
| `z`, `Z`             | Configures SELinux labeling. See [Configure the SELinux label](#configure-the-selinux-label)                       |
| `rprivate` (default) | Sets bind propagation to `rprivate` for this mount. See [Configure bind propagation](#configure-bind-propagation). |
| `private`            | Sets bind propagation to `private` for this mount. See [Configure bind propagation](#configure-bind-propagation).  |
| `rshared`            | Sets bind propagation to `rshared` for this mount. See [Configure bind propagation](#configure-bind-propagation).  |
| `shared`             | Sets bind propagation to `shared` for this mount. See [Configure bind propagation](#configure-bind-propagation).   |
| `rslave`             | Sets bind propagation to `rslave` for this mount. See [Configure bind propagation](#configure-bind-propagation).   |
| `slave`              | Sets bind propagation to `slave` for this mount. See [Configure bind propagation](#configure-bind-propagation).    |

```console {title="Example"}
$ docker run -v .:/project:ro,rshared
```

## Start a container with a bind mount

Consider a case where you have a directory `source` and that when you build the
source code, the artifacts are saved into another directory, `source/target/`.
You want the artifacts to be available to the container at `/app/`, and you
want the container to get access to a new build each time you build the source
on your development host. Use the following command to bind-mount the `target/`
directory into your container at `/app/`. Run the command from within the
`source` directory. The `$(pwd)` sub-command expands to the current working
directory on Linux or macOS hosts.
If you're on Windows, see also [Path conversions on Windows](../../desktop/troubleshoot-and-support/troubleshoot/topics.md).

The following `--mount` and `-v` examples produce the same result. You can't
run them both unless you remove the `devtest` container after running the first
one.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  nginx:latest
```

{{< /tab >}}
{{< /tabs >}}

Use `docker inspect devtest` to verify that the bind mount was created
correctly. Look for the `Mounts` section:

```json
"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
],
```

This shows that the mount is a `bind` mount, it shows the correct source and
destination, it shows that the mount is read-write, and that the propagation is
set to `rprivate`.

Stop and remove the container:

```console
$ docker container rm -fv devtest
```

### Mount into a non-empty directory on the container

If you bind-mount a directory into a non-empty directory on the container, the
directory's existing contents are obscured by the bind mount. This can be
beneficial, such as when you want to test a new version of your application
without building a new image. However, it can also be surprising and this
behavior differs from that of [volumes](volumes.md).

This example is contrived to be extreme, but replaces the contents of the
container's `/usr/` directory with the `/tmp/` directory on the host machine. In
most cases, this would result in a non-functioning container.

The `--mount` and `-v` examples have the same end result.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  -it \
  --name broken-container \
  --mount type=bind,source=/tmp,target=/usr \
  nginx:latest

docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  -it \
  --name broken-container \
  -v /tmp:/usr \
  nginx:latest

docker: Error response from daemon: oci runtime error: container_linux.go:262:
starting container process caused "exec: \"nginx\": executable file not found in $PATH".
```

{{< /tab >}}
{{< /tabs >}}

The container is created but does not start. Remove it:

```console
$ docker container rm broken-container
```

## Use a read-only bind mount

For some development applications, the container needs to
write into the bind mount, so changes are propagated back to the
Docker host. At other times, the container only needs read access.

This example modifies the previous one, but mounts the directory as a read-only
bind mount, by adding `ro` to the (empty by default) list of options, after the
mount point within the container. Where multiple options are present, separate
them by commas.

The `--mount` and `-v` examples have the same result.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app,readonly \
  nginx:latest
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:ro \
  nginx:latest
```

{{< /tab >}}
{{< /tabs >}}

Use `docker inspect devtest` to verify that the bind mount was created
correctly. Look for the `Mounts` section:

```json
"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "ro",
        "RW": false,
        "Propagation": "rprivate"
    }
],
```

Stop and remove the container:

```console
$ docker container rm -fv devtest
```

## Recursive mounts

When you bind mount a path that itself contains mounts, those submounts are
also included in the bind mount by default. This behavior is configurable,
using the `bind-recursive` option for `--mount`. This option is only supported
with the `--mount` flag, not with `-v` or `--volume`.

If the bind mount is read-only, the Docker Engine makes a best-effort attempt
at making the submounts read-only as well. This is referred to as recursive
read-only mounts. Recursive read-only mounts require Linux kernel version 5.12
or later. If you're running an older kernel version, submounts are
automatically mounted as read-write by default. Attempting to set submounts to
be read-only on a kernel version earlier than 5.12, using the
`bind-recursive=readonly` option, results in an error.

Supported values for the `bind-recursive` option are:

| Value               | Description                                                                                                       |
| :------------------ | :---------------------------------------------------------------------------------------------------------------- |
| `enabled` (default) | Read-only mounts are made recursively read-only if kernel is v5.12 or later. Otherwise, submounts are read-write. |
| `disabled`          | Submounts are ignored (not included in the bind mount).                                                           |
| `writable`          | Submounts are read-write.                                                                                         |
| `readonly`          | Submounts are read-only. Requires kernel v5.12 or later.                                                          |

## Configure bind propagation

Bind propagation defaults to `rprivate` for both bind mounts and volumes. It is
only configurable for bind mounts, and only on Linux host machines. Bind
propagation is an advanced topic and many users never need to configure it.

Bind propagation refers to whether or not mounts created within a given
bind-mount can be propagated to replicas of that mount. Consider
a mount point `/mnt`, which is also mounted on `/tmp`. The propagation settings
control whether a mount on `/tmp/a` would also be available on `/mnt/a`. Each
propagation setting has a recursive counterpoint. In the case of recursion,
consider that `/tmp/a` is also mounted as `/foo`. The propagation settings
control whether `/mnt/a` and/or `/tmp/a` would exist.

> [!NOTE]
> Mount propagation doesn't work with Docker Desktop.

| Propagation setting | Description                                                                                                                                                                                                         |
| :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `shared`            | Sub-mounts of the original mount are exposed to replica mounts, and sub-mounts of replica mounts are also propagated to the original mount.                                                                         |
| `slave`             | similar to a shared mount, but only in one direction. If the original mount exposes a sub-mount, the replica mount can see it. However, if the replica mount exposes a sub-mount, the original mount cannot see it. |
| `private`           | The mount is private. Sub-mounts within it are not exposed to replica mounts, and sub-mounts of replica mounts are not exposed to the original mount.                                                               |
| `rshared`           | The same as shared, but the propagation also extends to and from mount points nested within any of the original or replica mount points.                                                                            |
| `rslave`            | The same as slave, but the propagation also extends to and from mount points nested within any of the original or replica mount points.                                                                             |
| `rprivate`          | The default. The same as private, meaning that no mount points anywhere within the original or replica mount points propagate in either direction.                                                                  |

Before you can set bind propagation on a mount point, the host filesystem needs
to already support bind propagation.

For more information about bind propagation, see the
[Linux kernel documentation for shared subtree](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt).

The following example mounts the `target/` directory into the container twice,
and the second mount sets both the `ro` option and the `rslave` bind propagation
option.

The `--mount` and `-v` examples have the same result.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  --mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
  nginx:latest
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app \
  -v "$(pwd)"/target:/app2:ro,rslave \
  nginx:latest
```

{{< /tab >}}
{{< /tabs >}}

Now if you create `/app/foo/`, `/app2/foo/` also exists.

## Configure the SELinux label

If you use SELinux, you can add the `z` or `Z` options to modify the SELinux
label of the host file or directory being mounted into the container. This
affects the file or directory on the host machine itself and can have
consequences outside of the scope of Docker.

- The `z` option indicates that the bind mount content is shared among multiple
  containers.
- The `Z` option indicates that the bind mount content is private and unshared.

Use extreme caution with these options. Bind-mounting a system directory
such as `/home` or `/usr` with the `Z` option renders your host machine
inoperable and you may need to relabel the host machine files by hand.

> [!IMPORTANT]
>
> When using bind mounts with services, SELinux labels
> (`:Z` and `:z`), as well as `:ro` are ignored. See
> [moby/moby #32579](https://github.com/moby/moby/issues/32579) for details.

This example sets the `z` option to specify that multiple containers can share
the bind mount's contents:

It is not possible to modify the SELinux label using the `--mount` flag.

```console
$ docker run -d \
  -it \
  --name devtest \
  -v "$(pwd)"/target:/app:z \
  nginx:latest
```

## Use a bind mount with Docker Compose

A single Docker Compose service with a bind mount looks like this:

```yaml
services:
  frontend:
    image: node:lts
    volumes:
      - type: bind
        source: ./static
        target: /opt/app/static
volumes:
  myapp:
```

For more information about using volumes of the `bind` type with Compose, see
[Compose reference on the volumes top-level element](../../reference/compose-file/volumes.md).
and
[Compose reference on the volume attribute](../../reference/compose-file/services.md#volumes).

## Next steps

- Learn about [volumes](volumes.md).
- Learn about [tmpfs mounts](tmpfs.md).
- Learn about [image mounts](image-mounts.md).
- Learn about [storage drivers](/engine/storage/drivers/).


---

# containerd image store with Docker Engine

*Sección: Engine*

The containerd image store is the default storage backend for Docker Engine
29.0 and later on fresh installations. If you upgraded from an earlier version,
your daemon continues using the legacy graph drivers (overlay2) until you
enable the containerd image store.

containerd, the industry-standard container runtime, uses snapshotters instead
of classic storage drivers for storing image and container data.

> [!NOTE]
> The containerd image store is not available when using user namespace
> remapping (`userns-remap`). See
> [moby#47377](https://github.com/moby/moby/issues/47377) for details.

## Why use the containerd image store

The containerd image store uses snapshotters to manage how image layers are
stored and accessed on the filesystem. This differs from the classic graph
drivers like overlay2.

The containerd image store enables:

- Building and storing multi-platform images locally. With classic storage
  drivers, you need external builders for multi-platform images.
- Working with images that include attestations (provenance, SBOM). These use
  image indices that the classic store doesn't support.
- Running Wasm containers. The containerd image store supports WebAssembly
  workloads.
- Using advanced snapshotters. containerd supports pluggable snapshotters that
  provide features like lazy-pulling of images (stargz) or peer-to-peer image
  distribution (nydus, dragonfly).

For most users, switching to the containerd image store is transparent. The
storage backend changes, but your workflows remain the same.

## Disk space usage

The containerd image store uses more disk space than the legacy storage
drivers for the same images. This is because containerd stores images in both
compressed and uncompressed formats, while the legacy drivers stored only the
uncompressed layers.

When you pull an image, containerd keeps the compressed layers (as received
from the registry) and also extracts them to disk. This dual storage means
each layer occupies more space. The compressed format enables faster pulls and
pushes, but requires additional disk capacity.

> [!IMPORTANT]
> containerd uses a separate storage path from the Docker data directory.
> If you previously configured a custom data directory for Docker (for example,
> to use a different partition), containerd's storage is not automatically
> moved to that location. You need to configure containerd's data directory
> separately to avoid filling your root partition.
>
> To configure containerd's data directory, see
> [Configure the data directory location](../daemon/index.md#configure-the-data-directory-location).

If disk space is constrained, consider the following:

- Regularly prune unused images with `docker image prune`
- Use `docker system df` to monitor disk usage
- [Configure the data directory](../daemon/index.md#configure-the-data-directory-location)
  to use a partition with adequate space

## Enable containerd image store on Docker Engine

If you're upgrading from an earlier Docker Engine version, you need to manually
enable the containerd image store.

> [!IMPORTANT]
> Switching storage backends temporarily hides images and containers created
> with the other backend. Your data remains on disk. To access the old images
> again, switch back to your previous storage configuration.

Add the following configuration to your `/etc/docker/daemon.json` file:

```json
{
  "features": {
    "containerd-snapshotter": true
  }
}
```

Save the file and restart the daemon:

```console
$ sudo systemctl restart docker
```

After restarting the daemon, verify you're using the containerd image store:

```console
$ docker info -f '{{ .DriverStatus }}'
[[driver-type io.containerd.snapshotter.v1]]
```

Docker Engine uses the `overlayfs` containerd snapshotter by default.

> [!NOTE]
> When you enable the containerd image store, existing images and containers
> from the overlay2 driver remain on disk but become hidden. They reappear if
> you switch back to overlay2. To use your existing images with the containerd
> image store, push them to a registry first, or use `docker save` to export
> them.

## Experimental automatic migration

Docker Engine includes an experimental feature that can automatically switch to
the containerd image store under certain conditions. **This feature is
experimental**. It's provided for those who want to test it, but [starting
fresh](#enable-containerd-image-store-on-docker-engine) is the recommended
approach.

> [!CAUTION]
> The automatic migration feature is experimental and may not work reliably in
> all scenarios. Create backups before attempting to use it.

To enable automatic migration, add the `containerd-migration` feature to your
`/etc/docker/daemon.json`:

```json
{
  "features": {
    "containerd-migration": true
  }
}
```

You can also set the `DOCKER_MIGRATE_SNAPSHOTTER_THRESHOLD` environment
variable to make the daemon switch automatically if you have no containers and
the total size of all image layers is at or below the threshold. The value is a
human-readable size (for example, `200M` or `1G`). For systemd:

```console
$ sudo systemctl edit docker.service
```

Add:

```ini
[Service]
Environment="DOCKER_MIGRATE_SNAPSHOTTER_THRESHOLD=200M"
```

If you have no running or stopped containers and the total size of all image
layers is 200M or less, the daemon switches to the containerd image store on
restart. Your overlay2 data remains
on disk but becomes hidden.

## Additional resources

To learn more about the containerd image store and its capabilities in Docker
Desktop, see
[containerd image store on Docker Desktop](../../desktop/features/containerd.md).


---

# Storage drivers

*Sección: Engine*

> [!NOTE]
> This page describes the classic storage drivers, such as `overlay2`. Docker
> Engine 29.0 and later uses the [containerd image store](../containerd.md) by
> default for fresh installations, which uses snapshotters instead of classic
> storage drivers. If you're running a fresh installation of Docker Engine 29.0
> or later, or if you've migrated to the containerd image store, the concepts on
> this page still explain how image layers work, but the commands and examples
> won't reflect how your system stores images. For operational guidance, see
> [containerd image store](../containerd.md).

To use storage drivers effectively, it's important to know how Docker builds and
stores images, and how these images are used by containers. You can use this
information to make informed choices about the best way to persist data from
your applications and avoid performance problems along the way.

## Storage drivers versus Docker volumes

Docker uses storage drivers to store image layers, and to store data in the
writable layer of a container. The container's writable layer doesn't persist
after the container is deleted, but is suitable for storing ephemeral data that
is generated at runtime. Storage drivers are optimized for space efficiency, but
(depending on the storage driver) write speeds are lower than native file system
performance, especially for storage drivers that use a copy-on-write filesystem.
Write-intensive applications, such as database storage, are impacted by a
performance overhead, particularly if pre-existing data exists in the read-only
layer.

Use Docker volumes for write-intensive data, data that must persist beyond the
container's lifespan, and data that must be shared between containers. Refer to
the [volumes section](../volumes.md) to learn how to use volumes to persist data
and improve performance.

## Images and layers

A Docker image is built up from a series of layers. Each layer represents an
instruction in the image's Dockerfile. Each layer except the very last one is
read-only. Consider the following Dockerfile:

```dockerfile
# syntax=docker/dockerfile:1

FROM ubuntu:22.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app
RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py
```

This Dockerfile contains four commands. Commands that modify the filesystem create
a new layer. The `FROM` statement starts out by creating a layer from the `ubuntu:22.04`
image. The `LABEL` command only modifies the image's metadata, and doesn't produce
a new layer. The `COPY` command adds some files from your Docker client's current
directory. The first `RUN` command builds your application using the `make` command,
and writes the result to a new layer. The second `RUN` command removes a cache
directory, and writes the result to a new layer. Finally, the `CMD` instruction
specifies what command to run within the container, which only modifies the
image's metadata, which doesn't produce an image layer.

Each layer is only a set of differences from the layer before it. Note that both
_adding_, and _removing_ files will result in a new layer. In the example above,
the `$HOME/.cache` directory is removed, but will still be available in the
previous layer and add up to the image's total size. Refer to the
[Best practices for writing Dockerfiles](../../../build/building/best-practices.md)
and [use multi-stage builds](../../../build/building/multi-stage.md)
sections to learn how to optimize your Dockerfiles for efficient images.

The layers are stacked on top of each other. When you create a new container,
you add a new writable layer on top of the underlying layers. This layer is often
called the "container layer". All changes made to the running container, such as
writing new files, modifying existing files, and deleting files, are written to
this thin writable container layer. The diagram below shows a container based
on an `ubuntu:15.04` image.

![Layers of a container based on the Ubuntu image](images/container-layers.webp?w=450&h=300)

A storage driver handles the details about the way these layers interact with
each other. Different storage drivers are available, which have advantages
and disadvantages in different situations.

## Container and layers

The major difference between a container and an image is the top writable layer.
All writes to the container that add new or modify existing data are stored in
this writable layer. When the container is deleted, the writable layer is also
deleted. The underlying image remains unchanged.

Because each container has its own writable container layer, and all changes are
stored in this container layer, multiple containers can share access to the same
underlying image and yet have their own data state. The diagram below shows
multiple containers sharing the same Ubuntu 15.04 image.

![Containers sharing the same image](images/sharing-layers.webp?w=600&h=300)

Docker uses storage drivers to manage the contents of the image layers and the
writable container layer. Each storage driver handles the implementation
differently, but all drivers use stackable image layers and the copy-on-write
(CoW) strategy.

> [!NOTE]
>
> Use Docker volumes if you need multiple containers to have shared access to
> the exact same data. Refer to the [volumes section](../volumes.md) to learn
> about volumes.

## Container size on disk

To view the approximate size of a running container, you can use the `docker ps -s`
command. Two different columns relate to size.

- `size`: the amount of data (on disk) that's used for the writable layer of
  each container.
- `virtual size`: the amount of data used for the read-only image data
  used by the container plus the container's writable layer `size`.
  Multiple containers may share some or all read-only
  image data. Two containers started from the same image share 100% of the
  read-only data, while two containers with different images which have layers
  in common share those common layers. Therefore, you can't just total the
  virtual sizes. This over-estimates the total disk usage by a potentially
  non-trivial amount.

The total disk space used by all of the running containers on disk is some
combination of each container's `size` and the `virtual size` values. If
multiple containers started from the same exact image, the total size on disk for
these containers would be SUM (`size` of containers) plus one image size
(`virtual size` - `size`).

This also doesn't count the following additional ways a container can take up
disk space:

- Disk space used for log files stored by the [logging-driver](../../logging/index.md).
  This can be non-trivial if your container generates a large amount of logging
  data and log rotation isn't configured.
- Volumes and bind mounts used by the container.
- Disk space used for the container's configuration files, which are typically
  small.
- Memory written to disk (if swapping is enabled).
- Checkpoints, if you're using the experimental checkpoint/restore feature.

## The copy-on-write (CoW) strategy

Copy-on-write is a strategy of sharing and copying files for maximum efficiency.
If a file or directory exists in a lower layer within the image, and another
layer (including the writable layer) needs read access to it, it just uses the
existing file. The first time another layer needs to modify the file (when
building the image or running the container), the file is copied into that layer
and modified. This minimizes I/O and the size of each of the subsequent layers.
These advantages are explained in more depth below.

### Sharing promotes smaller images

When you use `docker pull` to pull down an image from a repository, or when you
create a container from an image that doesn't yet exist locally, each layer is
pulled down separately, and stored in Docker's local storage area, which is
usually `/var/lib/docker/` on Linux hosts. You can see these layers being pulled
in this example:

```console
$ docker pull ubuntu:22.04
22.04: Pulling from library/ubuntu
f476d66f5408: Pull complete
8882c27f669e: Pull complete
d9af21273955: Pull complete
f5029279ec12: Pull complete
Digest: sha256:6120be6a2b7ce665d0cbddc3ce6eae60fe94637c6a66985312d1f02f63cc0bcd
Status: Downloaded newer image for ubuntu:22.04
docker.io/library/ubuntu:22.04
```

Each of these layers is stored in its own directory inside the Docker host's
local storage area. To examine the layers on the filesystem, list the contents
of `/var/lib/docker/<storage-driver>`. This example uses the `overlay2`
storage driver:

```console
$ ls /var/lib/docker/overlay2
16802227a96c24dcbeab5b37821e2b67a9f921749cd9a2e386d5a6d5bc6fc6d3
377d73dbb466e0bc7c9ee23166771b35ebdbe02ef17753d79fd3571d4ce659d7
3f02d96212b03e3383160d31d7c6aeca750d2d8a1879965b89fe8146594c453d
ec1ec45792908e90484f7e629330666e7eee599f08729c93890a7205a6ba35f5
l
```

The directory names don't correspond to the layer IDs.

Now imagine that you have two different Dockerfiles. You use the first one to
create an image called `acme/my-base-image:1.0`.

```dockerfile
# syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache bash
```

The second one is based on `acme/my-base-image:1.0`, but has some additional
layers:

```dockerfile
# syntax=docker/dockerfile:1
FROM acme/my-base-image:1.0
COPY . /app
RUN chmod +x /app/hello.sh
CMD /app/hello.sh
```

The second image contains all the layers from the first image, plus new layers
created by the `COPY` and `RUN` instructions, and a read-write container layer.
Docker already has all the layers from the first image, so it doesn't need to
pull them again. The two images share any layers they have in common.

If you build images from the two Dockerfiles, you can use `docker image ls` and
`docker image history` commands to verify that the cryptographic IDs of the shared
layers are the same.

1. Make a new directory `cow-test/` and change into it.

2. Within `cow-test/`, create a new file called `hello.sh` with the following contents.

   ```bash
   #!/usr/bin/env bash
   echo "Hello world"
   ```

3. Copy the contents of the first Dockerfile above into a new file called
   `Dockerfile.base`.

4. Copy the contents of the second Dockerfile above into a new file called
   `Dockerfile`.

5. Within the `cow-test/` directory, build the first image. Don't forget to
   include the final `.` in the command. That sets the `PATH`, which tells
   Docker where to look for any files that need to be added to the image.

   ```console
   $ docker build -t acme/my-base-image:1.0 -f Dockerfile.base .
   [+] Building 6.0s (11/11) FINISHED
   => [internal] load build definition from Dockerfile.base                                      0.4s
   => => transferring dockerfile: 116B                                                           0.0s
   => [internal] load .dockerignore                                                              0.3s
   => => transferring context: 2B                                                                0.0s
   => resolve image config for docker.io/docker/dockerfile:1                                     1.5s
   => [auth] docker/dockerfile:pull token for registry-1.docker.io                               0.0s
   => CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671... 0.0s
   => [internal] load .dockerignore                                                              0.0s
   => [internal] load build definition from Dockerfile.base                                      0.0s
   => [internal] load metadata for docker.io/library/alpine:latest                               0.0s
   => CACHED [1/2] FROM docker.io/library/alpine                                                 0.0s
   => [2/2] RUN apk add --no-cache bash                                                          3.1s
   => exporting to image                                                                         0.2s
   => => exporting layers                                                                        0.2s
   => => writing image sha256:da3cf8df55ee9777ddcd5afc40fffc3ead816bda99430bad2257de4459625eaa   0.0s
   => => naming to docker.io/acme/my-base-image:1.0                                              0.0s
   ```

6. Build the second image.

   ```console
   $ docker build -t acme/my-final-image:1.0 -f Dockerfile .

   [+] Building 3.6s (12/12) FINISHED
   => [internal] load build definition from Dockerfile                                            0.1s
   => => transferring dockerfile: 156B                                                            0.0s
   => [internal] load .dockerignore                                                               0.1s
   => => transferring context: 2B                                                                 0.0s
   => resolve image config for docker.io/docker/dockerfile:1                                      0.5s
   => CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9e2c9eca7367393aecc68795c671...  0.0s
   => [internal] load .dockerignore                                                               0.0s
   => [internal] load build definition from Dockerfile                                            0.0s
   => [internal] load metadata for docker.io/acme/my-base-image:1.0                               0.0s
   => [internal] load build context                                                               0.2s
   => => transferring context: 340B                                                               0.0s
   => [1/3] FROM docker.io/acme/my-base-image:1.0                                                 0.2s
   => [2/3] COPY . /app                                                                           0.1s
   => [3/3] RUN chmod +x /app/hello.sh                                                            0.4s
   => exporting to image                                                                          0.1s
   => => exporting layers                                                                         0.1s
   => => writing image sha256:8bd85c42fa7ff6b33902ada7dcefaaae112bf5673873a089d73583b0074313dd    0.0s
   => => naming to docker.io/acme/my-final-image:1.0                                              0.0s
   ```

7. Check out the sizes of the images.

   ```console
   $ docker image ls

   REPOSITORY             TAG     IMAGE ID         CREATED               SIZE
   acme/my-final-image    1.0     8bd85c42fa7f     About a minute ago    7.75MB
   acme/my-base-image     1.0     da3cf8df55ee     2 minutes ago         7.75MB
   ```

8. Check out the history of each image.

   ```console
   $ docker image history acme/my-base-image:1.0

   IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
   da3cf8df55ee   5 minutes ago   RUN /bin/sh -c apk add --no-cache bash # bui…   2.15MB    buildkit.dockerfile.v0
   <missing>      7 weeks ago     /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
   <missing>      7 weeks ago     /bin/sh -c #(nop) ADD file:f278386b0cef68136…   5.6MB
   ```

   Some steps don't have a size (`0B`), and are metadata-only changes, which do
   not produce an image layer and don't take up any size, other than the metadata
   itself. The output above shows that this image consists of 2 image layers.

   ```console
   $ docker image history  acme/my-final-image:1.0

   IMAGE          CREATED         CREATED BY                                      SIZE      COMMENT
   8bd85c42fa7f   3 minutes ago   CMD ["/bin/sh" "-c" "/app/hello.sh"]            0B        buildkit.dockerfile.v0
   <missing>      3 minutes ago   RUN /bin/sh -c chmod +x /app/hello.sh # buil…   39B       buildkit.dockerfile.v0
   <missing>      3 minutes ago   COPY . /app # buildkit                          222B      buildkit.dockerfile.v0
   <missing>      4 minutes ago   RUN /bin/sh -c apk add --no-cache bash # bui…   2.15MB    buildkit.dockerfile.v0
   <missing>      7 weeks ago     /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
   <missing>      7 weeks ago     /bin/sh -c #(nop) ADD file:f278386b0cef68136…   5.6MB
   ```

   Notice that all steps of the first image are also included in the final
   image. The final image includes the two layers from the first image, and
   two layers that were added in the second image.

   The `<missing>` lines in the `docker history` output indicate that those
   steps were either built on another system and part of the `alpine` image
   that was pulled from Docker Hub, or were built with BuildKit as builder.
   Before BuildKit, the "classic" builder would produce a new "intermediate"
   image for each step for caching purposes, and the `IMAGE` column would show
   the ID of that image.

   BuildKit uses its own caching mechanism, and no longer requires intermediate
   images for caching. Refer to [BuildKit](../../../build/buildkit/index.md)
   to learn more about other enhancements made in BuildKit.

9. Check out the layers for each image

   Use the `docker image inspect` command to view the cryptographic IDs of the
   layers in each image:

   ```console
   $ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-base-image:1.0
   [
     "sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
     "sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a"
   ]
   ```

   ```console
   $ docker image inspect --format "{{json .RootFS.Layers}}" acme/my-final-image:1.0
   [
     "sha256:72e830a4dff5f0d5225cdc0a320e85ab1ce06ea5673acfe8d83a7645cbd0e9cf",
     "sha256:07b4a9068b6af337e8b8f1f1dae3dd14185b2c0003a9a1f0a6fd2587495b204a",
     "sha256:cc644054967e516db4689b5282ee98e4bc4b11ea2255c9630309f559ab96562e",
     "sha256:e84fb818852626e89a09f5143dbc31fe7f0e0a6a24cd8d2eb68062b904337af4"
   ]
   ```

   Notice that the first two layers are identical in both images. The second
   image adds two additional layers. Shared image layers are only stored once
   in `/var/lib/docker/` and are also shared when pushing and pulling an image
   to an image registry. Shared image layers can therefore reduce network
   bandwidth and storage.

   > [!TIP]
   >
   > Format output of Docker commands with the `--format` option.
   >
   > The examples above use the `docker image inspect` command with the `--format`
   > option to view the layer IDs, formatted as a JSON array. The `--format`
   > option on Docker commands can be a powerful feature that allows you to
   > extract and format specific information from the output, without requiring
   > additional tools such as `awk` or `sed`. To learn more about formatting
   > the output of docker commands using the `--format` flag, refer to the
   > [format command and log output section](../../cli/formatting.md).
   > We also pretty-printed the JSON output using the [`jq` utility](https://stedolan.github.io/jq/)
   > for readability.

### Copying makes containers efficient

When you start a container, a thin writable container layer is added on top of
the other layers. Any changes the container makes to the filesystem are stored
here. Any files the container doesn't change don't get copied to this writable
layer. This means that the writable layer is as small as possible.

When an existing file in a container is modified, the storage driver performs a
copy-on-write operation. The specific steps involved depend on the specific
storage driver. For the `overlay2` driver, the copy-on-write operation follows
this rough sequence:

- Search through the image layers for the file to update. The process starts
  at the newest layer and works down to the base layer one layer at a time.
  When results are found, they're added to a cache to speed future operations.
- Perform a `copy_up` operation on the first copy of the file that's found, to
  copy the file to the container's writable layer.
- Any modifications are made to this copy of the file, and the container can't
  see the read-only copy of the file that exists in the lower layer.

Btrfs, ZFS, and other drivers handle the copy-on-write differently. You can
read more about the methods of these drivers later in their detailed
descriptions.

Containers that write a lot of data consume more space than containers
that don't. This is because most write operations consume new space in the
container's thin writable top layer. Note that changing the metadata of files,
for example, changing file permissions or ownership of a file, can also result
in a `copy_up` operation, therefore duplicating the file to the writable layer.

> [!TIP]
>
> Use volumes for write-heavy applications.
>
> Don't store the data in the container for write-heavy applications. Such
> applications, for example write-intensive databases, are known to be
> problematic particularly when pre-existing data exists in the read-only
> layer.
>
> Instead, use Docker volumes, which are independent of the running container,
> and designed to be efficient for I/O. In addition, volumes can be shared
> among containers and don't increase the size of your container's writable
> layer. Refer to the [use volumes](../volumes.md) section to learn about
> volumes.

A `copy_up` operation can incur a noticeable performance overhead. This overhead
is different depending on which storage driver is in use. Large files,
lots of layers, and deep directory trees can make the impact more noticeable.
This is mitigated by the fact that each `copy_up` operation only occurs the first
time a given file is modified.

To verify the way that copy-on-write works, the following procedure spins up 5
containers based on the `acme/my-final-image:1.0` image we built earlier and
examines how much room they take up.

1. From a terminal on your Docker host, run the following `docker run` commands.
   The strings at the end are the IDs of each container.

   ```console
   $ docker run -dit --name my_container_1 acme/my-final-image:1.0 bash \
     && docker run -dit --name my_container_2 acme/my-final-image:1.0 bash \
     && docker run -dit --name my_container_3 acme/my-final-image:1.0 bash \
     && docker run -dit --name my_container_4 acme/my-final-image:1.0 bash \
     && docker run -dit --name my_container_5 acme/my-final-image:1.0 bash

   40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
   a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
   3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
   939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
   cddae31c314fbab3f7eabeb9b26733838187abc9a2ed53f97bd5b04cd7984a5a
   ```

2. Run the `docker ps` command with the `--size` option to verify the 5 containers
   are running, and to see each container's size.

   ```console
   $ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"

   CONTAINER ID   IMAGE                     NAMES            SIZE
   cddae31c314f   acme/my-final-image:1.0   my_container_5   0B (virtual 7.75MB)
   939b3bf9e7ec   acme/my-final-image:1.0   my_container_4   0B (virtual 7.75MB)
   3ed3c1a10430   acme/my-final-image:1.0   my_container_3   0B (virtual 7.75MB)
   a5ff32e2b551   acme/my-final-image:1.0   my_container_2   0B (virtual 7.75MB)
   40ebdd763416   acme/my-final-image:1.0   my_container_1   0B (virtual 7.75MB)
   ```

   The output above shows that all containers share the image's read-only layers
   (7.75MB), but no data was written to the container's filesystem, so no additional
   storage is used for the containers.

   {{< accordion title="Advanced: metadata and logs storage used for containers" >}}

   > [!NOTE]
   >
   > This step requires a Linux machine, and doesn't work on Docker Desktop, as
   > it requires access to the Docker Daemon's file storage.

   While the output of `docker ps` provides you information about disk space
   consumed by a container's writable layer, it doesn't include information
   about metadata and log-files stored for each container.

   More details can be obtained by exploring the Docker Daemon's storage
   location (`/var/lib/docker` by default).

   ```console
   $ sudo du -sh /var/lib/docker/containers/*

   36K  /var/lib/docker/containers/3ed3c1a10430e09f253704116965b01ca920202d52f3bf381fbb833b8ae356bc
   36K  /var/lib/docker/containers/40ebdd7634162eb42bdb1ba76a395095527e9c0aa40348e6c325bd0aa289423c
   36K  /var/lib/docker/containers/939b3bf9e7ece24bcffec57d974c939da2bdcc6a5077b5459c897c1e2fa37a39
   36K  /var/lib/docker/containers/a5ff32e2b551168b9498870faf16c9cd0af820edf8a5c157f7b80da59d01a107
   36K  /var/lib/docker/containers/cddae31c314fbab3f7eabeb9b26733838187abc9a2ed53f97bd5b04cd7984a5a
   ```

   Each of these containers only takes up 36k of space on the filesystem.

   {{< /accordion >}}

3. Per-container storage

   To demonstrate this, run the following command to write the word 'hello' to
   a file on the container's writable layer in containers `my_container_1`,
   `my_container_2`, and `my_container_3`:

   ```console
   $ for i in {1..3}; do docker exec my_container_$i sh -c 'printf hello > /out.txt'; done
   ```

   Running the `docker ps` command again afterward shows that those containers
   now consume 5 bytes each. This data is unique to each container, and not
   shared. The read-only layers of the containers aren't affected, and are still
   shared by all containers.

   ```console
   $ docker ps --size --format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Size}}"

   CONTAINER ID   IMAGE                     NAMES            SIZE
   cddae31c314f   acme/my-final-image:1.0   my_container_5   0B (virtual 7.75MB)
   939b3bf9e7ec   acme/my-final-image:1.0   my_container_4   0B (virtual 7.75MB)
   3ed3c1a10430   acme/my-final-image:1.0   my_container_3   5B (virtual 7.75MB)
   a5ff32e2b551   acme/my-final-image:1.0   my_container_2   5B (virtual 7.75MB)
   40ebdd763416   acme/my-final-image:1.0   my_container_1   5B (virtual 7.75MB)
   ```

The previous examples illustrate how copy-on-write filesystems help make
containers efficient. Not only does copy-on-write save space, but it also
reduces container start-up time. When you create a container (or multiple
containers from the same image), Docker only needs to create the thin writable
container layer.

If Docker had to make an entire copy of the underlying image stack each time it
created a new container, container creation times and disk space used would be
significantly increased. This would be similar to the way that virtual machines
work, with one or more virtual disks per virtual machine. The [`vfs` storage](vfs-driver.md)
doesn't provide a CoW filesystem or other optimizations. When using this storage
driver, a full copy of the image's data is created for each container.

## Related information

- [Volumes](../volumes.md)
- [Select a storage driver](select-storage-driver.md)


---

# AUFS storage driver

*Sección: Engine*

> **Deprecated**
>
> The AuFS storage driver has been deprecated, and is removed in Docker Engine
> v24.0. If you are using AufS, you must migrate to a supported storage driver
> before upgrading to Docker Engine v24.0. Read the [Docker storage drivers](select-storage-driver.md)
> page for supported storage drivers.

AUFS is a *union filesystem*. The `aufs` storage driver was previously the default
storage driver used for managing images and layers on Docker for Ubuntu, and for
Debian versions prior to Stretch. If your Linux kernel is version 4.0 or higher,
and you use Docker Engine - Community, consider using the newer
[overlay2](overlayfs-driver.md), which has
potential performance advantages over the `aufs` storage driver.

## Prerequisites

- For Docker Engine - Community, AUFS is supported on Ubuntu, and on Debian versions prior to
  Stretch.
- If you use Ubuntu, you need to add the AUFS module to the kernel. If you do
  not install these packages, you need to use  `overlay2`.
- AUFS cannot use the following backing filesystems: `aufs`, `btrfs`, or
  `ecryptfs`. This means that the filesystem which contains
  `/var/lib/docker/aufs` cannot be one of these filesystem types.

## Configure Docker with the `aufs` storage driver

If the AUFS driver is loaded into the kernel when you start Docker, and no other
storage driver is configured, Docker uses it by default.

1.  Use the following command to verify that your kernel supports AUFS.

    ```console
    $ grep aufs /proc/filesystems

    nodev   aufs
    ```

2.  Check which storage driver Docker is using.

    ```console
    $ docker info

    <truncated output>
    Storage Driver: aufs
     Root Dir: /var/lib/docker/aufs
     Backing Filesystem: extfs
     Dirs: 0
     Dirperm1 Supported: true
    <truncated output>
    ```

3.  If you are using a different storage driver, either AUFS is not included in
    the kernel (in which case a different default driver is used) or that
    Docker has been explicitly configured to use a different driver. Check
    `/etc/docker/daemon.json` or the output of `ps auxw | grep dockerd` to see
    if Docker has been started with the `--storage-driver` flag.

## How the `aufs` storage driver works

AUFS is a *union filesystem*, which means that it layers multiple directories on
a single Linux host and presents them as a single directory. These directories
are called _branches_ in AUFS terminology, and _layers_ in Docker terminology.

The unification process is referred to as a _union mount_.

The diagram below shows a Docker container based on the `ubuntu:latest` image.

![Layers of an Ubuntu container](images/aufs_layers.webp) 

Each image layer, and the container layer, are represented on the Docker host as
subdirectories within `/var/lib/docker/`. The union mount provides the unified
view of all layers. The directory names do not directly correspond to the IDs
of the layers themselves.

AUFS uses the Copy-on-Write (CoW) strategy to maximize storage efficiency and
minimize overhead.

### Example: Image and container on-disk constructs

The following `docker pull` command shows a Docker host downloading a Docker
image comprising five layers.

```console
$ docker pull ubuntu

Using default tag: latest
latest: Pulling from library/ubuntu
b6f892c0043b: Pull complete
55010f332b04: Pull complete
2955fb827c94: Pull complete
3deef3fcbd30: Pull complete
cf9722e506aa: Pull complete
Digest: sha256:382452f82a8bbd34443b2c727650af46aced0f94a44463c62a9848133ecb1aa8
Status: Downloaded newer image for ubuntu:latest
```

#### The image layers

> [!WARNING]: Do not directly manipulate any files or directories within
> `/var/lib/docker/`. These files and directories are managed by Docker.

All of the information about the image and container layers is stored in
subdirectories of `/var/lib/docker/aufs/`.

- `diff/`: the **contents** of each layer, each stored in a separate
  subdirectory
- `layers/`: metadata about how image layers are stacked. This directory
  contains one file for each image or container layer on the Docker host. Each
  file contains the IDs of all the layers below it in the stack (its parents).
- `mnt/`: Mount points, one per image or container layer, which are used to
  assemble and mount the unified filesystem for a container. For images, which
  are read-only, these directories are always empty.

#### The container layer

If a container is running, the contents of `/var/lib/docker/aufs/` change in the
following ways:

- `diff/`: Differences introduced in the writable container layer, such as new
   or modified files.
- `layers/`: Metadata about the writable container layer's parent layers.
- `mnt/`: A mount point for each running container's unified filesystem, exactly
  as it appears from within the container.

## How container reads and writes work with `aufs`

### Reading files

Consider three scenarios where a container opens a file for read access with
aufs.

- **The file does not exist in the container layer**: If a container opens a
  file for read access and the file does not already exist in the container
  layer, the storage driver searches for the file in the image layers,
  starting with the layer just below the container layer. It is read from the
  layer where it is found.

- **The file only exists in the container layer**: If a container opens a file
  for read access and the file exists in the container layer, it is read from
  there.

- **The file exists in both the container layer and the image layer**: If a
  container opens a file for read access and the file exists in the container
  layer and one or more image layers, the file is read from the container layer.
  Files in the container layer obscure files with the same name in the image
  layers.

### Modifying files or directories

Consider some scenarios where files in a container are modified.

- **Writing to a file for the first time**: The first time a container writes
  to an existing file, that file does not exist in the container (`upperdir`).
  The `aufs` driver performs a *copy_up* operation to copy the file from the
  image layer where it exists to the writable container layer. The container
  then writes the changes to the new copy of the file in the container layer.

  However, AUFS works at the file level rather than the block level. This
  means that all copy_up operations copy the entire file, even if the file is
  very large and only a small part of it is being modified. This can have a
  noticeable impact on container write performance. AUFS can suffer
  noticeable latencies when searching for files in images with many layers.
  However, it is worth noting that the copy_up operation only occurs the first
  time a given file is written to. Subsequent writes to the same file operate
  against the copy of the file already copied up to the container.

- **Deleting files and directories**:

  - When a _file_ is deleted within a container, a *whiteout* file is created
    in the container layer. The version of the file in the image layer is not
    deleted (because the image layers are read-only). However, the whiteout
    file prevents it from being available to the container.

  - When a _directory_ is deleted within a container, an _opaque file_ is
    created in the container layer. This works in the same way as a
    whiteout file and effectively prevents the directory from being accessed,
    even though it still exists in the image layer.

- **Renaming directories**: Calling `rename(2)` for a directory is not fully
  supported on AUFS. It returns `EXDEV` ("cross-device link not permitted"),
  even when both of the source and the destination path are on a same AUFS
  layer, unless the directory has no children. Your application needs to be
  designed to handle `EXDEV` and fall back to a "copy and unlink" strategy.

## AUFS and Docker performance

To summarize some of the performance related aspects already mentioned:

- The AUFS storage driver is less performant than the `overlay2` driver, but is
  a good choice for PaaS and other similar use-cases where container density is
  important. This is because AUFS efficiently shares images between multiple
  running containers, enabling fast container start times and minimal use of
  disk space.

- The underlying mechanics of how AUFS shares files between image layers and
  containers uses the page cache very efficiently.

- The AUFS storage driver can introduce significant latencies into container
  write performance. This is because the first time a container writes to any
  file, the file needs to be located and copied into the containers top writable
  layer. These latencies increase and are compounded when these files exist below
  many image layers and the files themselves are large.

### Performance best practices

The following generic performance best practices also apply to AUFS.

- **Solid State Devices (SSD)** provide faster reads and writes than spinning
  disks.

- **Use volumes for write-heavy workloads**: Volumes provide the best and most
  predictable performance for write-heavy workloads. This is because they bypass
  the storage driver and do not incur any of the potential overheads introduced
  by thin provisioning and copy-on-write. Volumes have other benefits, such as
  allowing you to share data among containers and persisting even when no
  running container is using them.

## Related information

- [Volumes](../volumes.md)
- [Understand images, containers, and storage drivers](../../../reference/api/ai-governance/index.md)
- [Select a storage driver](select-storage-driver.md)


---

# BTRFS storage driver

*Sección: Engine*

> [!IMPORTANT]
>
> In most cases you should use the `overlay2` storage driver - it's not
> required to use the `btrfs` storage driver simply because your system uses
> Btrfs as its root filesystem.
>
> Btrfs driver has known issues. See [Moby issue #27653](https://github.com/moby/moby/issues/27653)
> for more information.

Btrfs is a copy-on-write filesystem that supports many advanced storage
technologies, making it a good fit for Docker. Btrfs is included in the
mainline Linux kernel.

Docker's `btrfs` storage driver leverages many Btrfs features for image and
container management. Among these features are block-level operations, thin
provisioning, copy-on-write snapshots, and ease of administration. You can
combine multiple physical block devices into a single Btrfs filesystem.

This page refers to Docker's Btrfs storage driver as `btrfs` and the overall
Btrfs Filesystem as Btrfs.

> [!NOTE]
>
> The `btrfs` storage driver is only supported with Docker Engine CE on SLES,
> Ubuntu, and Debian systems.

## Prerequisites

`btrfs` is supported if you meet the following prerequisites:

- `btrfs` is only recommended with Docker Engine on Ubuntu or Debian systems.

- Changing the storage driver makes any containers you have already
  created inaccessible on the local system. Use `docker save` to save containers,
  and push existing images to Docker Hub or a private repository, so that you
  do not need to re-create them later.

- `btrfs` requires a dedicated block storage device such as a physical disk. This
  block device must be formatted for Btrfs and mounted into `/var/lib/docker/`.
  The configuration instructions below walk you through this procedure. By
  default, the SLES `/` filesystem is formatted with Btrfs, so for SLES, you do
  not need to use a separate block device, but you can choose to do so for
  performance reasons.

- `btrfs` support must exist in your kernel. To check this, run the following
  command:

  ```console
  $ grep btrfs /proc/filesystems

  btrfs
  ```

- To manage Btrfs filesystems at the level of the operating system, you need the
  `btrfs` command. If you don't have this command, install the `btrfsprogs`
  package (SLES) or `btrfs-tools` package (Ubuntu).

## Configure Docker to use the btrfs storage driver

This procedure is essentially identical on SLES and Ubuntu.

1. Stop Docker.

2. Copy the contents of `/var/lib/docker/` to a backup location, then empty
   the contents of `/var/lib/docker/`:

   ```console
   $ sudo cp -au /var/lib/docker /var/lib/docker.bk
   $ sudo rm -rf /var/lib/docker/*
   ```

3. Format your dedicated block device or devices as a Btrfs filesystem. This
   example assumes that you are using two block devices called `/dev/xvdf` and
   `/dev/xvdg`. Double-check the block device names because this is a
   destructive operation.

   ```console
   $ sudo mkfs.btrfs -f /dev/xvdf /dev/xvdg
   ```

   There are many more options for Btrfs, including striping and RAID. See the
   [Btrfs documentation](https://btrfs.wiki.kernel.org/index.php/Using_Btrfs_with_Multiple_Devices).

4. Mount the new Btrfs filesystem on the `/var/lib/docker/` mount point. You
   can specify any of the block devices used to create the Btrfs filesystem.

   ```console
   $ sudo mount -t btrfs /dev/xvdf /var/lib/docker
   ```

   > [!NOTE]
   >
   > Make the change permanent across reboots by adding an entry to
   > `/etc/fstab`.

5. Copy the contents of `/var/lib/docker.bk` to `/var/lib/docker/`.

   ```console
   $ sudo cp -au /var/lib/docker.bk/* /var/lib/docker/
   ```

6. Configure Docker to use the `btrfs` storage driver. This is required even
   though `/var/lib/docker/` is now using a Btrfs filesystem.
   Edit or create the file `/etc/docker/daemon.json`. If it is a new file, add
   the following contents. If it is an existing file, add the key and value
   only, being careful to end the line with a comma if it isn't the final
   line before an ending curly bracket (`}`).

   ```json
   {
     "storage-driver": "btrfs"
   }
   ```

   See all storage options for each storage driver in the
   [daemon reference documentation](/reference/cli/dockerd/#options-per-storage-driver)

7. Start Docker. When it's running, verify that `btrfs` is being used as the
   storage driver.

   ```console
   $ docker info

   Containers: 0
    Running: 0
    Paused: 0
    Stopped: 0
   Images: 0
   Server Version: 17.03.1-ce
   Storage Driver: btrfs
    Build Version: Btrfs v4.4
    Library Version: 101
   <...>
   ```

8. When you are ready, remove the `/var/lib/docker.bk` directory.

## Manage a Btrfs volume

One of the benefits of Btrfs is the ease of managing Btrfs filesystems without
the need to unmount the filesystem or restart Docker.

When space gets low, Btrfs automatically expands the volume in chunks of
roughly 1 GB.

To add a block device to a Btrfs volume, use the `btrfs device add` and
`btrfs filesystem balance` commands.

```console
$ sudo btrfs device add /dev/svdh /var/lib/docker

$ sudo btrfs filesystem balance /var/lib/docker
```

> [!NOTE]
>
> While you can do these operations with Docker running, performance suffers.
> It might be best to plan an outage window to balance the Btrfs filesystem.

## How the `btrfs` storage driver works

The `btrfs` storage driver works differently from other
storage drivers in that your entire `/var/lib/docker/` directory is stored on a
Btrfs volume.

### Image and container layers on-disk

Information about image layers and writable container layers is stored in
`/var/lib/docker/btrfs/subvolumes/`. This subdirectory contains one directory
per image or container layer, with the unified filesystem built from a layer
plus all its parent layers. Subvolumes are natively copy-on-write and have space
allocated to them on-demand from an underlying storage pool. They can also be
nested and snapshotted. The diagram below shows 4 subvolumes. 'Subvolume 2' and
'Subvolume 3' are nested, whereas 'Subvolume 4' shows its own internal directory
tree.

![Subvolume example](images/btfs_subvolume.webp?w=350&h=100)

Only the base layer of an image is stored as a true subvolume. All the other
layers are stored as snapshots, which only contain the differences introduced
in that layer. You can create snapshots of snapshots as shown in the diagram
below.

![Snapshots diagram](images/btfs_snapshots.webp?w=350&h=100)

On disk, snapshots look and feel just like subvolumes, but in reality they are
much smaller and more space-efficient. Copy-on-write is used to maximize storage
efficiency and minimize layer size, and writes in the container's writable layer
are managed at the block level. The following image shows a subvolume and its
snapshot sharing data.

![Snapshot and subvolume sharing data](images/btfs_pool.webp?w=450&h=200)

For maximum efficiency, when a container needs more space, it is allocated in
chunks of roughly 1 GB in size.

Docker's `btrfs` storage driver stores every image layer and container in its
own Btrfs subvolume or snapshot. The base layer of an image is stored as a
subvolume whereas child image layers and containers are stored as snapshots.
This is shown in the diagram below.

![Btrfs container layers](images/btfs_container_layer.webp?w=600)

The high level process for creating images and containers on Docker hosts
running the `btrfs` driver is as follows:

1. The image's base layer is stored in a Btrfs _subvolume_ under
   `/var/lib/docker/btrfs/subvolumes`.

2. Subsequent image layers are stored as a Btrfs _snapshot_ of the parent
   layer's subvolume or snapshot, but with the changes introduced by this
   layer. These differences are stored at the block level.

3. The container's writable layer is a Btrfs snapshot of the final image layer,
   with the differences introduced by the running container. These differences
   are stored at the block level.

## How container reads and writes work with `btrfs`

### Reading files

A container is a space-efficient snapshot of an image. Metadata in the snapshot
points to the actual data blocks in the storage pool. This is the same as with
a subvolume. Therefore, reads performed against a snapshot are essentially the
same as reads performed against a subvolume.

### Writing files

As a general caution, writing and updating a large number of small files with
Btrfs can result in slow performance.

Consider three scenarios where a container opens a file for write access with
Btrfs.

#### Writing new files

Writing a new file to a container invokes an allocate-on-demand operation to
allocate new data block to the container's snapshot. The file is then written
to this new space. The allocate-on-demand operation is native to all writes
with Btrfs and is the same as writing new data to a subvolume. As a result,
writing new files to a container's snapshot operates at native Btrfs speeds.

#### Modifying existing files

Updating an existing file in a container is a copy-on-write operation
(redirect-on-write is the Btrfs terminology). The original data is read from
the layer where the file currently exists, and only the modified blocks are
written into the container's writable layer. Next, the Btrfs driver updates the
filesystem metadata in the snapshot to point to this new data. This behavior
incurs minor overhead.

#### Deleting files or directories

If a container deletes a file or directory that exists in a lower layer, Btrfs
masks the existence of the file or directory in the lower layer. If a container
creates a file and then deletes it, this operation is performed in the Btrfs
filesystem itself and the space is reclaimed.

## Btrfs and Docker performance

There are several factors that influence Docker's performance under the `btrfs`
storage driver.

> [!NOTE]
>
> Many of these factors are mitigated by using Docker volumes for write-heavy
> workloads, rather than relying on storing data in the container's writable
> layer. However, in the case of Btrfs, Docker volumes still suffer from these
> draw-backs unless `/var/lib/docker/volumes/` isn't backed by Btrfs.

### Page caching

Btrfs doesn't support page cache sharing. This means that each process
accessing the same file copies the file into the Docker host's memory. As a
result, the `btrfs` driver may not be the best choice for high-density use cases
such as PaaS.

### Small writes

Containers performing lots of small writes (this usage pattern matches what
happens when you start and stop many containers in a short period of time, as
well) can lead to poor use of Btrfs chunks. This can prematurely fill the Btrfs
filesystem and lead to out-of-space conditions on your Docker host. Use `btrfs
filesys show` to closely monitor the amount of free space on your Btrfs device.

### Sequential writes

Btrfs uses a journaling technique when writing to disk. This can impact the
performance of sequential writes, reducing performance by up to 50%.

### Fragmentation

Fragmentation is a natural byproduct of copy-on-write filesystems like Btrfs.
Many small random writes can compound this issue. Fragmentation can manifest as
CPU spikes when using SSDs or head thrashing when using spinning disks. Either
of these issues can harm performance.

If your Linux kernel version is 3.9 or higher, you can enable the `autodefrag`
feature when mounting a Btrfs volume. Test this feature on your own workloads
before deploying it into production, as some tests have shown a negative impact
on performance.

### SSD performance

Btrfs includes native optimizations for SSD media. To enable these features,
mount the Btrfs filesystem with the `-o ssd` mount option. These optimizations
include enhanced SSD write performance by avoiding optimization such as seek
optimizations that don't apply to solid-state media.

### Balance Btrfs filesystems often

Use operating system utilities such as a `cron` job to balance the Btrfs
filesystem regularly, during non-peak hours. This reclaims unallocated blocks
and helps to prevent the filesystem from filling up unnecessarily. You can't
rebalance a totally full Btrfs filesystem unless you add additional physical
block devices to the filesystem.

See the [Btrfs
Wiki](https://btrfs.wiki.kernel.org/index.php/Balance_Filters#Balancing_to_fix_filesystem_full_errors).

### Use fast storage

Solid-state drives (SSDs) provide faster reads and writes than spinning disks.

### Use volumes for write-heavy workloads

Volumes provide the best and most predictable performance for write-heavy
workloads. This is because they bypass the storage driver and don't incur any
of the potential overheads introduced by thin provisioning and copy-on-write.
Volumes have other benefits, such as allowing you to share data among
containers and persisting even when no running container is using them.

## Related Information

- [Volumes](../volumes.md)
- [Understand images, containers, and storage drivers](../../../reference/api/ai-governance/index.md)
- [Select a storage driver](select-storage-driver.md)


---

# Device Mapper storage driver (deprecated)

*Sección: Engine*

> **Deprecated**
>
> The Device Mapper driver [has been deprecated](/manuals/engine/deprecated.md#device-mapper-storage-driver),
> and is removed in Docker Engine v25.0. If you are using Device Mapper,
> you must migrate to a supported storage driver before upgrading to Docker
> Engine v25.0. Read the [Docker storage drivers](select-storage-driver.md)
> page for supported storage drivers.

Device Mapper is a kernel-based framework that underpins many advanced
volume management technologies on Linux. Docker's `devicemapper` storage driver
leverages the thin provisioning and snapshotting capabilities of this framework
for image and container management. This article refers to the Device Mapper
storage driver as `devicemapper`, and the kernel framework as _Device Mapper_.

For the systems where it is supported, `devicemapper` support is included in
the Linux kernel. However, specific configuration is required to use it with
Docker.

The `devicemapper` driver uses block devices dedicated to Docker and operates at
the block level, rather than the file level. These devices can be extended by
adding physical storage to your Docker host, and they perform better than using
a filesystem at the operating system (OS) level.

## Prerequisites

- `devicemapper` is supported on Docker Engine - Community running on CentOS, Fedora,
  SLES 15, Ubuntu, Debian, or RHEL.
- `devicemapper` requires the `lvm2` and `device-mapper-persistent-data` packages
  to be installed.
- Changing the storage driver makes any containers you have already
  created inaccessible on the local system. Use `docker save` to save containers,
  and push existing images to Docker Hub or a private repository, so you do
  not need to recreate them later.

## Configure Docker with the `devicemapper` storage driver

Before following these procedures, you must first meet all the
[prerequisites](#prerequisites).

### Configure `loop-lvm` mode for testing

This configuration is only appropriate for testing. The `loop-lvm` mode makes
use of a 'loopback' mechanism that allows files on the local disk to be
read from and written to as if they were an actual physical disk or block
device.
However, the addition of the loopback mechanism, and interaction with the OS
filesystem layer, means that IO operations can be slow and resource-intensive.
Use of loopback devices can also introduce race conditions.
However, setting up `loop-lvm` mode can help identify basic issues (such as
missing user space packages, kernel drivers, etc.) ahead of attempting the more
complex set up required to enable `direct-lvm` mode. `loop-lvm` mode should
therefore only be used to perform rudimentary testing prior to configuring
`direct-lvm`.

For production systems, see
[Configure direct-lvm mode for production](#configure-direct-lvm-mode-for-production).

1. Stop Docker.

   ```console
   $ sudo systemctl stop docker
   ```

2.  Edit `/etc/docker/daemon.json`. If it does not yet exist, create it. Assuming
    that the file was empty, add the following contents.

    ```json
    {
      "storage-driver": "devicemapper"
    }
    ```

    See all storage options for each storage driver in the
    [daemon reference documentation](/reference/cli/dockerd/#options-per-storage-driver)

    Docker does not start if the `daemon.json` file contains badly-formed JSON.

3.  Start Docker.

    ```console
    $ sudo systemctl start docker
    ```

4.  Verify that the daemon is using the `devicemapper` storage driver. Use the
    `docker info` command and look for `Storage Driver`.

    ```console
    $ docker info

      Containers: 0
        Running: 0
        Paused: 0
        Stopped: 0
      Images: 0
      Server Version: 17.03.1-ce
      Storage Driver: devicemapper
      Pool Name: docker-202:1-8413957-pool
      Pool Blocksize: 65.54 kB
      Base Device Size: 10.74 GB
      Backing Filesystem: xfs
      Data file: /dev/loop0
      Metadata file: /dev/loop1
      Data Space Used: 11.8 MB
      Data Space Total: 107.4 GB
      Data Space Available: 7.44 GB
      Metadata Space Used: 581.6 KB
      Metadata Space Total: 2.147 GB
      Metadata Space Available: 2.147 GB
      Thin Pool Minimum Free Space: 10.74 GB
      Udev Sync Supported: true
      Deferred Removal Enabled: false
      Deferred Deletion Enabled: false
      Deferred Deleted Device Count: 0
      Data loop file: /var/lib/docker/devicemapper/data
      Metadata loop file: /var/lib/docker/devicemapper/metadata
      Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    ```

  This host is running in `loop-lvm` mode, which is **not** supported on
  production systems. This is indicated by the fact that the `Data loop file`
  and a `Metadata loop file` are on files under
  `/var/lib/docker/devicemapper`. These are loopback-mounted
  sparse files. For production systems, see
  [Configure direct-lvm mode for production](#configure-direct-lvm-mode-for-production).


### Configure direct-lvm mode for production

Production hosts using the `devicemapper` storage driver must use `direct-lvm`
mode. This mode uses block devices to create the thin pool. This is faster than
using loopback devices, uses system resources more efficiently, and block
devices can grow as needed. However, more setup is required than in `loop-lvm`
mode.

After you have satisfied the [prerequisites](#prerequisites), follow the steps
below to configure Docker to use the `devicemapper` storage driver in
`direct-lvm` mode.

> [!WARNING]
> Changing the storage driver makes any containers you have already
> created inaccessible on the local system. Use `docker save` to save containers,
> and push existing images to Docker Hub or a private repository, so you do not
> need to recreate them later.

#### Allow Docker to configure direct-lvm mode

Docker can manage the block device for you, simplifying configuration of `direct-lvm`
mode. **This is appropriate for fresh Docker setups only.** You can only use a
single block device. If you need to use multiple block devices,
[configure direct-lvm mode manually](#configure-direct-lvm-mode-manually) instead.
The following new configuration options are available:

| Option                          | Description                                                                                                                                                                        | Required? | Default | Example                            |
|:--------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------|:--------|:-----------------------------------|
| `dm.directlvm_device`           | The path to the block device to configure for `direct-lvm`.                                                                                                                        | Yes       |         | `dm.directlvm_device="/dev/xvdf"`  |
| `dm.thinp_percent`              | The percentage of space to use for storage from the passed in block device.                                                                                                        | No        | 95      | `dm.thinp_percent=95`              |
| `dm.thinp_metapercent`          | The percentage of space to use for metadata storage from the passed-in block device.                                                                                                   | No        | 1       | `dm.thinp_metapercent=1`           |
| `dm.thinp_autoextend_threshold` | The threshold for when lvm should automatically extend the thin pool as a percentage of the total storage space.                                                                   | No        | 80      | `dm.thinp_autoextend_threshold=80` |
| `dm.thinp_autoextend_percent`   | The percentage to increase the thin pool by when an autoextend is triggered.                                                                                                       | No        | 20      | `dm.thinp_autoextend_percent=20`   |
| `dm.directlvm_device_force`     | Whether to format the block device even if a filesystem already exists on it. If set to `false` and a filesystem is present, an error is logged and the filesystem is left intact. | No        | false   | `dm.directlvm_device_force=true`   |

Edit the `daemon.json` file and set the appropriate options, then restart Docker
for the changes to take effect. The following `daemon.json` configuration sets all of the
options in the table above.

```json
{
  "storage-driver": "devicemapper",
  "storage-opts": [
    "dm.directlvm_device=/dev/xdf",
    "dm.thinp_percent=95",
    "dm.thinp_metapercent=1",
    "dm.thinp_autoextend_threshold=80",
    "dm.thinp_autoextend_percent=20",
    "dm.directlvm_device_force=false"
  ]
}
```

See all storage options for each storage driver in the
[daemon reference documentation](/reference/cli/dockerd/#options-per-storage-driver)

Restart Docker for the changes to take effect. Docker invokes the commands to
configure the block device for you.

> [!WARNING]
> Changing these values after Docker has prepared the block device for you is
> not supported and causes an error.

You still need to [perform periodic maintenance tasks](#manage-devicemapper).

#### Configure direct-lvm mode manually

The procedure below creates a logical volume configured as a thin pool to
use as backing for the storage pool. It assumes that you have a spare block
device at `/dev/xvdf` with enough free space to complete the task. The device
identifier and volume sizes may be different in your environment and you
should substitute your own values throughout the procedure. The procedure also
assumes that the Docker daemon is in the `stopped` state.

1.  Identify the block device you want to use. The device is located under
    `/dev/` (such as `/dev/xvdf`) and needs enough free space to store the
    images and container layers for the workloads that host runs.
    A solid state drive is ideal.

2.  Stop Docker.

    ```console
    $ sudo systemctl stop docker
    ```

3.  Install the following packages:

    - **RHEL / CentOS**: `device-mapper-persistent-data`, `lvm2`, and all
      dependencies

    - **Ubuntu / Debian / SLES 15**: `thin-provisioning-tools`, `lvm2`, and all
      dependencies

4.  Create a physical volume on your block device from step 1, using the
    `pvcreate` command. Substitute your device name for `/dev/xvdf`.

    > [!WARNING]
    > The next few steps are destructive, so be sure that you have specified
    > the correct device.

    ```console
    $ sudo pvcreate /dev/xvdf

    Physical volume "/dev/xvdf" successfully created.
    ```

5.  Create a `docker` volume group on the same device, using the `vgcreate`
    command.

    ```console
    $ sudo vgcreate docker /dev/xvdf

    Volume group "docker" successfully created
    ```

6.  Create two logical volumes named `thinpool` and `thinpoolmeta` using the
    `lvcreate` command. The last parameter specifies the amount of free space
    to allow for automatic expanding of the data or metadata if space runs low,
    as a temporary stop-gap. These are the recommended values.

    ```console
    $ sudo lvcreate --wipesignatures y -n thinpool docker -l 95%VG

    Logical volume "thinpool" created.

    $ sudo lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG

    Logical volume "thinpoolmeta" created.
    ```

7.  Convert the volumes to a thin pool and a storage location for metadata for
    the thin pool, using the `lvconvert` command.

    ```console
    $ sudo lvconvert -y \
    --zero n \
    -c 512K \
    --thinpool docker/thinpool \
    --poolmetadata docker/thinpoolmeta

    WARNING: Converting logical volume docker/thinpool and docker/thinpoolmeta to
    thin pool's data and metadata volumes with metadata wiping.
    THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)
    Converted docker/thinpool to thin pool.
    ```

8.  Configure autoextension of thin pools via an `lvm` profile.

    ```console
    $ sudo vi /etc/lvm/profile/docker-thinpool.profile
    ```

9.  Specify `thin_pool_autoextend_threshold` and `thin_pool_autoextend_percent`
    values.

    `thin_pool_autoextend_threshold` is the percentage of space used before `lvm`
    attempts to autoextend the available space (100 = disabled, not recommended).

    `thin_pool_autoextend_percent` is the amount of space to add to the device
    when automatically extending (0 = disabled).

    The example below adds 20% more capacity when the disk usage reaches
    80%.

    ```text
    activation {
      thin_pool_autoextend_threshold=80
      thin_pool_autoextend_percent=20
    }
    ```

    Save the file.

10. Apply the LVM profile, using the `lvchange` command.

    ```console
    $ sudo lvchange --metadataprofile docker-thinpool docker/thinpool

    Logical volume docker/thinpool changed.
    ```

11. Ensure monitoring of the logical volume is enabled.

    ```console
    $ sudo lvs -o+seg_monitor

    LV       VG     Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor
    thinpool docker twi-a-t--- 95.00g             0.00   0.01                             not monitored
    ```

    If the output in the `Monitor` column reports, as above, that the volume is
    `not monitored`, then monitoring needs to be explicitly enabled. Without
    this step, automatic extension of the logical volume will not occur,
    regardless of any settings in the applied profile.

    ```console
    $ sudo lvchange --monitor y docker/thinpool
    ```

    Double check that monitoring is now enabled by running the
    `sudo lvs -o+seg_monitor` command a second time. The `Monitor` column
    should now report the logical volume is being `monitored`.

12. If you have ever run Docker on this host before, or if `/var/lib/docker/`
    exists, move it out of the way so that Docker can use the new LVM pool to
    store the contents of image and containers.

    ```console
    $ sudo su -
    # mkdir /var/lib/docker.bk
    # mv /var/lib/docker/* /var/lib/docker.bk
    # exit
    ```

    If any of the following steps fail and you need to restore, you can remove
    `/var/lib/docker` and replace it with `/var/lib/docker.bk`.

13. Edit `/etc/docker/daemon.json` and configure the options needed for the
    `devicemapper` storage driver. If the file was previously empty, it should
    now contain the following contents:

    ```json
    {
        "storage-driver": "devicemapper",
        "storage-opts": [
        "dm.thinpooldev=/dev/mapper/docker-thinpool",
        "dm.use_deferred_removal=true",
        "dm.use_deferred_deletion=true"
        ]
    }
    ```

14. Start Docker.

    **systemd**:

    ```console
    $ sudo systemctl start docker
    ```

    **service**:

    ```console
    $ sudo service docker start
    ```

15. Verify that Docker is using the new configuration using `docker info`.

    ```console
    $ docker info

    Containers: 0
     Running: 0
     Paused: 0
     Stopped: 0
    Images: 0
    Server Version: 17.03.1-ce
    Storage Driver: devicemapper
     Pool Name: docker-thinpool
     Pool Blocksize: 524.3 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file:
     Metadata file:
     Data Space Used: 19.92 MB
     Data Space Total: 102 GB
     Data Space Available: 102 GB
     Metadata Space Used: 147.5 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
     Thin Pool Minimum Free Space: 10.2 GB
     Udev Sync Supported: true
     Deferred Removal Enabled: true
     Deferred Deletion Enabled: true
     Deferred Deleted Device Count: 0
     Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    ```

    If Docker is configured correctly, the `Data file` and `Metadata file` is
    blank, and the pool name is `docker-thinpool`.

16. After you have verified that the configuration is correct, you can remove the
    `/var/lib/docker.bk` directory which contains the previous configuration.

    ```console
    $ sudo rm -rf /var/lib/docker.bk
    ```

## Manage devicemapper

### Monitor the thin pool

Do not rely on LVM auto-extension alone. The volume group
automatically extends, but the volume can still fill up. You can monitor
free space on the volume using `lvs` or `lvs -a`. Consider using a monitoring
tool at the OS level, such as Nagios.

To view the LVM logs, you can use `journalctl`:

```console
$ sudo journalctl -fu dm-event.service
```

If you run into repeated problems with thin pool, you can set the storage option
`dm.min_free_space` to a value (representing a percentage) in
`/etc/docker/daemon.json`. For instance, setting it to `10` ensures
that operations fail with a warning when the free space is at or near 10%.
See the
[storage driver options in the Engine daemon reference](/reference/cli/dockerd/#daemon-storage-driver).

### Increase capacity on a running device

You can increase the capacity of the pool on a running thin-pool device. This is
useful if the data's logical volume is full and the volume group is at full
capacity. The specific procedure depends on whether you are using a
[loop-lvm thin pool](#resize-a-loop-lvm-thin-pool) or a
[direct-lvm thin pool](#resize-a-direct-lvm-thin-pool).

#### Resize a loop-lvm thin pool

The easiest way to resize a `loop-lvm` thin pool is to
[use the device_tool utility](#use-the-device_tool-utility),
but you can [use operating system utilities](#use-operating-system-utilities)
instead.

##### Use the device_tool utility

A community-contributed script called `device_tool.go` is available in the
[moby/moby](https://github.com/moby/moby/tree/master/contrib/docker-device-tool)
Github repository. You can use this tool to resize a `loop-lvm` thin pool,
avoiding the long process above. This tool is not guaranteed to work, but you
should only be using `loop-lvm` on non-production systems.

If you do not want to use `device_tool`, you can [resize the thin pool manually](#use-operating-system-utilities) instead.

1.  To use the tool, clone the Github repository, change to the
    `contrib/docker-device-tool`, and follow the instructions in the `README.md`
    to compile the tool.

2.  Use the tool. The following example resizes the thin pool to 200GB.

    ```console
    $ ./device_tool resize 200GB
    ```

##### Use operating system utilities

If you do not want to [use the device-tool utility](#use-the-device_tool-utility),
you can resize a `loop-lvm` thin pool manually using the following procedure.

In `loop-lvm` mode, a loopback device is used to store the data, and another
to store the metadata. `loop-lvm` mode is only supported for testing, because
it has significant performance and stability drawbacks.

If you are using `loop-lvm` mode, the output of `docker info` shows file
paths for `Data loop file` and `Metadata loop file`:

```console
$ docker info |grep 'loop file'

 Data loop file: /var/lib/docker/devicemapper/data
 Metadata loop file: /var/lib/docker/devicemapper/metadata
```

Follow these steps to increase the size of the thin pool. In this example, the
thin pool is 100 GB, and is increased to 200 GB.

1.  List the sizes of the devices.

    ```console
    $ sudo ls -lh /var/lib/docker/devicemapper/

    total 1175492
    -rw------- 1 root root 100G Mar 30 05:22 data
    -rw------- 1 root root 2.0G Mar 31 11:17 metadata
    ```

2.  Increase the size of the `data` file to 200 G using the `truncate` command,
    which is used to increase **or** decrease the size of a file. Note that
    decreasing the size is a destructive operation.

    ```console
    $ sudo truncate -s 200G /var/lib/docker/devicemapper/data
    ```

3.  Verify the file size changed.

    ```console
    $ sudo ls -lh /var/lib/docker/devicemapper/

    total 1.2G
    -rw------- 1 root root 200G Apr 14 08:47 data
    -rw------- 1 root root 2.0G Apr 19 13:27 metadata
    ```

4.  The loopback file has changed on disk but not in memory. List the size of
    the loopback device in memory, in GB. Reload it, then list the size again.
    After the reload, the size is 200 GB.

    ```console
    $ echo $[ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 ]

    100

    $ sudo losetup -c /dev/loop0

    $ echo $[ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 ]

    200
    ```

5.  Reload the devicemapper thin pool.

    a. Get the pool name first. The pool name is the first field, delimited by
    `:`. This command extracts it.

    ```console
    $ sudo dmsetup status | grep ' thin-pool ' | awk -F ': ' {'print $1'}
    docker-8:1-123141-pool
    ```

    b. Dump the device mapper table for the thin pool.

    ```console
    $ sudo dmsetup table docker-8:1-123141-pool
    0 209715200 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing
    ```

    c. Calculate the total sectors of the thin pool using the second field
    of the output. The number is expressed in 512-k sectors. A 100G file has
    209715200 512-k sectors. If you double this number to 200G, you get
    419430400 512-k sectors.

    d. Reload the thin pool with the new sector number, using the following
    three `dmsetup`  commands.

    ```console
    $ sudo dmsetup suspend docker-8:1-123141-pool
    $ sudo dmsetup reload docker-8:1-123141-pool --table '0 419430400 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing'
    $ sudo dmsetup resume docker-8:1-123141-pool
    ```

#### Resize a direct-lvm thin pool

To extend a `direct-lvm` thin pool, you need to first attach a new block device
to the Docker host, and make note of the name assigned to it by the kernel. In
this example, the new block device is `/dev/xvdg`.

Follow this procedure to extend a `direct-lvm` thin pool, substituting your
block device and other parameters to suit your situation.

1.  Gather information about your volume group.

    Use the `pvdisplay` command to find the physical block devices currently in
    use by your thin pool, and the volume group's name.

    ```console
    $ sudo pvdisplay |grep 'VG Name'

    PV Name               /dev/xvdf
    VG Name               docker
    ```

    In the following steps, substitute your block device or volume group name as
    appropriate.

2.  Extend the volume group, using the `vgextend` command with the `VG Name`
    from the previous step, and the name of your **new** block device.

    ```console
    $ sudo vgextend docker /dev/xvdg

    Physical volume "/dev/xvdg" successfully created.
    Volume group "docker" successfully extended
    ```

3.  Extend the `docker/thinpool` logical volume. This command uses 100% of the
    volume right away, without auto-extend. To extend the metadata thinpool
    instead, use `docker/thinpool_tmeta`.

    ```console
    $ sudo lvextend -l+100%FREE -n docker/thinpool

    Size of logical volume docker/thinpool_tdata changed from 95.00 GiB (24319 extents) to 198.00 GiB (50688 extents).
    Logical volume docker/thinpool_tdata successfully resized.
    ```

4.  Verify the new thin pool size using the `Data Space Available` field in the
    output of `docker info`. If you extended the `docker/thinpool_tmeta` logical
    volume instead, look for `Metadata Space Available`.

    ```bash
    Storage Driver: devicemapper
     Pool Name: docker-thinpool
     Pool Blocksize: 524.3 kB
     Base Device Size: 10.74 GB
     Backing Filesystem: xfs
     Data file:
     Metadata file:
     Data Space Used: 212.3 MB
     Data Space Total: 212.6 GB
     Data Space Available: 212.4 GB
     Metadata Space Used: 286.7 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
    <...>
    ```

### Activate the `devicemapper` after reboot

If you reboot the host and find that the `docker` service failed to start,
look for the error, "Non existing device". You need to re-activate the
logical volumes with this command:

```console
$ sudo lvchange -ay docker/thinpool
```

## How the `devicemapper` storage driver works

> [!WARNING]
> Do not directly manipulate any files or directories within
> `/var/lib/docker/`. These files and directories are managed by Docker.

Use the `lsblk` command to see the devices and their pools, from the operating
system's point of view:

```console
$ sudo lsblk

NAME                    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda                    202:0    0    8G  0 disk
└─xvda1                 202:1    0    8G  0 part /
xvdf                    202:80   0  100G  0 disk
├─docker-thinpool_tmeta 253:0    0 1020M  0 lvm
│ └─docker-thinpool     253:2    0   95G  0 lvm
└─docker-thinpool_tdata 253:1    0   95G  0 lvm
  └─docker-thinpool     253:2    0   95G  0 lvm
```

Use the `mount` command to see the mount-point Docker is using:

```console
$ mount |grep devicemapper
/dev/xvda1 on /var/lib/docker/devicemapper type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
```

When you use `devicemapper`, Docker stores image and layer contents in the
thinpool, and exposes them to containers by mounting them under
subdirectories of `/var/lib/docker/devicemapper/`.

### Image and container layers on-disk

The `/var/lib/docker/devicemapper/metadata/` directory contains metadata about
the Devicemapper configuration itself and about each image and container layer
that exist. The `devicemapper` storage driver uses snapshots, and this metadata
include information about those snapshots. These files are in JSON format.

The `/var/lib/docker/devicemapper/mnt/` directory contains a mount point for each image
and container layer that exists. Image layer mount points are empty, but a
container's mount point shows the container's filesystem as it appears from
within the container.


### Image layering and sharing

The `devicemapper` storage driver uses dedicated block devices rather than
formatted filesystems, and operates on files at the block level for maximum
performance during copy-on-write (CoW) operations.

#### Snapshots

Another feature of `devicemapper` is its use of snapshots (also sometimes called
_thin devices_ or _virtual devices_), which store the differences introduced in
each layer as very small, lightweight thin pools. Snapshots provide many
benefits:

- Layers which are shared in common between containers are only stored on disk
  once, unless they are writable. For instance, if you have 10 different
  images which are all based on `alpine`, the `alpine` image and all its
  parent images are only stored once each on disk.

- Snapshots are an implementation of a copy-on-write (CoW) strategy. This means
  that a given file or directory is only copied to the container's writable
  layer when it is modified or deleted by that container.

- Because `devicemapper` operates at the block level, multiple blocks in a
  writable layer can be modified simultaneously.

- Snapshots can be backed up using standard OS-level backup utilities. Just
  make a copy of `/var/lib/docker/devicemapper/`.

#### Devicemapper workflow

When you start Docker with the `devicemapper` storage driver, all objects
related to image and container layers are stored in
`/var/lib/docker/devicemapper/`, which is backed by one or more block-level
devices, either loopback devices (testing only) or physical disks.

- The _base device_ is the lowest-level object. This is the thin pool itself.
  You can examine it using `docker info`. It contains a filesystem. This base
  device is the starting point for every image and container layer. The base
  device is a Device Mapper implementation detail, rather than a Docker layer.

- Metadata about the base device and each image or container layer is stored in
  `/var/lib/docker/devicemapper/metadata/` in JSON format. These layers are
  copy-on-write snapshots, which means that they are empty until they diverge
  from their parent layers.

- Each container's writable layer is mounted on a mountpoint in
  `/var/lib/docker/devicemapper/mnt/`. An empty directory exists for each
  read-only image layer and each stopped container.

Each image layer is a snapshot of the layer below it. The lowest layer of each
image is a snapshot of the base device that exists in the pool. When you run a
container, it is a snapshot of the image the container is based on. The following
example shows a Docker host with two running containers. The first is a `ubuntu`
container and the second is a `busybox` container.

![Ubuntu and busybox image layers](images/two_dm_container.webp?w=450&h=100)

## How container reads and writes work with `devicemapper`

### Reading files

With `devicemapper`, reads happen at the block level. The diagram below shows
the high level process for reading a single block (`0x44f`) in an example
container.

![Reading a block with devicemapper](images/dm_container.webp?w=650)

An application makes a read request for block `0x44f` in the container. Because
the container is a thin snapshot of an image, it doesn't have the block, but it
has a pointer to the block on the nearest parent image where it does exist, and
it reads the block from there. The block now exists in the container's memory.

### Writing files

**Writing a new file**: With the `devicemapper` driver, writing new data to a
container is accomplished by an *allocate-on-demand* operation. Each block of
the new file is allocated in the container's writable layer and the block is
written there.

**Updating an existing file**: The relevant block of the file is read from the
nearest layer where it exists. When the container writes the file, only the
modified blocks are written to the container's writable layer.

**Deleting a file or directory**: When you delete a file or directory in a
container's writable layer, or when an image layer deletes a file that exists
in its parent layer, the `devicemapper` storage driver intercepts further read
attempts on that file or directory and responds that the file or directory does
not exist.

**Writing and then deleting a file**: If a container writes to a file and later
deletes the file, all of those operations happen in the container's writable
layer. In that case, if you are using `direct-lvm`, the blocks are freed. If you
use `loop-lvm`, the blocks may not be freed. This is another reason not to use
`loop-lvm` in production.

## Device Mapper and Docker performance

- **`allocate-on demand` performance impact**:

  The `devicemapper` storage driver uses an `allocate-on-demand` operation to
  allocate new blocks from the thin pool into a container's writable layer.
  Each block is 64KB, so this is the minimum amount of space that is used
  for a write.

- **Copy-on-write performance impact**: The first time a container modifies a
  specific block, that block is written to the container's writable layer.
  Because these writes happen at the level of the block rather than the file,
  performance impact is minimized. However, writing a large number of blocks can
  still negatively impact performance, and the `devicemapper` storage driver may
  actually perform worse than other storage drivers in this scenario. For
  write-heavy workloads, you should use data volumes, which bypass the storage
  driver completely.

### Performance best practices

Keep these things in mind to maximize performance when using the `devicemapper`
storage driver.

- **Use `direct-lvm`**: The `loop-lvm` mode is not performant and should never
  be used in production.

- **Use fast storage**:  Solid-state drives (SSDs) provide faster reads and
  writes than spinning disks.

- **Memory usage**: the `devicemapper` uses more memory than some other storage
  drivers. Each launched container loads one or more copies of its files into
  memory, depending on how many blocks of the same file are being modified at
  the same time. Due to the memory pressure, the `devicemapper` storage driver
  may not be the right choice for certain workloads in high-density use cases.

- **Use volumes for write-heavy workloads**: Volumes provide the best and most
  predictable performance for write-heavy workloads. This is because they bypass
  the storage driver and do not incur any of the potential overheads introduced
  by thin provisioning and copy-on-write. Volumes have other benefits, such as
  allowing you to share data among containers and persisting even when no
  running container is using them.

  > [!NOTE]
  >
  > When using `devicemapper` and the `json-file` log driver, the log files generated by a container are still stored in Docker's dataroot directory, by default `/var/lib/docker`.  If your containers generate lots of log messages, this may lead to increased disk usage or the inability to manage your system due to a full disk. You can configure a [log driver](../../logging/configure.md) to store your container logs externally.

## Related Information

- [Volumes](../volumes.md)
- [Understand images, containers, and storage drivers](index.md)
- [Select a storage driver](select-storage-driver.md)


---

# OverlayFS storage driver

*Sección: Engine*

OverlayFS is a union filesystem.

This page refers to the Linux kernel driver as `OverlayFS` and to the Docker
storage driver as `overlay2`.

> [!NOTE]
> Docker Engine 29.0 and later uses the
> [containerd image store](../containerd.md) by default.
> The `overlay2` driver is a legacy storage driver that is superseded by the
> `overlayfs` containerd snapshotter. For more information, see
> [Select a storage driver](select-storage-driver.md).

> [!NOTE]
> For `fuse-overlayfs` driver, check [Rootless mode documentation](/manuals/engine/security/rootless.md).

## Prerequisites

The `overlay2` driver is supported if you meet the following prerequisites:

- Version 4.0 or higher of the Linux kernel, or RHEL or CentOS using
  version 3.10.0-514 of the kernel or higher.
- The `overlay2` driver is supported on `xfs` backing filesystems,
  but only with `d_type=true` enabled.

  Use `xfs_info` to verify that the `ftype` option is set to `1`. To format an
  `xfs` filesystem correctly, use the flag `-n ftype=1`.

- Changing the storage driver makes existing containers and images inaccessible
  on the local system. Use `docker save` to save any images you have built or
  push them to Docker Hub or a private registry before changing the storage driver,
  so that you don't need to re-create them later.

## Configure Docker with the `overlay2` storage driver

<a name="configure-docker-with-the-overlay-or-overlay2-storage-driver"></a>

Before following this procedure, you must first meet all the
[prerequisites](#prerequisites).

The following steps outline how to configure the `overlay2` storage driver.

1. Stop Docker.

   ```console
   $ sudo systemctl stop docker
   ```

2. Copy the contents of `/var/lib/docker` to a temporary location.

   ```console
   $ cp -au /var/lib/docker /var/lib/docker.bk
   ```

3. If you want to use a separate backing filesystem from the one used by
   `/var/lib/`, format the filesystem and mount it into `/var/lib/docker`.
   Make sure to add this mount to `/etc/fstab` to make it permanent.

4. Edit `/etc/docker/daemon.json`. If it doesn't yet exist, create it. Assuming
   that the file was empty, add the following contents.

   ```json
   {
     "storage-driver": "overlay2"
   }
   ```

   Docker doesn't start if the `daemon.json` file contains invalid JSON.

5. Start Docker.

   ```console
   $ sudo systemctl start docker
   ```

6. Verify that the daemon is using the `overlay2` storage driver.
   Use the `docker info` command and look for `Storage Driver` and
   `Backing filesystem`.

   ```console
   $ docker info

   Containers: 0
   Images: 0
   Storage Driver: overlay2
    Backing Filesystem: xfs
    Supports d_type: true
    Native Overlay Diff: true
   <...>
   ```

Docker is now using the `overlay2` storage driver and has automatically
created the overlay mount with the required `lowerdir`, `upperdir`, `merged`,
and `workdir` constructs.

Continue reading for details about how OverlayFS works within your Docker
containers, as well as performance advice and information about limitations of
its compatibility with different backing filesystems.

## How the `overlay2` driver works

OverlayFS layers two directories on a single Linux host and presents them as
a single directory. These directories are called layers, and the unification
process is referred to as a union mount. OverlayFS refers to the lower directory
as `lowerdir` and the upper directory as `upperdir`. The unified view is exposed
through its own directory called `merged`.

The `overlay2` driver natively supports up to 128 lower OverlayFS layers. This
capability provides better performance for layer-related Docker commands such
as `docker build` and `docker commit`, and consumes fewer inodes on the backing
filesystem.

### Image and container layers on-disk

After downloading a five-layer image using `docker pull ubuntu`, you can see
six directories under `/var/lib/docker/overlay2`.

> [!WARNING]
>
> Don't directly manipulate any files or directories within
> `/var/lib/docker/`. These files and directories are managed by Docker.

```console
$ ls -l /var/lib/docker/overlay2

total 24
drwx------ 5 root root 4096 Jun 20 07:36 223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7
drwx------ 3 root root 4096 Jun 20 07:36 3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b
drwx------ 5 root root 4096 Jun 20 07:36 4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1
drwx------ 5 root root 4096 Jun 20 07:36 e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5
drwx------ 5 root root 4096 Jun 20 07:36 eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed
drwx------ 2 root root 4096 Jun 20 07:36 l
```

The new `l` (lowercase `L`) directory contains shortened layer identifiers as
symbolic links. These identifiers are used to avoid hitting the page size
limitation on arguments to the `mount` command.

```console
$ ls -l /var/lib/docker/overlay2/l

total 20
lrwxrwxrwx 1 root root 72 Jun 20 07:36 6Y5IM2XC7TSNIJZZFLJCS6I4I4 -> ../3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 B3WWEFKBG3PLLV737KZFIASSW7 -> ../4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 JEYMODZYFCZFYSDABYXD5MF6YO -> ../eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 NFYKDW6APBCCUCTOUSYDH4DXAT -> ../223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 UL2MW33MSE3Q5VYIKBRN4ZAGQP -> ../e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5/diff
```

The lowest layer contains a file called `link`, which contains the name of the
shortened identifier, and a directory called `diff` which contains the
layer's contents.

```console
$ ls /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/

diff  link

$ cat /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/link

6Y5IM2XC7TSNIJZZFLJCS6I4I4

$ ls  /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff

bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
```

The second-lowest layer, and each higher layer, contain a file called `lower`,
which denotes its parent, and a directory called `diff` which contains its
contents. It also contains a `merged` directory, which contains the unified
contents of its parent layer and itself, and a `work` directory which is used
internally by OverlayFS.

```console
$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7

diff  link  lower  merged  work

$ cat /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/lower

l/6Y5IM2XC7TSNIJZZFLJCS6I4I4

$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff/

etc  sbin  usr  var
```

To view the mounts which exist when you use the `overlay` storage driver with
Docker, use the `mount` command. The output below is truncated for readability.

```console
$ mount | grep overlay

overlay on /var/lib/docker/overlay2/9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/merged
type overlay (rw,relatime,
lowerdir=l/DJA75GUWHWG7EWICFYX54FIOVT:l/B3WWEFKBG3PLLV737KZFIASSW7:l/JEYMODZYFCZFYSDABYXD5MF6YO:l/UL2MW33MSE3Q5VYIKBRN4ZAGQP:l/NFYKDW6APBCCUCTOUSYDH4DXAT:l/6Y5IM2XC7TSNIJZZFLJCS6I4I4,
upperdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/diff,
workdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/work)
```

The `rw` on the second line shows that the `overlay` mount is read-write.

The following diagram shows how a Docker image and a Docker container are
layered. The image layer is the `lowerdir` and the container layer is the
`upperdir`. If the image has multiple layers, multiple `lowerdir` directories
are used. The unified view is exposed through a directory called `merged` which
is effectively the containers mount point.

![How Docker constructs map to OverlayFS constructs](images/overlay_constructs.webp)

Where the image layer and the container layer contain the same files, the
container layer (`upperdir`) takes precedence and obscures the existence of the
same files in the image layer.

To create a container, the `overlay2` driver combines the directory representing
the image's top layer plus a new directory for the container. The image's
layers are the `lowerdirs` in the overlay and are read-only. The new directory for
the container is the `upperdir` and is writable.

### Image and container layers on-disk (legacy overlay driver)

The following `docker pull` command shows a Docker host downloading a Docker
image comprising five layers.

```console
$ docker pull ubuntu

Using default tag: latest
latest: Pulling from library/ubuntu

5ba4f30e5bea: Pull complete
9d7d19c9dc56: Pull complete
ac6ad7efd0f9: Pull complete
e7491a747824: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:46fb5d001b88ad904c5c732b086b596b92cfb4a4840a3abd0e35dbb6870585e4
Status: Downloaded newer image for ubuntu:latest
```

#### The image layers

Each image layer has its own directory within `/var/lib/docker/overlay/`, which
contains its contents, as shown in the following example. The image layer IDs
don't correspond to the directory IDs.

> [!WARNING]
>
> Don't directly manipulate any files or directories within
> `/var/lib/docker/`. These files and directories are managed by Docker.

```console
$ ls -l /var/lib/docker/overlay/

total 20
drwx------ 3 root root 4096 Jun 20 16:11 38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8
drwx------ 3 root root 4096 Jun 20 16:11 55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
drwx------ 3 root root 4096 Jun 20 16:11 824c8a961a4f5e8fe4f4243dab57c5be798e7fd195f6d88ab06aea92ba931654
drwx------ 3 root root 4096 Jun 20 16:11 ad0fe55125ebf599da124da175174a4b8c1878afe6907bf7c78570341f308461
drwx------ 3 root root 4096 Jun 20 16:11 edab9b5e5bf73f2997524eebeac1de4cf9c8b904fa8ad3ec43b3504196aa3801
```

The image layer directories contain the files unique to that layer as well as
hard links to the data shared with lower layers. This allows for efficient use
of disk space.

```console
$ ls -i /var/lib/docker/overlay2/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls

19793696 /var/lib/docker/overlay2/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls

$ ls -i /var/lib/docker/overlay2/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls

19793696 /var/lib/docker/overlay2/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls
```

#### The container layer

Containers also exist on-disk in the Docker host's filesystem under
`/var/lib/docker/overlay/`. If you list a running container's subdirectory
using the `ls -l` command, three directories and one file exist:

```console
$ ls -l /var/lib/docker/overlay2/<directory-of-running-container>

total 16
-rw-r--r-- 1 root root   64 Jun 20 16:39 lower-id
drwxr-xr-x 1 root root 4096 Jun 20 16:39 merged
drwxr-xr-x 4 root root 4096 Jun 20 16:39 upper
drwx------ 3 root root 4096 Jun 20 16:39 work
```

The `lower-id` file contains the ID of the top layer of the image the container
is based on, which is the OverlayFS `lowerdir`.

```console
$ cat /var/lib/docker/overlay2/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id

55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
```

The `upper` directory contains the contents of the container's read-write layer,
which corresponds to the OverlayFS `upperdir`.

The `merged` directory is the union mount of the `lowerdir` and `upperdirs`, which
comprises the view of the filesystem from within the running container.

The `work` directory is internal to OverlayFS.

To view the mounts which exist when you use the `overlay2` storage driver with
Docker, use the `mount` command. The following output is truncated for
readability.

```console
$ mount | grep overlay

overlay on /var/lib/docker/overlay2/l/ec444863a55a.../merged
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/55f1e14c361b.../root,
upperdir=/var/lib/docker/overlay2/l/ec444863a55a.../upper,
workdir=/var/lib/docker/overlay2/l/ec444863a55a.../work)
```

The `rw` on the second line shows that the `overlay` mount is read-write.

## How container reads and writes work with `overlay2`

<a name="how-container-reads-and-writes-work-with-overlay-or-overlay2"></a>

### Reading files

Consider three scenarios where a container opens a file for read access with
overlay.

#### The file does not exist in the container layer

If a container opens a file for read access and the file does not already exist
in the container (`upperdir`) it is read from the image (`lowerdir`). This
incurs very little performance overhead.

#### The file only exists in the container layer

If a container opens a file for read access and the file exists in the
container (`upperdir`) and not in the image (`lowerdir`), it's read directly
from the container.

#### The file exists in both the container layer and the image layer

If a container opens a file for read access and the file exists in the image
layer and the container layer, the file's version in the container layer is
read. Files in the container layer (`upperdir`) obscure files with the same
name in the image layer (`lowerdir`).

### Modifying files or directories

Consider some scenarios where files in a container are modified.

#### Writing to a file for the first time

The first time a container writes to an existing file, that file does not
exist in the container (`upperdir`). The `overlay2` driver performs a
`copy_up` operation to copy the file from the image (`lowerdir`) to the
container (`upperdir`). The container then writes the changes to the new copy
of the file in the container layer.

However, OverlayFS works at the file level rather than the block level. This
means that all OverlayFS `copy_up` operations copy the entire file, even if
the file is large and only a small part of it's being modified. This can have
a noticeable impact on container write performance. However, two things are
worth noting:

- The `copy_up` operation only occurs the first time a given file is written
  to. Subsequent writes to the same file operate against the copy of the file
  already copied up to the container.

- OverlayFS works with multiple layers. This means that performance can be
  impacted when searching for files in images with many layers.

#### Deleting files and directories

- When a _file_ is deleted within a container, a _whiteout_ file is created in
  the container (`upperdir`). The version of the file in the image layer
  (`lowerdir`) is not deleted (because the `lowerdir` is read-only). However,
  the whiteout file prevents it from being available to the container.

- When a _directory_ is deleted within a container, an _opaque directory_ is
  created within the container (`upperdir`). This works in the same way as a
  whiteout file and effectively prevents the directory from being accessed,
  even though it still exists in the image (`lowerdir`).

#### Renaming directories

Calling `rename(2)` for a directory is allowed only when both the source and
the destination path are on the top layer. Otherwise, it returns `EXDEV` error
("cross-device link not permitted"). Your application needs to be designed to
handle `EXDEV` and fall back to a "copy and unlink" strategy.

## OverlayFS and Docker Performance

`overlay2` may perform better than `btrfs`. However, be aware of the following details:

### Page caching

OverlayFS supports page cache sharing. Multiple containers accessing the same
file share a single page cache entry for that file. This makes the `overlay2`
drivers efficient with memory and a good option for high-density use cases such
as PaaS.

### Copyup

As with other copy-on-write filesystems, OverlayFS performs copy-up operations
whenever a container writes to a file for the first time. This can add latency
into the write operation, especially for large files. However, once the file
has been copied up, all subsequent writes to that file occur in the upper
layer, without the need for further copy-up operations.

### Performance best practices

The following generic performance best practices apply to OverlayFS.

#### Use fast storage

Solid-state drives (SSDs) provide faster reads and writes than spinning disks.

#### Use volumes for write-heavy workloads

Volumes provide the best and most predictable performance for write-heavy
workloads. This is because they bypass the storage driver and don't incur any
of the potential overheads introduced by thin provisioning and copy-on-write.
Volumes have other benefits, such as allowing you to share data among
containers and persisting your data even if no running container is using them.

## Limitations on OverlayFS compatibility

To summarize the OverlayFS's aspect which is incompatible with other
filesystems:

[`open(2)`](https://linux.die.net/man/2/open)
: OverlayFS only implements a subset of the POSIX standards.
This can result in certain OverlayFS operations breaking POSIX standards. One
such operation is the copy-up operation. Suppose that your application calls
`fd1=open("foo", O_RDONLY)` and then `fd2=open("foo", O_RDWR)`. In this case,
your application expects `fd1` and `fd2` to refer to the same file. However, due
to a copy-up operation that occurs after the second calling to `open(2)`, the
descriptors refer to different files. The `fd1` continues to reference the file
in the image (`lowerdir`) and the `fd2` references the file in the container
(`upperdir`). A workaround for this is to `touch` the files which causes the
copy-up operation to happen. All subsequent `open(2)` operations regardless of
read-only or read-write access mode reference the file in the
container (`upperdir`).

`yum` is known to be affected unless the `yum-plugin-ovl` package is installed.
If the `yum-plugin-ovl` package is not available in your distribution such as
RHEL/CentOS prior to 6.8 or 7.2, you may need to run `touch /var/lib/rpm/*`
before running `yum install`. This package implements the `touch` workaround
referenced above for `yum`.

[`rename(2)`](https://linux.die.net/man/2/rename)
: OverlayFS does not fully support the `rename(2)` system call. Your
application needs to detect its failure and fall back to a "copy and unlink"
strategy.


---

# Select a storage driver

*Sección: Engine*

Ideally, very little data is written to a container's writable layer, and you
use Docker volumes to write data. However, some workloads require you to be able
to write to the container's writable layer. This is where storage drivers come
in.

> [!NOTE]
> Docker Engine 29.0 and later uses the
> [containerd image store](../containerd.md) by default for fresh installations.
> If you upgraded from an earlier version, your daemon continues using the
> classic storage drivers described on this page. You can migrate to the
> containerd image store following the instructions in the
> [containerd image store](../containerd.md) documentation.

Docker supports several storage drivers, using a pluggable architecture. The
storage driver controls how images and containers are stored and managed on your
Docker host. After you have read the [storage driver overview](index.md), the
next step is to choose the best storage driver for your workloads. Use the storage
driver with the best overall performance and stability in the most usual scenarios.

> [!NOTE]
> This page discusses storage drivers for Docker Engine on Linux. If you're
> running the Docker daemon with Windows as the host OS, the only supported
> storage driver is windowsfilter. For more information, see
> [windowsfilter](windowsfilter-driver.md).

The Docker Engine provides the following storage backends on Linux:

| Backend                     | Description                                                                                                                                                                                                                                                |
| :-------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `containerd` (snapshotters) | The default for Docker Engine 29.0 and later. Uses containerd snapshotters for image storage. Supports multi-platform images and attestations. See [containerd image store](../containerd.md) for details.                                                 |
| `overlay2`                  | Classic storage driver. Most widely compatible across all currently supported Linux distributions, and requires no extra configuration.                                                                                                                    |
| `fuse-overlayfs`            | Preferred only for running Rootless Docker on hosts that don't support rootless `overlay2`. Not needed since Linux kernel 5.11, as `overlay2` works in rootless mode. See [rootless mode documentation](/manuals/engine/security/rootless.md) for details. |
| `btrfs` and `zfs`           | Allow for advanced options, such as creating snapshots, but require more maintenance and setup. Each relies on the backing filesystem being configured correctly.                                                                                          |
| `vfs`                       | Intended for testing purposes, and for situations where no copy-on-write filesystem can be used. Performance is poor, and not generally recommended for production use.                                                                                    |

<!-- markdownlint-disable reference-links-images -->

The Docker Engine has a prioritized list of which storage driver to use if no
storage driver is explicitly configured, assuming that the storage driver meets
the prerequisites, and automatically selects a compatible storage driver. You
can see the order in the [source code for Docker Engine {{% param "docker_ce_version" %}}](https://github.com/moby/moby/blob/docker-v{{% param "docker_ce_version" %}}/daemon/graphdriver/driver_linux.go).
{ #storage-driver-order }

<!-- markdownlint-enable reference-links-images -->

Some storage drivers require you to use a specific format for the backing filesystem.
If you have external requirements to use a specific backing filesystem, this may
limit your choices. See [Supported backing filesystems](#supported-backing-filesystems).

After you have narrowed down which storage drivers you can choose from, your choice
is determined by the characteristics of your workload and the level of stability
you need. See [Other considerations](#other-considerations) for help in making
the final decision.

## Supported storage drivers per Linux distribution

> [!NOTE]
> Modifying the storage driver by editing the daemon configuration file isn't
> supported on Docker Desktop. Docker Desktop uses the
> [containerd image store](../../../desktop/features/containerd.md) by default
> (version 4.34 and later for clean installs). The following table is also not
> applicable for the Docker Engine in rootless mode. For the drivers available
> in rootless mode, see the
> [Rootless mode documentation](/manuals/engine/security/rootless.md).

This section applies to classic storage drivers only. If you're using the
containerd image store (the default for Docker Engine 29.0+), see the
[containerd image store documentation](../containerd.md) instead.

Your operating system and kernel may not support every classic storage driver.
For example, `btrfs` is only supported if your system uses `btrfs` as storage.
In general, the following configurations work on recent versions of the Linux
distribution:

| Linux distribution   | Default classic driver  | Alternative drivers  |
| :------------------- | :---------------------- | :------------------- |
| Ubuntu               | `overlay2`              | `zfs`, `vfs`         |
| Debian               | `overlay2`              | `vfs`                |
| CentOS               | `overlay2`              | `zfs`, `vfs`         |
| Fedora               | `overlay2`              | `zfs`, `vfs`         |
| SLES 15              | `overlay2`              | `vfs`                |
| RHEL                 | `overlay2`              | `vfs`                |

For systems using classic storage drivers, `overlay2` provides broad
compatibility across Linux distributions. Use Docker volumes for write-heavy
workloads instead of relying on writing data to the container's writable layer.

The `vfs` storage driver is usually not the best choice, and primarily intended
for debugging purposes in situations where no other storage-driver is supported.
Before using the `vfs` storage driver, be sure to read about
[its performance and storage characteristics and limitations](vfs-driver.md).

The recommendations in the table above are known to work for a large number of
users. If you use a recommended configuration and find a reproducible issue,
it's likely to be fixed very quickly. If the driver that you want to use is
not recommended according to this table, you can run it at your own risk. You
can and should still report any issues you run into. However, such issues
have a lower priority than issues encountered when using a recommended
configuration.

Depending on your Linux distribution, other storage-drivers, such as `btrfs` may
be available. These storage drivers can have advantages for specific use-cases,
but may require additional set-up or maintenance, which make them not recommended
for common scenarios. Refer to the documentation for those storage drivers for
details.

## Supported backing filesystems

With regard to Docker, the backing filesystem is the filesystem where
`/var/lib/docker/` is located. Some storage drivers only work with specific
backing filesystems.

| Storage driver   | Supported backing filesystems                         |
| :--------------- | :-----------------------------------------------------|
| `overlay2`       | `xfs` with ftype=1, `ext4`, `btrfs`, (and more)     |
| `fuse-overlayfs` | any filesystem                                        |
| `btrfs`          | `btrfs`                                               |
| `zfs`            | `zfs`                                                 |
| `vfs`            | any filesystem                                        |

> [!NOTE]
>
> Most filesystems should work if they have the required features.
> Consult [OverlayFS](https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html)
> for more information.


## Other considerations

### Suitability for your workload

Among other things, each storage driver has its own performance characteristics
that make it more or less suitable for different workloads. Consider the
following generalizations:

- `overlay2` operates at the file level rather than
  the block level. This uses memory more efficiently, but the container's
  writable layer may grow quite large in write-heavy workloads.
- Block-level storage drivers such as `btrfs`, and `zfs` perform
  better for write-heavy workloads (though not as well as Docker volumes).
- `btrfs` and `zfs` require a lot of memory.
- `zfs` is a good choice for high-density workloads such as PaaS.

More information about performance, suitability, and best practices is available
in the documentation for each storage driver.

### Shared storage systems and the storage driver

If you use SAN, NAS, hardware RAID, or other shared storage systems, those
systems may provide high availability, increased performance, thin
provisioning, deduplication, and compression. In many cases, Docker can work on
top of these storage systems, but Docker doesn't closely integrate with them.

Each Docker storage driver is based on a Linux filesystem or volume manager. Be
sure to follow existing best practices for operating your storage driver
(filesystem or volume manager) on top of your shared storage system. For
example, if using the ZFS storage driver on top of a shared storage system, be
sure to follow best practices for operating ZFS filesystems on top of that
specific shared storage system.

### Stability

For some users, stability is more important than performance. Though Docker
considers all of the storage drivers mentioned here to be stable, some are newer
and are still under active development. In general, `overlay2` provides the
highest stability.

### Test with your own workloads

You can test Docker's performance when running your own workloads on different
storage drivers. Make sure to use equivalent hardware and workloads to match
production conditions, so you can see which storage driver offers the best
overall performance.

## Check your current storage driver

The detailed documentation for each individual storage driver details all of the
set-up steps to use a given storage driver.

To see what storage driver Docker is currently using, use `docker info` and look
for the `Storage Driver` line:

```console
$ docker info

Containers: 0
Images: 0
Storage Driver: overlay2
 Backing Filesystem: xfs
<...>
```

To change the storage driver, see the specific instructions for the new storage
driver. Some drivers require additional configuration, including configuration
to physical or logical disks on the Docker host.

> [!IMPORTANT]
>
> When you change the storage driver, any existing images and containers become
> inaccessible. This is because their layers can't be used by the new storage
> driver. If you revert your changes, you can access the old images and containers
> again, but any that you pulled or created using the new driver are then
> inaccessible.

## Related information

- [Storage drivers](index.md)
- [`overlay2` storage driver](overlayfs-driver.md)
- [`btrfs` storage driver](btrfs-driver.md)
- [`zfs` storage driver](zfs-driver.md)
- [`windowsfilter` storage driver](windowsfilter-driver.md)


---

# VFS storage driver

*Sección: Engine*

The VFS storage driver isn't a union filesystem. Each layer is a
directory on disk, and there is no copy-on-write support. To create a new
layer, a "deep copy" is done of the previous layer. This leads to lower
performance and more space used on disk than other storage drivers. However, it
is robust, stable, and works in every environment. It can also be used as a
mechanism to verify other storage back-ends against, in a testing environment.

## Configure Docker with the `vfs` storage driver

1. Stop Docker.

   ```console
   $ sudo systemctl stop docker
   ```

2.  Edit `/etc/docker/daemon.json`. If it doesn't yet exist, create it. Assuming
    that the file was empty, add the following contents.

    ```json
    {
      "storage-driver": "vfs"
    }
    ```

    If you want to set a quota to control the maximum size the VFS storage
    driver can use, set the `size` option on the `storage-opts` key.

    ```json
    {
      "storage-driver": "vfs",
      "storage-opts": ["size=256M"]
    }
    ```

    Docker doesn't start if the `daemon.json` file contains invalid JSON.

3.  Start Docker.

    ```console
    $ sudo systemctl start docker
    ```

4.  Verify that the daemon is using the `vfs` storage driver.
    Use the `docker info` command and look for `Storage Driver`.

    ```console
    $ docker info

    Storage Driver: vfs
    ...
    ```

Docker is now using the `vfs` storage driver. Docker has automatically
created the `/var/lib/docker/vfs/` directory, which contains all the layers
used by running containers.

## How the `vfs` storage driver works

Each image layer and the writable container layer are represented on the Docker
host as subdirectories within `/var/lib/docker/`. The union mount provides the
unified view of all layers. The directory names don't directly correspond to
the IDs of the layers themselves.

VFS doesn't support copy-on-write (COW). Each time a new layer is created,
it's a deep copy of its parent layer. These layers are all located under
`/var/lib/docker/vfs/dir/`.

### Example: Image and container on-disk constructs

The following `docker pull` command shows a Docker host downloading a Docker
image comprising five layers.

```console
$ docker pull ubuntu

Using default tag: latest
latest: Pulling from library/ubuntu
e0a742c2abfd: Pull complete
486cb8339a27: Pull complete
dc6f0d824617: Pull complete
4f7a5649a30e: Pull complete
672363445ad2: Pull complete
Digest: sha256:84c334414e2bfdcae99509a6add166bbb4fa4041dc3fa6af08046a66fed3005f
Status: Downloaded newer image for ubuntu:latest
```

After pulling, each of these layers is represented as a subdirectory of
`/var/lib/docker/vfs/dir/`. The directory names do not correlate with the
image layer IDs shown in the `docker pull` command. To see the size taken up on
disk by each layer, you can use the `du -sh` command, which gives the size as a
human-readable value.

```console
$ ls -l /var/lib/docker/vfs/dir/

total 0
drwxr-xr-x.  2 root root  19 Aug  2 18:19 3262dfbe53dac3e1ab7dcc8ad5d8c4d586a11d2ac3c4234892e34bff7f6b821e
drwxr-xr-x. 21 root root 224 Aug  2 18:23 6af21814449345f55d88c403e66564faad965d6afa84b294ae6e740c9ded2561
drwxr-xr-x. 21 root root 224 Aug  2 18:23 6d3be4585ba32f9f5cbff0110e8d07aea5f5b9fbb1439677c27e7dfee263171c
drwxr-xr-x. 21 root root 224 Aug  2 18:23 9ecd2d88ca177413ab89f987e1507325285a7418fc76d0dcb4bc021447ba2bab
drwxr-xr-x. 21 root root 224 Aug  2 18:23 a292ac6341a65bf3a5da7b7c251e19de1294bd2ec32828de621d41c7ad31f895
drwxr-xr-x. 21 root root 224 Aug  2 18:23 e92be7a4a4e3ccbb7dd87695bca1a0ea373d4f673f455491b1342b33ed91446b
```

```console
$ du -sh /var/lib/docker/vfs/dir/*

4.0K	/var/lib/docker/vfs/dir/3262dfbe53dac3e1ab7dcc8ad5d8c4d586a11d2ac3c4234892e34bff7f6b821e
125M	/var/lib/docker/vfs/dir/6af21814449345f55d88c403e66564faad965d6afa84b294ae6e740c9ded2561
104M	/var/lib/docker/vfs/dir/6d3be4585ba32f9f5cbff0110e8d07aea5f5b9fbb1439677c27e7dfee263171c
125M	/var/lib/docker/vfs/dir/9ecd2d88ca177413ab89f987e1507325285a7418fc76d0dcb4bc021447ba2bab
104M	/var/lib/docker/vfs/dir/a292ac6341a65bf3a5da7b7c251e19de1294bd2ec32828de621d41c7ad31f895
104M	/var/lib/docker/vfs/dir/e92be7a4a4e3ccbb7dd87695bca1a0ea373d4f673f455491b1342b33ed91446b
```

The above output shows that three layers each take 104M and two take 125M.
These directories have only small differences from each other, but they all
consume the same amount of disk space. This is one of the disadvantages of
using the `vfs` storage driver.

## Related information

- [Understand images, containers, and storage drivers](../../../reference/api/ai-governance/index.md)
- [Select a storage driver](select-storage-driver.md)


---

# windowsfilter storage driver

*Sección: Engine*

The windowsfilter storage driver is the default storage driver for Docker
Engine on Windows. The windowsfilter driver uses Windows-native file system
layers to for storing Docker layers and volume data on disk. The windowsfilter
storage driver only works on file systems formatted with NTFS.

## Configure the windowsfilter storage driver

For most use case, no configuring the windowsfilter storage driver is not
necessary.

The default storage limit for Docker Engine on Windows is 127GB. To use a
different storage size, set the `size` option for the windowsfilter storage
driver. See [windowsfilter options](/reference/cli/dockerd.md#windowsfilter-options).

Data is stored on the Docker host in `image` and `windowsfilter` subdirectories
within `C:\ProgramData\docker` by default. You can change the storage location
by configuring the `data-root` option in the [Daemon configuration file](/reference/cli/dockerd.md#on-windows):

```json
{
  "data-root": "d:\\docker"
}
```

You must restart the daemon for the configuration change to take effect.

## Additional information

For more information about how container storage works on Windows, refer to
Microsoft's [Containers on Windows documentation](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/container-storage).


---

# ZFS storage driver

*Sección: Engine*

ZFS is a next generation filesystem that supports many advanced storage
technologies such as volume management, snapshots, checksumming, compression and
deduplication, replication and more.

It was created by Sun Microsystems (now Oracle Corporation) and is open sourced
under the CDDL license. Due to licensing incompatibilities between the CDDL and
GPL, ZFS cannot be shipped as part of the mainline Linux kernel. However, the
ZFS On Linux (ZoL) project provides an out-of-tree kernel module and userspace
tools which can be installed separately.

The ZFS on Linux (ZoL) port is healthy and maturing. However, at this point in
time it is not recommended to use the `zfs` Docker storage driver for production
use unless you have substantial experience with ZFS on Linux.

> [!NOTE]
>
> There is also a FUSE implementation of ZFS on the Linux platform. This is not recommended. The native ZFS driver (ZoL) is more tested, has better performance, and is more widely used. The remainder of this document refers to the native ZoL port.

## Prerequisites

- ZFS requires one or more dedicated block devices, preferably solid-state
  drives (SSDs).
- The `/var/lib/docker/` directory must be mounted on a ZFS-formatted
  filesystem.
- Changing the storage driver makes any containers you have already
  created inaccessible on the local system. Use `docker save` to save containers,
  and push existing images to Docker Hub or a private repository, so that you
  do not need to re-create them later.

> [!NOTE]
>
> There is no need to use `MountFlags=slave` because `dockerd` and `containerd` are in different mount namespaces.

## Configure Docker with the `zfs` storage driver

1.  Stop Docker.

2.  Copy the contents of `/var/lib/docker/` to `/var/lib/docker.bk` and remove
    the contents of `/var/lib/docker/`.

    ```console
    $ sudo cp -au /var/lib/docker /var/lib/docker.bk

    $ sudo rm -rf /var/lib/docker/*
    ```

3.  Create a new `zpool` on your dedicated block device or devices, and mount it
    into `/var/lib/docker/`. Be sure you
    have specified the correct devices, because this is a destructive operation.
    This example adds two devices to the pool.

    ```console
    $ sudo zpool create -f zpool-docker -m /var/lib/docker /dev/xvdf /dev/xvdg
    ```

    The command creates the `zpool` and names it `zpool-docker`. The name is for
    display purposes only, and you can use a different name. Check that the pool
    was created and mounted correctly using `zfs list`.

    ```console
    $ sudo zfs list

    NAME           USED  AVAIL  REFER  MOUNTPOINT
    zpool-docker    55K  96.4G    19K  /var/lib/docker
    ```

4.  Configure Docker to use `zfs`. Edit `/etc/docker/daemon.json` and set the
    `storage-driver` to `zfs`. If the file was empty before, it should now look
    like this:

    ```json
    {
      "storage-driver": "zfs"
    }
    ```

    Save and close the file.

5.  Start Docker. Use `docker info` to verify that the storage driver is `zfs`.

    ```console
    $ sudo docker info
      Containers: 0
       Running: 0
       Paused: 0
       Stopped: 0
      Images: 0
      Server Version: 17.03.1-ce
      Storage Driver: zfs
       Zpool: zpool-docker
       Zpool Health: ONLINE
       Parent Dataset: zpool-docker
       Space Used By Parent: 249856
       Space Available: 103498395648
       Parent Quota: no
       Compression: off
    <...>
    ```

## Manage `zfs`

### Increase capacity on a running device

To increase the size of the `zpool`, you need to add a dedicated block device to
the Docker host, and then add it to the `zpool` using the `zpool add` command:

```console
$ sudo zpool add zpool-docker /dev/xvdh
```

### Limit a container's writable storage quota

If you want to implement a quota on a per-image/dataset basis, you can set the
`size` storage option to limit the amount of space a single container can use
for its writable layer.

Edit `/etc/docker/daemon.json` and add the following:

```json
{
  "storage-driver": "zfs",
  "storage-opts": ["size=256M"]
}
```

See all storage options for each storage driver in the
[daemon reference documentation](/reference/cli/dockerd/#daemon-storage-driver)

Save and close the file, and restart Docker.

## How the `zfs` storage driver works

ZFS uses the following objects:

- **filesystems**: thinly provisioned, with space allocated from the `zpool` on
  demand.
- **snapshots**: read-only space-efficient point-in-time copies of filesystems.
- **clones**: Read-write copies of snapshots. Used for storing the differences
  from the previous layer.

The process of creating a clone:

![ZFS snapshots and clones](images/zfs_clones.webp?w=450)


1.  A read-only snapshot is created from the filesystem.
2.  A writable clone is created from the snapshot. This contains any differences
    from the parent layer.

Filesystems, snapshots, and clones all allocate space from the underlying
`zpool`.

### Image and container layers on-disk

Each running container's unified filesystem is mounted on a mount point in
`/var/lib/docker/zfs/graph/`. Continue reading for an explanation of how the
unified filesystem is composed.

### Image layering and sharing

The base layer of an image is a ZFS filesystem. Each child layer is a ZFS clone
based on a ZFS snapshot of the layer below it. A container is a ZFS clone based
on a ZFS Snapshot of the top layer of the image it's created from.

The diagram below shows how this is put together with a running container based
on a two-layer image.

![ZFS pool for Docker container](images/zfs_zpool.webp?w=600)

When you start a container, the following steps happen in order:

1.  The base layer of the image exists on the Docker host as a ZFS filesystem.

2.  Additional image layers are clones of the dataset hosting the image layer
    directly below it.

    In the diagram, "Layer 1" is added by taking a ZFS snapshot of the base
    layer and then creating a clone from that snapshot. The clone is writable and
    consumes space on-demand from the zpool. The snapshot is read-only,
    maintaining the base layer as an immutable object.

3.  When the container is launched, a writable layer is added above the image.

    In the diagram, the container's read-write layer is created by making
    a snapshot of the top layer of the image (Layer 1) and creating a clone from
    that snapshot.

4.  As the container modifies the contents of its writable layer, space is
    allocated for the blocks that are changed. By default, these blocks are
    128k.


## How container reads and writes work with `zfs`

### Reading files

Each container's writable layer is a ZFS clone which shares all its data with
the dataset it was created from (the snapshots of its parent layers). Read
operations are fast, even if the data being read is from a deep layer.
This diagram illustrates how block sharing works:

![ZFS block sharing](images/zpool_blocks.webp?w=450)


### Writing files

**Writing a new file**: space is allocated on demand from the underlying `zpool`
and the blocks are written directly into the container's writable layer.

**Modifying an existing file**: space is allocated only for the changed blocks,
and those blocks are written into the container's writable layer using a
copy-on-write (CoW) strategy. This minimizes the size of the layer and increases
write performance.

**Deleting a file or directory**:
  - When you delete a file or directory that exists in a lower layer, the ZFS
    driver masks the existence of the file or directory in the container's
    writable layer, even though the file or directory still exists in the lower
    read-only layers.
  - If you create and then delete a file or directory within the container's
    writable layer, the blocks are reclaimed by the `zpool`.


## ZFS and Docker performance

There are several factors that influence the performance of Docker using the
`zfs` storage driver.

- **Memory**: Memory has a major impact on ZFS performance. ZFS was originally
  designed for large enterprise-grade servers with a large amount of memory.

- **ZFS Features**: ZFS includes a de-duplication feature. Using this feature
  may save disk space, but uses a large amount of memory. It is recommended that
  you disable this feature for the `zpool` you are using with Docker, unless you
  are using SAN, NAS, or other hardware RAID technologies.

- **ZFS Caching**: ZFS caches disk blocks in a memory structure called the
  adaptive replacement cache (ARC). The *Single Copy ARC* feature of ZFS allows
  a single cached copy of a block to be shared by multiple clones of a
  With this feature, multiple running containers can share a single copy of a
  cached block. This feature makes ZFS a good option for PaaS and other
  high-density use cases.

- **Fragmentation**: Fragmentation is a natural byproduct of copy-on-write
  filesystems like ZFS. ZFS mitigates this by using a small block size of 128k.
  The ZFS intent log (ZIL) and the coalescing of writes (delayed writes) also
  help to reduce fragmentation. You can monitor fragmentation using
  `zpool status`. However, there is no way to defragment ZFS without reformatting
  and restoring the filesystem.

- **Use the native ZFS driver for Linux**: The ZFS FUSE implementation is not
  recommended, due to poor performance.

### Performance best practices

- **Use fast storage**:  Solid-state drives (SSDs) provide faster reads and
  writes than spinning disks.

- **Use volumes for write-heavy workloads**: Volumes provide the best and most
  predictable performance for write-heavy workloads. This is because they bypass
  the storage driver and do not incur any of the potential overheads introduced
  by thin provisioning and copy-on-write. Volumes have other benefits, such as
  allowing you to share data among containers and persisting even when no
  running container is using them.


---

# Image mounts

*Sección: Engine*

[Volumes](volumes.md), [bind mounts](bind-mounts.md), and [tmpfs mounts](tmpfs.md)
all give a container a place to read and write data. An image mount is
different: instead of mounting a directory or a memory-backed filesystem, it
mounts the contents of another image into the container.

When you use an image mount, the filesystem of a second image is mounted into
the container at a path you choose. The container can read the files from that
image alongside its own filesystem, without those files being part of the
container's own image. This is useful when you want to bring the tools or assets
from one image into a container that's running a different image.

Image mounts are read-only. The mounted image is never modified, and the
container can't write to the mount.

> [!NOTE]
> Image mounts require the [containerd image store](containerd.md).

## When to use image mounts

Image mounts are appropriate for the following types of use case:

- Debugging a minimal or hardened image that doesn't include a shell or common
  utilities. You can mount a tool-rich image, such as `busybox`, into the
  running container's namespace and run those tools without changing the
  original image. For a worked example, see
  [Debug with Docker Hardened Images](../../dhi/how-to/troubleshoot.md).

- Sharing read-only assets, such as datasets, models, or static content, that
  are distributed as an image and consumed by containers running a different
  image.

- Keeping application images small by packaging optional tooling in a separate
  image and mounting it only when needed.

## Mounting over existing data

If you mount an image into a directory in the container in which files or
directories exist, the pre-existing files are obscured by the mount. This is
similar to if you were to save files into `/mnt` on a Linux host, and then
mounted a USB drive into `/mnt`. The contents of `/mnt` would be obscured by the
contents of the USB drive until the USB drive was unmounted.

With containers, there's no straightforward way of removing a mount to reveal
the obscured files again. Your best option is to recreate the container without
the mount.

## Considerations and constraints

- Image mounts are always read-only. The container can't modify the mounted
  image, and changes aren't persisted anywhere.

- The source image must already exist in the daemon's image store. Docker
  doesn't pull the source image automatically when you create the mount. If the
  image isn't present, the command fails:

  ```console
  $ docker run --mount type=image,source=busybox:musl,destination=/dbg alpine
  docker: Error response from daemon: No such image: busybox:musl
  ```

  Pull the image first with `docker pull`, then create the mount.

- Image mounts require the [containerd image store](containerd.md). They aren't
  available when the daemon uses the classic storage drivers.

- You can only create an image mount with the `--mount` flag. There is no
  `--volume` (`-v`) equivalent.

- Running an executable from a mounted image requires a compatible runtime in
  the container. A dynamically linked binary only runs if the container provides
  a matching dynamic linker and shared libraries. For example, a glibc-based
  binary fails in a musl-based image such as Alpine. Statically linked binaries,
  or mounting only data from an image, avoid this constraint.

## Syntax

To mount an image with the `docker run` command, use the `--mount` flag with
`type=image`.

```console
$ docker run --mount type=image,src=<image-reference>,dst=<container-path>
```

The `--mount` flag consists of multiple key-value pairs, separated by commas and
each consisting of a `<key>=<value>` tuple. The order of the keys isn't
significant.

```console
$ docker run --mount type=image,src=<image-reference>,dst=<container-path>[,<key>=<value>...]
```

### Options for --mount

Valid options for `--mount type=image` include:

| Option                         | Description                                                                                                                       |
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| `source`, `src`                | The reference of the image to mount, for example `busybox` or `busybox:musl`. The image must exist locally.                       |
| `destination`, `dst`, `target` | The path where the image is mounted in the container. Must be an absolute path.                                                   |
| `image-subpath`                | Path inside the source image to mount instead of the image root. See [Mount a subpath of an image](#mount-a-subpath-of-an-image). |

```console {title="Example"}
$ docker run --mount type=image,src=busybox,dst=/dbg,image-subpath=bin
```

## Use an image mount in a container

The following example runs an Alpine container and mounts the `busybox:musl`
image at `/dbg`. Pull the source image first, since Docker doesn't pull it for
you when creating the mount. This example uses the musl-based BusyBox image so
its binaries are compatible with the musl-based Alpine container.

```console
$ docker pull busybox:musl
$ docker run -d \
  -it \
  --name imgtest \
  --mount type=image,source=busybox:musl,destination=/dbg \
  alpine:latest
```

The container can now read the BusyBox tools from `/dbg` while running the Alpine
image:

```console
$ docker exec imgtest /dbg/bin/echo "hello from busybox"
hello from busybox
```

Verify that the mount is an `image` mount by looking in the `Mounts` section of
the `docker inspect` output:

```console
$ docker inspect imgtest --format '{{ json .Mounts }}'
[{"Type":"image","Name":"busybox:musl","Source":"/var/lib/docker/rootfs/overlayfs/...","Destination":"/dbg","Mode":"","RW":false,"Propagation":"rprivate"}]
```

This shows that the mount is an `image` mount, that its source is the
`busybox:musl` image, and that it's read-only (`"RW":false`).

Stop and remove the container:

```console
$ docker container rm -fv imgtest
```

## Mount a subpath of an image

Use the `image-subpath` option to mount a specific directory from the source
image instead of its root. For example, to mount only the `bin` directory of the
`busybox` image at `/tools`:

```console
$ docker run -d \
  -it \
  --name imgtest \
  --mount type=image,source=busybox,destination=/tools,image-subpath=bin \
  alpine:latest
```

The container sees the contents of the image's `bin` directory at `/tools`.

## Use an image mount with Docker Compose

A single Docker Compose service with an image mount looks like this:

```yaml
services:
  app:
    image: alpine:latest
    volumes:
      - type: image
        source: busybox
        target: /dbg
```

To mount a subpath of the image, use the `subpath` option under `image`:

```yaml
services:
  app:
    image: alpine:latest
    volumes:
      - type: image
        source: busybox
        target: /tools
        image:
          subpath: bin
```

The `image.subpath` option is available in Docker Compose version 2.35.0 and
later. For more information about using mounts of the `image` type with Compose,
see the
[Compose reference on the volume attribute](../../reference/compose-file/services.md#volumes).

## Next steps

- Learn about [volumes](volumes.md).
- Learn about [bind mounts](bind-mounts.md).
- Learn about [tmpfs mounts](tmpfs.md).
- Learn about [storage drivers](/engine/storage/drivers/).


---

# tmpfs mounts

*Sección: Engine*

[Volumes](volumes.md) and [bind mounts](bind-mounts.md) let you share files
between the host machine and container so that you can persist data even after
the container is stopped.

If you're running Docker on Linux, you have a third option: tmpfs mounts.
When you create a container with a tmpfs mount, the container can create
files outside the container's writable layer.

As opposed to volumes and bind mounts, a tmpfs mount is temporary, and only
persisted in the host memory. When the container stops, the tmpfs mount is
removed, and files written there won't be persisted.

Because tmpfs stores data in memory, that usage counts against the container's
memory cgroup limit (`--memory` / Compose `mem_limit`). Setting a large
`tmpfs-size` (or host-mounted tmpfs) does not give the container extra RAM
outside that limit — filling the mount can still OOM the container. Memory
metrics for the container include tmpfs usage; see
[runtime metrics](../containers/runmetrics.md).

tmpfs mounts are best used for cases when you do not want the data to persist
either on the host machine or within the container. This may be for security
reasons or to protect the performance of the container when your application
needs to write a large volume of non-persistent state data.

> [!IMPORTANT]
> tmpfs mounts in Docker map directly to
> [tmpfs](https://en.wikipedia.org/wiki/Tmpfs) in the Linux kernel. As such,
> the temporary data may be written to a swap file, and thereby persisted to
> the filesystem.

## Mounting over existing data

If you create a tmpfs mount into a directory in the container in which files or
directories exist, the pre-existing files are obscured by the mount. This is
similar to if you were to save files into `/mnt` on a Linux host, and then
mounted a USB drive into `/mnt`. The contents of `/mnt` would be obscured by
the contents of the USB drive until the USB drive was unmounted.

With containers, there's no straightforward way of removing a mount to reveal
the obscured files again. Your best option is to recreate the container without
the mount.

## Limitations of tmpfs mounts

- Unlike volumes and bind mounts, you can't share tmpfs mounts between containers.
- This functionality is only available if you're running Docker on Linux.
- Data on a tmpfs mount counts toward the container memory limit. A large
  `size=` value does not raise that limit.
- Setting permissions on tmpfs may cause them to [reset after container restart](https://github.com/docker/for-linux/issues/138). In some cases [setting the uid/gid](https://github.com/docker/compose/issues/3425#issuecomment-423091370) can serve as a workaround.

## Syntax

To mount a tmpfs with the `docker run` command, you can use either the
`--mount` or `--tmpfs` flag.

```console
$ docker run --mount type=tmpfs,dst=<mount-path>
$ docker run --tmpfs <mount-path>
```

In general, `--mount` is preferred. The main difference is that the `--mount`
flag is more explicit. On the other hand, `--tmpfs` is less verbose and gives
you more flexibility as it lets you set more mount options.

The `--tmpfs` flag cannot be used with swarm services. You must use `--mount`.

### Options for --tmpfs

The `--tmpfs` flag consists of two fields, separated by a colon character
(`:`).

```console
$ docker run --tmpfs <mount-path>[:opts]
```

The first field is the container path to mount into a tmpfs. The second field
is optional and lets you set mount options. Valid mount options for `--tmpfs`
include:

| Option       | Description                                                                                 |
| ------------ | ------------------------------------------------------------------------------------------- |
| `ro`         | Creates a read-only tmpfs mount.                                                            |
| `rw`         | Creates a read-write tmpfs mount (default behavior).                                        |
| `nosuid`     | Prevents `setuid` and `setgid` bits from being honored during execution.                    |
| `suid`       | Allows `setuid` and `setgid` bits to be honored during execution (default behavior).        |
| `nodev`      | Device files can be created but are not functional (access results in an error).            |
| `dev`        | Device files can be created and are fully functional.                                       |
| `exec`       | Allows the execution of executable binaries in the mounted file system.                     |
| `noexec`     | Does not allow the execution of executable binaries in the mounted file system.             |
| `sync`       | All I/O to the file system is done synchronously.                                           |
| `async`      | All I/O to the file system is done asynchronously (default behavior).                       |
| `dirsync`    | Directory updates within the file system are done synchronously.                            |
| `atime`      | Updates file access time each time the file is accessed.                                    |
| `noatime`    | Does not update file access times when the file is accessed.                                |
| `diratime`   | Updates directory access times each time the directory is accessed.                         |
| `nodiratime` | Does not update directory access times when the directory is accessed.                      |
| `size`       | Specifies the size of the tmpfs mount, for example, `size=64m`.                             |
| `mode`       | Specifies the file mode (permissions) for the tmpfs mount (for example, `mode=1777`).       |
| `uid`        | Specifies the user ID for the owner of the tmpfs mount (for example, `uid=1000`).           |
| `gid`        | Specifies the group ID for the owner of the tmpfs mount (for example, `gid=1000`).          |
| `nr_inodes`  | Specifies the maximum number of inodes for the tmpfs mount (for example, `nr_inodes=400k`). |
| `nr_blocks`  | Specifies the maximum number of blocks for the tmpfs mount (for example, `nr_blocks=1024`). |

```console {title="Example"}
$ docker run --tmpfs /data:noexec,size=1024,mode=1777
```

Not all tmpfs mount features available in the Linux mount command are supported
with the `--tmpfs` flag. If you require advanced tmpfs options or features, you
may need to use a privileged container or configure the mount outside of
Docker.

> [!CAUTION]
> Running containers with `--privileged` grants elevated permissions and can
> expose the host system to security risks. Use this option only when
> absolutely necessary and in trusted environments.

```console
$ docker run --privileged -it debian sh
/# mount -t tmpfs -o <options> tmpfs /data
```

### Options for --mount

The `--mount` flag consists of multiple key-value pairs, separated by commas
and each consisting of a `<key>=<value>` tuple. The order of the keys isn't
significant.

```console
$ docker run --mount type=tmpfs,dst=<mount-path>[,<key>=<value>...]
```

Valid options for `--mount type=tmpfs` include:

| Option                         | Description                                                                                                            |
| :----------------------------- | :--------------------------------------------------------------------------------------------------------------------- |
| `destination`, `dst`, `target` | Container path to mount into a tmpfs.                                                                                  |
| `tmpfs-size`                   | Size of the tmpfs mount in bytes. If unset, the default maximum size of a tmpfs volume is 50% of the host's total RAM. |
| `tmpfs-mode`                   | File mode of the tmpfs in octal. For instance, `700` or `0770`. Defaults to `1777` or world-writable.                  |

```console {title="Example"}
$ docker run --mount type=tmpfs,dst=/app,tmpfs-size=21474836480,tmpfs-mode=1770
```

## Use a tmpfs mount in a container

To use a `tmpfs` mount in a container, use the `--tmpfs` flag, or use the
`--mount` flag with `type=tmpfs` and `destination` options. There is no
`source` for `tmpfs` mounts. The following example creates a `tmpfs` mount at
`/app` in a Nginx container. The first example uses the `--mount` flag and the
second uses the `--tmpfs` flag.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  -it \
  --name tmptest \
  --mount type=tmpfs,destination=/app \
  nginx:latest
```

Verify that the mount is a `tmpfs` mount by looking in the `Mounts` section of
the `docker inspect` output:

```console
$ docker inspect tmptest --format '{{ json .Mounts }}'
[{"Type":"tmpfs","Source":"","Destination":"/app","Mode":"","RW":true,"Propagation":""}]
```

{{< /tab >}}
{{< tab name="`--tmpfs`" >}}

```console
$ docker run -d \
  -it \
  --name tmptest \
  --tmpfs /app \
  nginx:latest
```

Verify that the mount is a `tmpfs` mount by looking in the `Mounts` section of
the `docker inspect` output:

```console
$ docker inspect tmptest --format '{{ json .Mounts }}'
{"/app":""}
```

{{< /tab >}}
{{< /tabs >}}

Stop and remove the container:

```console
$ docker stop tmptest
$ docker rm tmptest
```

## Next steps

- Learn about [volumes](volumes.md)
- Learn about [bind mounts](bind-mounts.md)
- Learn about [image mounts](image-mounts.md)
- Learn about [storage drivers](/engine/storage/drivers/)


---

# Volumes

*Sección: Engine*

Volumes are persistent data stores for containers, created and managed by
Docker. You can create a volume explicitly using the `docker volume create`
command, or Docker can create a volume during container or service creation.

When you create a volume, it's stored within a directory on the Docker
host. When you mount the volume into a container, this directory is what's
mounted into the container. This is similar to the way that bind mounts work,
except that volumes are managed by Docker and are isolated from the core
functionality of the host machine.

## When to use volumes

Volumes are the preferred mechanism for persisting data generated by and used
by Docker containers. While [bind mounts](bind-mounts.md) are dependent on the
directory structure and OS of the host machine, volumes are completely managed by
Docker. Volumes are a good choice for the following use cases:

- Volumes are easier to back up or migrate than bind mounts.
- You can manage volumes using Docker CLI commands or the Docker API.
- Volumes work on both Linux and Windows containers.
- Volumes can be more safely shared among multiple containers.
- New volumes can have their content pre-populated by a container or build.
- When your application requires high-performance I/O.

Volumes are not a good choice if you need to access the files from the host, as
the volume is completely managed by Docker. Use [bind mounts](bind-mounts.md)
if you need to access files or directories from both containers and the host.

Volumes are often a better choice than writing data directly to a container,
because a volume doesn't increase the size of the containers using it. Using a
volume is also faster; writing into a container's writable layer requires a
[storage driver](drivers/index.md) to manage the
filesystem. The storage driver provides a union filesystem, using the Linux
kernel. This extra abstraction reduces performance as compared to using
volumes, which write directly to the host filesystem.

If your container generates non-persistent state data, consider using a
[tmpfs mount](tmpfs.md) to avoid storing the data anywhere permanently, and to
increase the container's performance by avoiding writing into the container's
writable layer.

Volumes use `rprivate` (recursive private) bind propagation, and bind propagation isn't
configurable for volumes.

## A volume's lifecycle

A volume's contents exist outside the lifecycle of a given container. When a
container is destroyed, the writable layer is destroyed with it. Using a volume
ensures that the data is persisted even if the container using it is removed.

A given volume can be mounted into multiple containers simultaneously. When no
running container is using a volume, the volume is still available to Docker
and isn't removed automatically. You can remove unused volumes using `docker
volume prune`.

## Mounting a volume over existing data

If you mount a _non-empty volume_ into a directory in the container in which
files or directories exist, the pre-existing files are obscured by the mount.
This is similar to if you were to save files into `/mnt` on a Linux host, and
then mounted a USB drive into `/mnt`. The contents of `/mnt` would be obscured
by the contents of the USB drive until the USB drive was unmounted.

With containers, there's no straightforward way of removing a mount to reveal
the obscured files again. Your best option is to recreate the container without
the mount.

If you mount an _empty volume_ into a directory in the container in which files
or directories exist, these files or directories are propagated (copied) into
the volume by default. Similarly, if you start a container and specify a volume
which does not already exist, an empty volume is created for you. This is a
good way to pre-populate data that another container needs.

To prevent Docker from copying a container's pre-existing files into an empty
volume, use the `volume-nocopy` option, see [Options for --mount](#options-for---mount).

## Named and anonymous volumes

A volume may be named or anonymous. Anonymous volumes are given a random name
that's guaranteed to be unique within a given Docker host. Just like named
volumes, anonymous volumes persist even if you remove the container that uses
them, except if you use the `--rm` flag when creating the container, in which
case the anonymous volume associated with the container is destroyed. See
[Remove anonymous volumes](volumes.md#remove-anonymous-volumes).

If you create multiple containers consecutively that each use anonymous
volumes, each container creates its own volume. Anonymous volumes aren't reused
or shared between containers automatically. To share an anonymous volume
between two or more containers, you must mount the anonymous volume using the
random volume ID.

## Syntax

To mount a volume with the `docker run` command, you can use either the
`--mount` or `--volume` flag.

```console
$ docker run --mount type=volume,src=<volume-name>,dst=<mount-path>
$ docker run --volume <volume-name>:<mount-path>
```

In general, `--mount` is preferred. The main difference is that the `--mount`
flag is more explicit and supports all the available options.

You must use `--mount` if you want to:

- Specify [volume driver options](#use-a-volume-driver)
- Mount a [volume subdirectory](#mount-a-volume-subdirectory)
- Mount a volume into a Swarm service

### Options for --mount

The `--mount` flag consists of multiple key-value pairs, separated by commas
and each consisting of a `<key>=<value>` tuple. The order of the keys isn't
significant.

```console
$ docker run --mount type=volume[,src=<volume-name>],dst=<mount-path>[,<key>=<value>...]
```

Valid options for `--mount type=volume` include:

| Option                         | Description                                                                                                                                                                                                                     |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `source`, `src`                | The source of the mount. For named volumes, this is the name of the volume. For anonymous volumes, this field is omitted.                                                                                                       |
| `destination`, `dst`, `target` | The path where the file or directory is mounted in the container.                                                                                                                                                               |
| `volume-subpath`               | A path to a subdirectory within the volume to mount into the container. The subdirectory must exist in the volume before the volume is mounted to a container. See [Mount a volume subdirectory](#mount-a-volume-subdirectory). |
| `readonly`, `ro`               | If present, causes the volume to be [mounted into the container as read-only](#use-a-read-only-volume).                                                                                                                         |
| `volume-nocopy`                | If present, data at the destination isn't copied into the volume if the volume is empty. By default, content at the target destination gets copied into a mounted volume if empty.                                              |
| `volume-opt`                   | Can be specified more than once, takes a key-value pair consisting of the option name and its value.                                                                                                                            |

```console {title="Example"}
$ docker run --mount type=volume,src=myvolume,dst=/data,ro,volume-subpath=/foo
```

### Options for --volume

The `--volume` or `-v` flag consists of three fields, separated by colon
characters (`:`). The fields must be in the correct order.

```console
$ docker run -v [<volume-name>:]<mount-path>[:opts]
```

In the case of named volumes, the first field is the name of the volume, and is
unique on a given host machine. For anonymous volumes, the first field is
omitted. The second field is the path where the file or directory is mounted in
the container.

The third field is optional, and is a comma-separated list of options. Valid
options for `--volume` with a data volume include:

| Option           | Description                                                                                                                                                                        |
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `readonly`, `ro` | If present, causes the volume to be [mounted into the container as read-only](#use-a-read-only-volume).                                                                            |
| `volume-nocopy`  | If present, data at the destination isn't copied into the volume if the volume is empty. By default, content at the target destination gets copied into a mounted volume if empty. |

```console {title="Example"}
$ docker run -v myvolume:/data:ro
```

## Create and manage volumes

Unlike a bind mount, you can create and manage volumes outside the scope of any
container.

Create a volume:

```console
$ docker volume create my-vol
```

List volumes:

```console
$ docker volume ls

local               my-vol
```

Inspect a volume:

```console
$ docker volume inspect my-vol
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]
```

Remove a volume:

```console
$ docker volume rm my-vol
```

## Start a container with a volume

If you start a container with a volume that doesn't yet exist, Docker creates
the volume for you. The following example mounts the volume `myvol2` into
`/app/` in the container.

The following `-v` and `--mount` examples produce the same result. You can't
run them both unless you remove the `devtest` container and the `myvol2` volume
after running the first one.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  --name devtest \
  --mount source=myvol2,target=/app \
  nginx:latest
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  --name devtest \
  -v myvol2:/app \
  nginx:latest
```

{{< /tab >}}
{{< /tabs >}}

Use `docker inspect devtest` to verify that Docker created the volume and it mounted
correctly. Look for the `Mounts` section:

```json
"Mounts": [
    {
        "Type": "volume",
        "Name": "myvol2",
        "Source": "/var/lib/docker/volumes/myvol2/_data",
        "Destination": "/app",
        "Driver": "local",
        "Mode": "",
        "RW": true,
        "Propagation": ""
    }
],
```

This shows that the mount is a volume, it shows the correct source and
destination, and that the mount is read-write.

Stop the container and remove the volume. Note volume removal is a separate
step.

```console
$ docker container stop devtest

$ docker container rm devtest

$ docker volume rm myvol2
```

## Use a volume with Docker Compose

The following example shows a single Docker Compose service with a volume:

```yaml
services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:
```

Running `docker compose up` for the first time creates a volume. Docker reuses the same volume when you run the command subsequently.

You can create a volume directly outside of Compose using `docker volume create` and
then reference it inside `compose.yaml` as follows:

```yaml
services:
  frontend:
    image: node:lts
    volumes:
      - myapp:/home/node/app
volumes:
  myapp:
    external: true
```

For more information about using volumes with Compose, refer to the
[Volumes](../../reference/compose-file/volumes.md)
section in the Compose specification.

### Start a service with volumes

When you start a service and define a volume, each service container uses its own
local volume. None of the containers can share this data if you use the `local`
volume driver. However, some volume drivers do support shared storage.

The following example starts an `nginx` service with four replicas, each of which
uses a local volume called `myvol2`.

```console
$ docker service create -d \
  --replicas=4 \
  --name devtest-service \
  --mount source=myvol2,target=/app \
  nginx:latest
```

Use `docker service ps devtest-service` to verify that the service is running:

```console
$ docker service ps devtest-service

ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
4d7oz1j85wwn        devtest-service.1   nginx:latest        moby                Running             Running 14 seconds ago
```

You can remove the service to stop the running tasks:

```console
$ docker service rm devtest-service
```

Removing the service doesn't remove any volumes created by the service.
Volume removal is a separate step.

### Populate a volume using a container

If you start a container which creates a new volume, and the container
has files or directories in the directory to be mounted such as `/app/`,
Docker copies the directory's contents into the volume. The container then
mounts and uses the volume, and other containers which use the volume also
have access to the pre-populated content.

To show this, the following example starts an `nginx` container and
populates the new volume `nginx-vol` with the contents of the container's
`/usr/share/nginx/html` directory. This is where Nginx stores its default HTML
content.

The `--mount` and `-v` examples have the same end result.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  --name=nginxtest \
  --mount source=nginx-vol,destination=/usr/share/nginx/html \
  nginx:latest
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  --name=nginxtest \
  -v nginx-vol:/usr/share/nginx/html \
  nginx:latest
```

{{< /tab >}}
{{< /tabs >}}

After running either of these examples, run the following commands to clean up
the containers and volumes. Note volume removal is a separate step.

```console
$ docker container stop nginxtest

$ docker container rm nginxtest

$ docker volume rm nginx-vol
```

## Use a read-only volume

For some applications, the container needs to write to the volume. At other
times, the container only needs read access to the data. Multiple
containers can mount the same volume. You can simultaneously mount a
single volume as `read-write` for some containers and as `read-only` for others.

The following example changes the previous one. It mounts the directory as a read-only
volume, by adding `ro` to the (empty by default) list of options, after the
mount point within the container. Where multiple options are present, you can separate
them using commas.

The `--mount` and `-v` examples have the same result.

{{< tabs >}}
{{< tab name="`--mount`" >}}

```console
$ docker run -d \
  --name=nginxtest \
  --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
  nginx:latest
```

{{< /tab >}}
{{< tab name="`-v`" >}}

```console
$ docker run -d \
  --name=nginxtest \
  -v nginx-vol:/usr/share/nginx/html:ro \
  nginx:latest
```

{{< /tab >}}
{{< /tabs >}}

Use `docker inspect nginxtest` to verify that Docker created the read-only mount
correctly. Look for the `Mounts` section:

```json
"Mounts": [
    {
        "Type": "volume",
        "Name": "nginx-vol",
        "Source": "/var/lib/docker/volumes/nginx-vol/_data",
        "Destination": "/usr/share/nginx/html",
        "Driver": "local",
        "Mode": "",
        "RW": false,
        "Propagation": ""
    }
],
```

Stop and remove the container, and remove the volume. Volume removal is a
separate step.

```console
$ docker container stop nginxtest

$ docker container rm nginxtest

$ docker volume rm nginx-vol
```

## Mount a volume subdirectory

When you mount a volume to a container, you can specify a subdirectory of the
volume to use, with the `volume-subpath` parameter for the `--mount` flag. The
subdirectory that you specify must exist in the volume before you attempt to
mount it into a container; if it doesn't exist, the mount fails.

Specifying `volume-subpath` is useful if you only want to share a specific
portion of a volume with a container. Say for example that you have multiple
containers running and you want to store logs from each container in a shared
volume. You can create a subdirectory for each container in the shared volume,
and mount the subdirectory to the container.

The following example creates a `logs` volume and initiates the subdirectories
`app1` and `app2` in the volume. It then starts two containers and mounts one
of the subdirectories of the `logs` volume to each container. This example
assumes that the processes in the containers write their logs to
`/var/log/app1` and `/var/log/app2`.

```console
$ docker volume create logs
$ docker run --rm \
  --mount src=logs,dst=/logs \
  alpine mkdir -p /logs/app1 /logs/app2
$ docker run -d \
  --name=app1 \
  --mount src=logs,dst=/var/log/app1,volume-subpath=app1 \
  app1:latest
$ docker run -d \
  --name=app2 \
  --mount src=logs,dst=/var/log/app2,volume-subpath=app2 \
  app2:latest
```

With this setup, the containers write their logs to separate subdirectories of
the `logs` volume. The containers can't access the other container's logs.

## Share data between machines

When building fault-tolerant applications, you may need to configure multiple
replicas of the same service to have access to the same files.

![shared storage](images/volumes-shared-storage.webp)

There are several ways to achieve this when developing your applications.
One is to add logic to your application to store files on a cloud object
storage system like Amazon S3. Another is to create volumes with a driver that
supports writing files to an external storage system like NFS or Amazon S3.

Volume drivers let you abstract the underlying storage system from the
application logic. For example, if your services use a volume with an NFS
driver, you can update the services to use a different driver. For example, to
store data in the cloud, without changing the application logic.

## Use a volume driver

When you create a volume using `docker volume create`, or when you start a
container which uses a not-yet-created volume, you can specify a volume driver.
The following examples use the `rclone/docker-volume-rclone` volume driver, first when creating
a standalone volume, and then when starting a container which creates a new
volume.

> [!NOTE]
>
> If your volume driver accepts a comma-separated list as an option,
> you must escape the value from the outer CSV parser. To escape a `volume-opt`,
> surround it with double quotes (`"`) and surround the entire mount parameter
> with single quotes (`'`).
>
> For example, the `local` driver accepts mount options as a comma-separated
> list in the `o` parameter. This example shows the correct way to escape the list.
>
> ```console
> $ docker service create \
>  --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
>  --name myservice \
>  <IMAGE>
> ```

### Initial setup

The following example assumes that you have two nodes, the first of which is a Docker
host and can connect to the second node using SSH.

On the Docker host, install the `rclone/docker-volume-rclone` plugin:

```console
$ docker plugin install --grant-all-permissions rclone/docker-volume-rclone --aliases rclone
```

### Create a volume using a volume driver

This example mounts the `/remote` directory on host `1.2.3.4` into a
volume named `rclonevolume`. Each volume driver may have zero or more
configurable options, you specify each of them using an `-o` flag.

```console
$ docker volume create \
  -d rclone \
  --name rclonevolume \
  -o type=sftp \
  -o path=remote \
  -o sftp-host=1.2.3.4 \
  -o sftp-user=user \
  -o "sftp-password=$(cat file_containing_password_for_remote_host)"
```

This volume can now be mounted into containers.

### Start a container which creates a volume using a volume driver

> [!NOTE]
>
> If the volume driver requires you to pass any options,
> you must use the `--mount` flag to mount the volume, and not `-v`.

```console
$ docker run -d \
  --name rclone-container \
  --mount type=volume,volume-driver=rclone,src=rclonevolume,target=/app,volume-opt=type=sftp,volume-opt=path=remote, volume-opt=sftp-host=1.2.3.4,volume-opt=sftp-user=user,volume-opt=-o "sftp-password=$(cat file_containing_password_for_remote_host)" \
  nginx:latest
```

### Create a service which creates an NFS volume

The following example shows how you can create an NFS volume when creating a service.
It uses `10.0.0.10` as the NFS server and `/var/docker-nfs` as the exported directory on the NFS server.
Note that the volume driver specified is `local`.

#### NFSv3

```console
$ docker service create -d \
  --name nfs-service \
  --mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,volume-opt=o=addr=10.0.0.10' \
  nginx:latest
```

#### NFSv4

```console
$ docker service create -d \
    --name nfs-service \
    --mount 'type=volume,source=nfsvolume,target=/app,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/var/docker-nfs,"volume-opt=o=addr=10.0.0.10,rw,nfsvers=4,async"' \
    nginx:latest
```

### Create CIFS/Samba volumes

You can mount a Samba share directly in Docker without configuring a mount point on your host.

```console
$ docker volume create \
	--driver local \
	--opt type=cifs \
	--opt device=//uxxxxx.your-server.de/backup \
	--opt o=addr=uxxxxx.your-server.de,username=uxxxxxxx,password=*****,file_mode=0777,dir_mode=0777 \
	--name cifs-volume
```

The `addr` option is required if you specify a hostname instead of an IP.
This lets Docker perform the hostname lookup.

### Block storage devices

You can mount a block storage device, such as an external drive or a drive partition, to a container.
The following example shows how to create and use a file as a block storage device,
and how to mount the block device as a container volume.

> [!IMPORTANT]
>
> The following procedure is only an example.
> The solution illustrated here isn't recommended as a general practice.
> Don't attempt this approach unless you're confident about what you're doing.

#### How mounting block devices works

Under the hood, the `--mount` flag using the `local` storage driver invokes the
Linux `mount` syscall and forwards the options you pass to it unaltered.
Docker doesn't implement any additional functionality on top of the native mount features supported by the Linux kernel.

If you're familiar with the
[Linux `mount` command](https://man7.org/linux/man-pages/man8/mount.8.html),
you can think of the `--mount` options as forwarded to the `mount` command in the following manner:

```console
$ mount -t <mount.volume-opt.type> <mount.volume-opt.device> <mount.dst> -o <mount.volume-opts.o>
```

To explain this further, consider the following `mount` command example.
This command mounts the `/dev/loop5` device to the path `/external-drive` on the system.

```console
$ mount -t ext4 /dev/loop5 /external-drive
```

The following `docker run` command achieves a similar result, from the point of view of the container being run.
Running a container with this `--mount` option sets up the mount in the same way as if you had executed the
`mount` command from the previous example.

```console
$ docker run \
  --mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4'
```

You can't run the `mount` command inside the container directly,
because the container is unable to access the `/dev/loop5` device.
That's why the `docker run` command uses the `--mount` option.

#### Example: Mounting a block device in a container

The following steps create an `ext4` filesystem and mounts it into a container.
The filesystem support of your system depends on the version of the Linux kernel you are using.

1. Create a file and allocate some space to it:

   ```console
   $ fallocate -l 1G disk.raw
   ```

2. Build a filesystem onto the `disk.raw` file:

   ```console
   $ mkfs.ext4 disk.raw
   ```

3. Create a loop device:

   ```console
   $ losetup -f --show disk.raw
   /dev/loop5
   ```

   > [!NOTE]
   >
   > `losetup` creates an ephemeral loop device that's removed after
   > system reboot, or manually removed with `losetup -d`.

4. Run a container that mounts the loop device as a volume:

   ```console
   $ docker run -it --rm \
     --mount='type=volume,dst=/external-drive,volume-driver=local,volume-opt=device=/dev/loop5,volume-opt=type=ext4' \
     ubuntu bash
   ```

   When the container starts, the path `/external-drive` mounts the
   `disk.raw` file from the host filesystem as a block device.

5. When you're done, and the device is unmounted from the container,
   detach the loop device to remove the device from the host system:

   ```console
   $ losetup -d /dev/loop5
   ```

## Back up, restore, or migrate data volumes

Volumes are useful for backups, restores, and migrations.
Use the `--volumes-from` flag to create a new container that mounts that volume.

### Back up a volume

For example, create a new container named `dbstore`:

```console
$ docker run -v /dbdata --name dbstore ubuntu /bin/bash
```

In the next command:

- Launch a new container and mount the volume from the `dbstore` container
- Mount a local host directory as `/backup`
- Pass a command that tars the contents of the `dbdata` volume to a `backup.tar` file inside the `/backup` directory.

```console
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
```

When the command completes and the container stops, it creates a backup of
the `dbdata` volume.

### Restore volume from a backup

With the backup just created, you can restore it to the same container,
or to another container that you created elsewhere.

For example, create a new container named `dbstore2`:

```console
$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash
```

Then, un-tar the backup file in the new container’s data volume:

```console
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
```

You can use these techniques to automate backup, migration, and restore
testing using your preferred tools.

## Remove volumes

A Docker data volume persists after you delete a container. There are two types
of volumes to consider:

- Named volumes have a specific name, for example, `awesome:/bar`, where `awesome` is the name.
- Anonymous volumes have no specific name. Therefore, when the container is deleted, you can instruct the Docker Engine daemon to remove them.

### Remove anonymous volumes

To automatically remove anonymous volumes, use the `--rm` option. For example,
this command creates an anonymous `/foo` volume. When you remove the container,
the Docker Engine removes the `/foo` volume but not the `awesome` volume.

The `--rm` option works with both foreground and detached (`-d`) containers.
The anonymous volumes are cleaned up when the container exits.

```console
$ docker run --rm -v /foo -v awesome:/bar busybox top
```

> [!NOTE]
>
> If another container binds the volumes with
> `--volumes-from`, the volume definitions are _copied_ and the
> anonymous volume also stays after the first container is removed.

### Remove all volumes

To remove all unused volumes and free up space:

```console
$ docker volume prune
```

## Next steps

- Learn about [bind mounts](bind-mounts.md).
- Learn about [tmpfs mounts](tmpfs.md).
- Learn about [image mounts](image-mounts.md).
- Learn about [storage drivers](/engine/storage/drivers/).
- Learn about [third-party volume driver plugins](/engine/extend/legacy_plugins/).


---

# Swarm mode

*Sección: Engine*

{{% include "swarm-mode.md" %}}

Current versions of Docker include Swarm mode for natively managing a cluster
of Docker Engines called a swarm. Use the Docker CLI to create a swarm, deploy
application services to a swarm, and manage swarm behavior.

Docker Swarm mode is built into the Docker Engine. Do not confuse Docker Swarm mode
with [Docker Classic Swarm](https://github.com/docker/classicswarm)
which is no longer actively developed.

## Feature highlights

### Cluster management integrated with Docker Engine

Use the Docker Engine CLI to create a swarm of Docker Engines where you can deploy application
services. You don't need additional orchestration software to create or manage
a swarm.

### Decentralized design

Instead of handling differentiation between node roles at deployment time, the Docker Engine handles any specialization at runtime. You can deploy both kinds of nodes, managers and workers, using the
Docker Engine. This means you can build an entire swarm from a single disk
image.

### Declarative service model

Docker Engine uses a declarative approach to
let you define the desired state of the various services in your application
stack. For example, you might describe an application comprised of a web front
end service with message queueing services and a database backend.

### Scaling 

For each service, you can declare the number of tasks you want to
run. When you scale up or down, the swarm manager automatically adapts by
adding or removing tasks to maintain the desired state.

### Desired state reconciliation

The swarm manager node constantly monitors
the cluster state and reconciles any differences between the actual state and your
expressed desired state. For example, if you set up a service to run 10
replicas of a container, and a worker machine hosting two of those replicas
crashes, the manager creates two new replicas to replace the replicas that
crashed. The swarm manager assigns the new replicas to workers that are
running and available.

### Multi-host networking

You can specify an overlay network for your
services. The swarm manager automatically assigns addresses to the containers
on the overlay network when it initializes or updates the application.

### Service discovery

Swarm manager nodes assign each service in the swarm a
unique DNS name and load balance running containers. You can query every
container running in the swarm through a DNS server embedded in the swarm.

### Load balancing

You can expose the ports for services to an
external load balancer. Internally, the swarm lets you specify how to distribute
service containers between nodes.

### Secure by default

Each node in the swarm enforces TLS mutual
authentication and encryption to secure communications between itself and all
other nodes. You have the option to use self-signed root certificates or
certificates from a custom root CA.

### Rolling updates

At rollout time you can apply service updates to nodes
incrementally. The swarm manager lets you control the delay between service
deployment to different sets of nodes. If anything goes wrong, you can
roll back to a previous version of the service.

## What's next?

* Learn Swarm mode [key concepts](key-concepts.md).
* Get started with the [Swarm mode tutorial](swarm-tutorial/index.md).
* Explore Swarm mode CLI commands
  * [swarm init](/reference/cli/docker/swarm/init/)
  * [swarm join](/reference/cli/docker/swarm/join/)
  * [service create](/reference/cli/docker/service/create/)
  * [service inspect](/reference/cli/docker/service/inspect/)
  * [service ls](/reference/cli/docker/service/ls/)
  * [service rm](/reference/cli/docker/service/rm/)
  * [service scale](/reference/cli/docker/service/scale/)
  * [service ps](/reference/cli/docker/service/ps/)
  * [service update](/reference/cli/docker/service/update/)


---

# Administer and maintain a swarm of Docker Engines

*Sección: Engine*

When you run a swarm of Docker Engines, manager nodes are the key components
for managing the swarm and storing the swarm state. It is important to
understand some key features of manager nodes to properly deploy and
maintain the swarm.

Refer to [How nodes work](how-swarm-mode-works/nodes.md)
for a brief overview of Docker Swarm mode and the difference between manager and
worker nodes.

## Operate manager nodes in a swarm

Swarm manager nodes use the [Raft Consensus Algorithm](raft.md) to manage the
swarm state. You only need to understand some general concepts of Raft in
order to manage a swarm.

There is no limit on the number of manager nodes. The decision about how many
manager nodes to implement is a trade-off between performance and
fault-tolerance. Adding manager nodes to a swarm makes the swarm more
fault-tolerant. However, additional manager nodes reduce write performance
because more nodes must acknowledge proposals to update the swarm state.
This means more network round-trip traffic.

Raft requires a majority of managers, also called the quorum, to agree on
proposed updates to the swarm, such as node additions or removals. Membership
operations are subject to the same constraints as state replication.

### Maintain the quorum of managers

If the swarm loses the quorum of managers, the swarm cannot perform management
tasks. If your swarm has multiple managers, always have more than two.
To maintain quorum, a majority of managers must be available. An odd number of
managers is recommended, because the next even number does not make the quorum
easier to keep. For instance, whether you have 3 or 4 managers, you can still
only lose 1 manager and maintain the quorum. If you have 5 or 6 managers, you
can still only lose two.

Even if a swarm loses the quorum of managers, swarm tasks on existing worker
nodes continue to run. However, swarm nodes cannot be added, updated, or
removed, and new or existing tasks cannot be started, stopped, moved, or
updated.

See [Recovering from losing the quorum](#recover-from-losing-the-quorum) for
troubleshooting steps if you do lose the quorum of managers.

## Configure the manager to advertise on a static IP address

When initiating a swarm, you must specify the `--advertise-addr` flag to
advertise your address to other manager nodes in the swarm. For more
information, see [Run Docker Engine in swarm mode](swarm-mode.md#configure-the-advertise-address). Because manager nodes are
meant to be a stable component of the infrastructure, you should use a *fixed
IP address* for the advertise address to prevent the swarm from becoming
unstable on machine reboot.

If the whole swarm restarts and every manager node subsequently gets a new IP
address, there is no way for any node to contact an existing manager. Therefore
the swarm is hung while nodes try to contact one another at their old IP addresses.

Dynamic IP addresses are OK for worker nodes.

## Add manager nodes for fault tolerance

You should maintain an odd number of managers in the swarm to support manager
node failures. Having an odd number of managers ensures that during a network
partition, there is a higher chance that the quorum remains available to process
requests if the network is partitioned into two sets. Keeping the quorum is not
guaranteed if you encounter more than two network partitions.

| Swarm Size |  Majority  |  Fault Tolerance  |
|:------------:|:----------:|:-----------------:|
|      1       |     1      |         0         |
|      2       |     2      |         0         |
|    **3**     |     2      |       **1**       |
|      4       |     3      |         1         |
|    **5**     |     3      |       **2**       |
|      6       |     4      |         2         |
|    **7**     |     4      |       **3**       |
|      8       |     5      |         3         |
|    **9**     |     5      |       **4**       |

For example, in a swarm with *5 nodes*, if you lose *3 nodes*, you don't have a
quorum. Therefore you can't add or remove nodes until you recover one of the
unavailable manager nodes or recover the swarm with disaster recovery
commands. See [Recover from disaster](#recover-from-disaster).

While it is possible to scale a swarm down to a single manager node, it is
impossible to demote the last manager node. This ensures you maintain access to
the swarm and that the swarm can still process requests. Scaling down to a
single manager is an unsafe operation and is not recommended. If
the last node leaves the swarm unexpectedly during the demote operation, the
swarm becomes unavailable until you reboot the node or restart with
`--force-new-cluster`.

You manage swarm membership with the `docker swarm` and `docker node`
subsystems. Refer to [Add nodes to a swarm](join-nodes.md) for more information
on how to add worker nodes and promote a worker node to be a manager.

### Distribute manager nodes

In addition to maintaining an odd number of manager nodes, pay attention to
datacenter topology when placing managers. For optimal fault-tolerance, distribute
manager nodes across a minimum of 3 availability-zones to support failures of an
entire set of machines or common maintenance scenarios. If you suffer a failure
in any of those zones, the swarm should maintain the quorum of manager nodes
available to process requests and rebalance workloads.

| Swarm manager nodes |  Repartition (on 3 Availability zones) |
|:-------------------:|:--------------------------------------:|
| 3                   |                  1-1-1                 |
| 5                   |                  2-2-1                 |
| 7                   |                  3-2-2                 |
| 9                   |                  3-3-3                 |

### Run manager-only nodes

By default manager nodes also act as a worker nodes. This means the scheduler
can assign tasks to a manager node. For small and non-critical swarms
assigning tasks to managers is relatively low-risk as long as you schedule
services using resource constraints for cpu and memory.

However, because manager nodes use the Raft consensus algorithm to replicate data
in a consistent way, they are sensitive to resource starvation. You should
isolate managers in your swarm from processes that might block swarm
operations like swarm heartbeat or leader elections.

To avoid interference with manager node operation, you can drain manager nodes
to make them unavailable as worker nodes:

```console
$ docker node update --availability drain <NODE>
```

When you drain a node, the scheduler reassigns any tasks running on the node to
other available worker nodes in the swarm. It also prevents the scheduler from
assigning tasks to the node.

## Add worker nodes for load balancing

[Add nodes to the swarm](join-nodes.md) to balance your swarm's
load. Replicated service tasks are distributed across the swarm as evenly as
possible over time, as long as the worker nodes are matched to the requirements
of the services. When limiting a service to run on only specific types of nodes,
such as nodes with a specific number of CPUs or amount of memory, remember that
worker nodes that do not meet these requirements cannot run these tasks.

## Monitor swarm health

You can monitor the health of manager nodes by querying the docker `nodes` API
in JSON format through the `/nodes` HTTP endpoint. Refer to the
[nodes API documentation](/reference/api/engine/version/v1.25/#tag/Node)
for more information.

From the command line, run `docker node inspect <id-node>` to query the nodes.
For instance, to query the reachability of the node as a manager:


```console
$ docker node inspect manager1 --format "{{ .ManagerStatus.Reachability }}"
reachable
```


To query the status of the node as a worker that accept tasks:


```console
$ docker node inspect manager1 --format "{{ .Status.State }}"
ready
```


From those commands, we can see that `manager1` is both at the status
`reachable` as a manager and `ready` as a worker.

An `unreachable` health status means that this particular manager node is unreachable
from other manager nodes. In this case you need to take action to restore the unreachable
manager:

- Restart the daemon and see if the manager comes back as reachable.
- Reboot the machine.
- If neither restarting nor rebooting works, you should add another manager node or promote a worker to be a manager node. You also need to cleanly remove the failed node entry from the manager set with `docker node demote <NODE>` and `docker node rm <id-node>`.

Alternatively you can also get an overview of the swarm health from a manager
node with `docker node ls`:

```console
$ docker node ls
ID                           HOSTNAME  MEMBERSHIP  STATUS  AVAILABILITY  MANAGER STATUS
1mhtdwhvsgr3c26xxbnzdc3yp    node05    Accepted    Ready   Active
516pacagkqp2xc3fk9t1dhjor    node02    Accepted    Ready   Active        Reachable
9ifojw8of78kkusuc4a6c23fx *  node01    Accepted    Ready   Active        Leader
ax11wdpwrrb6db3mfjydscgk7    node04    Accepted    Ready   Active
bb1nrq2cswhtbg4mrsqnlx1ck    node03    Accepted    Ready   Active        Reachable
di9wxgz8dtuh9d2hn089ecqkf    node06    Accepted    Ready   Active
```

## Troubleshoot a manager node

You should never restart a manager node by copying the `raft` directory from another node. The data directory is unique to a node ID. A node can only use a node ID once to join the swarm. The node ID space should be globally unique.

To cleanly re-join a manager node to a cluster:

1. Demote the node to a worker using `docker node demote <NODE>`.
2. Remove the node from the swarm using `docker node rm <NODE>`.
3. Re-join the node to the swarm with a fresh state using `docker swarm join`.

For more information on joining a manager node to a swarm, refer to
[Join nodes to a swarm](join-nodes.md).

## Forcibly remove a node

In most cases, you should shut down a node before removing it from a swarm with
the `docker node rm` command. If a node becomes unreachable, unresponsive, or
compromised you can forcefully remove the node without shutting it down by
passing the `--force` flag. For instance, if `node9` becomes compromised:

```console
$ docker node rm node9

Error response from daemon: rpc error: code = 9 desc = node node9 is not down and can't be removed

$ docker node rm --force node9

Node node9 removed from swarm
```

Before you forcefully remove a manager node, you must first demote it to the
worker role. Make sure that you always have an odd number of manager nodes if
you demote or remove a manager.

## Back up the swarm

Docker manager nodes store the swarm state and manager logs in the
`/var/lib/docker/swarm/` directory. This data includes the keys used to encrypt
the Raft logs. Without these keys, you cannot restore the swarm.

You can back up the swarm using any manager. Use the following procedure.

1.  If the swarm has auto-lock enabled, you need the unlock key
    to restore the swarm from backup. Retrieve the unlock key if necessary and
    store it in a safe location. If you are unsure, read
    [Lock your swarm to protect its encryption key](swarm-manager-locking.md).

2.  Stop Docker on the manager before backing up the data, so that no data is
    being changed during the backup. It is possible to take a backup while the
    manager is running (a "hot" backup), but this is not recommended and your
    results are less predictable when restoring. While the manager is down,
    other nodes continue generating swarm data that is not part of this backup.

    > [!NOTE]
    > 
    > Be sure to maintain the quorum of swarm managers. During the
    > time that a manager is shut down, your swarm is more vulnerable to
    > losing the quorum if further nodes are lost. The number of managers you
    > run is a trade-off. If you regularly take down managers to do backups,
    > consider running a five manager swarm, so that you can lose an additional
    > manager while the backup is running, without disrupting your services.

3.  Back up the entire `/var/lib/docker/swarm` directory.

4.  Restart the manager.

To restore, see [Restore from a backup](#restore-from-a-backup). 

## Recover from disaster

### Restore from a backup

After backing up the swarm as described in
[Back up the swarm](#back-up-the-swarm), use the following procedure to
restore the data to a new swarm.

1.  Shut down Docker on the target host machine for the restored swarm.

2.  Remove the contents of the `/var/lib/docker/swarm` directory on the new
    swarm.

3.  Restore the `/var/lib/docker/swarm` directory with the contents of the
    backup.

    > [!NOTE]
    > 
    > The new node uses the same encryption key for on-disk
    > storage as the old one. It is not possible to change the on-disk storage
    > encryption keys at this time.
    >
    > In the case of a swarm with auto-lock enabled, the unlock key is also the
    > same as on the old swarm, and the unlock key is needed to restore the
    > swarm.

4.  Start Docker on the new node. Unlock the swarm if necessary. Re-initialize
    the swarm using the following command, so that this node does not attempt
    to connect to nodes that were part of the old swarm, and presumably no
    longer exist.

    ```console
    $ docker swarm init --force-new-cluster
    ```

5.  Verify that the state of the swarm is as expected. This may include
    application-specific tests or simply checking the output of
    `docker service ls` to be sure that all expected services are present.

6.  If you use auto-lock,
    [rotate the unlock key](swarm-manager-locking.md#rotate-the-unlock-key).

7.  Add manager and worker nodes to bring your new swarm up to operating
    capacity.

8.  Reinstate your previous backup regimen on the new swarm.

### Recover from losing the quorum

Swarm is resilient to failures and can recover from any number
of temporary node failures (machine reboots or crash with restart) or other
transient errors. However, a swarm cannot automatically recover if it loses a
quorum. Tasks on existing worker nodes continue to run, but administrative
tasks are not possible, including scaling or updating services and joining or
removing nodes from the swarm. The best way to recover is to bring the missing
manager nodes back online. If that is not possible, continue reading for some
options for recovering your swarm.

In a swarm of `N` managers, a quorum (a majority) of manager nodes must always
be available. For example, in a swarm with five managers, a minimum of three must be
operational and in communication with each other. In other words, the swarm can
tolerate up to `(N-1)/2` permanent failures beyond which requests involving
swarm management cannot be processed. These types of failures include data
corruption or hardware failures.

If you lose the quorum of managers, you cannot administer the swarm. If you have
lost the quorum and you attempt to perform any management operation on the swarm,
an error occurs:

```text
Error response from daemon: rpc error: code = 4 desc = context deadline exceeded
```

The best way to recover from losing the quorum is to bring the failed nodes back
online. If you can't do that, the only way to recover from this state is to use
the `--force-new-cluster` action from a manager node. This removes all managers
except the manager the command was run from. The quorum is achieved because
there is now only one manager. Promote nodes to be managers until you have the
desired number of managers.

From the node to recover, run:

```console
$ docker swarm init --force-new-cluster --advertise-addr node01:2377
```

When you run the `docker swarm init` command with the `--force-new-cluster`
flag, the Docker Engine where you run the command becomes the manager node of a
single-node swarm which is capable of managing and running services. The manager
has all the previous information about services and tasks, worker nodes are
still part of the swarm, and services are still running. You need to add or
re-add  manager nodes to achieve your previous task distribution and ensure that
you have enough managers to maintain high availability and prevent losing the
quorum.

## Force the swarm to rebalance

Generally, you do not need to force the swarm to rebalance its tasks. When you
add a new node to a swarm, or a node reconnects to the swarm after a
period of unavailability, the swarm does not automatically give a workload to
the idle node. This is a design decision. If the swarm periodically shifted tasks
to different nodes for the sake of balance, the clients using those tasks would
be disrupted. The goal is to avoid disrupting running services for the sake of
balance across the swarm. When new tasks start, or when a node with running
tasks becomes unavailable, those tasks are given to less busy nodes. The goal
is eventual balance, with minimal disruption to the end user.

You can use the `--force` or `-f` flag with the `docker service update` command
to force the service to redistribute its tasks across the available worker nodes.
This causes the service tasks to restart. Client applications may be disrupted.
If you have configured it, your service uses a [rolling update](swarm-tutorial/rolling-update.md).

If you use an earlier version and you want to achieve an even balance of load
across workers and don't mind disrupting running tasks, you can force your swarm
to re-balance by temporarily scaling the service upward. Use
`docker service inspect --pretty <servicename>` to see the configured scale
of a service. When you use `docker service scale`, the nodes with the lowest
number of tasks are targeted to receive the new workloads. There may be multiple
under-loaded nodes in your swarm. You may need to scale the service up by modest
increments a few times to achieve the balance you want across all the nodes.

When the load is balanced to your satisfaction, you can scale the service back
down to the original scale. You can use `docker service ps` to assess the current
balance of your service across nodes.

See also
[`docker service scale`](/reference/cli/docker/service/scale/) and
[`docker service ps`](/reference/cli/docker/service/ps/).


---

# Store configuration data using Docker Configs

*Sección: Engine*

## About configs

Docker swarm service configs  allow you to store non-sensitive information,
such as configuration files, outside a service's image or running containers.
This allows you to keep your images as generic as possible, without the need to
bind-mount configuration files into the containers or use environment variables.

Configs operate in a similar way to [secrets](secrets.md), except that they are
not encrypted at rest and are mounted directly into the container's filesystem
without the use of RAM disks. Configs can be added or removed from a service at
any time, and services can share a config. You can even use configs in
conjunction with environment variables or labels, for maximum flexibility.
Config values can be generic strings or binary content (up to 500 kb in size).

> [!NOTE]
>
> Docker configs are only available to swarm services, not to
> standalone containers. To use this feature, consider adapting your container
> to run as a service with a scale of 1.

Configs are supported on both Linux and Windows services.

### Windows support

Docker includes support for configs on Windows containers, but there are differences
in the implementations, which are called out in the examples below. Keep the
following notable differences in mind:

- Config files with custom targets are not directly bind-mounted into Windows
  containers, since Windows does not support non-directory file bind-mounts.
  Instead, configs for a container are all mounted in
  `C:\ProgramData\Docker\internal\configs` (an implementation detail which
  should not be relied upon by applications) within the container. Symbolic
  links are used to point from there to the desired target of the config within
  the container. The default target is `C:\ProgramData\Docker\configs`.

- When creating a service which uses Windows containers, the options to specify
  UID, GID, and mode are not supported for configs. Configs are currently only
  accessible by administrators and users with `system` access within the
  container.

- On Windows, create or update a service using `--credential-spec` with the
  `config://<config-name>` format.  This passes the gMSA credentials file
  directly to nodes before a container starts. No gMSA credentials are written
  to disk on worker nodes. For more information, refer to
  [Deploy services to a swarm](services.md#gmsa-for-swarm).

## How Docker manages configs

When you add a config to the swarm, Docker sends the config to the swarm manager
over a mutual TLS connection. The config is stored in the Raft log, which is
encrypted. The entire Raft log is replicated across the other managers, ensuring
the same high availability guarantees for configs as for the rest of the swarm
management data.

When you grant a newly-created or running service access to a config, the config
is mounted as a file in the container. The location of the mount point within
the container defaults to `/<config-name>` in Linux containers. In Windows
containers, configs are all mounted into `C:\ProgramData\Docker\configs` and
symbolic links are created to the desired location, which defaults to
`C:\<config-name>`.

You can set the ownership (`uid` and `gid`) for the config, using either the
numerical ID or the name of the user or group. You can also specify the file
permissions (`mode`). These settings are ignored for Windows containers.

- If not set, the config is owned by the user running the container
  command (often `root`) and that user's default group (also often `root`).
- If not set, the config has world-readable permissions (mode `0444`), unless a
  `umask` is set within the container, in which case the mode is impacted by
  that `umask` value.

You can update a service to grant it access to additional configs or revoke its
access to a given config at any time.

A node only has access to configs if the node is a swarm manager or if it is
running service tasks which have been granted access to the config. When a
container task stops running, the configs shared to it are unmounted from the
in-memory filesystem for that container and flushed from the node's memory.

If a node loses connectivity to the swarm while it is running a task container
with access to a config, the task container still has access to its configs, but
cannot receive updates until the node reconnects to the swarm.

You can add or inspect an individual config at any time, or list all
configs. You cannot remove a config that a running service is
using. See [Rotate a config](configs.md#example-rotate-a-config) for a way to
remove a config without disrupting running services.

To update or roll back configs more easily, consider adding a version
number or date to the config name. This is made easier by the ability to control
the mount point of the config within a given container.

To update a stack, make changes to your Compose file, then re-run `docker
stack deploy -c <new-compose-file> <stack-name>`. If you use a new config in
that file, your services start using them. Keep in mind that configurations
are immutable, so you can't change the file for an existing service.
Instead, you create a new config to use a different file

You can run `docker stack rm` to stop the app and take down the stack. This
removes any config that was created by `docker stack deploy` with the same stack
name. This removes _all_ configs, including those not referenced by services and
those remaining after a `docker service update --config-rm`.

## Read more about `docker config` commands

Use these links to read about specific commands, or continue to the
[example about using configs with a service](#advanced-example-use-configs-with-a-nginx-service).

- [`docker config create`](/reference/cli/docker/config/create/)
- [`docker config inspect`](/reference/cli/docker/config/inspect/)
- [`docker config ls`](/reference/cli/docker/config/ls/)
- [`docker config rm`](/reference/cli/docker/config/rm/)

## Examples

This section includes graduated examples which illustrate how to use
Docker configs.

> [!NOTE]
>
> These examples use a single-engine swarm and unscaled services for
> simplicity. The examples use Linux containers, but Windows containers also
> support configs.

### Defining and using configs in compose files

The `docker stack` command supports defining configs in a Compose file.
However, the `configs` key is not supported for `docker compose`. See
[the Compose file reference](../../reference/compose-file/configs.md) for details.

### Simple example: Get started with configs

This simple example shows how configs work in just a few commands. For a
real-world example, continue to
[Advanced example: Use configs with a Nginx service](#advanced-example-use-configs-with-a-nginx-service).

1.  Add a config to Docker. The `docker config create` command reads standard
    input because the last argument, which represents the file to read the
    config from, is set to `-`.

    ```console
    $ echo "This is a config" | docker config create my-config -
    ```

2.  Create a `redis` service and grant it access to the config. By default,
    the container can access the config at `/my-config`, but
    you can customize the file name on the container using the `target` option.

    ```console
    $ docker service create --name redis --config my-config redis:alpine
    ```

3.  Verify that the task is running without issues using `docker service ps`. If
    everything is working, the output looks similar to this:

    ```console
    $ docker service ps redis

    ID            NAME     IMAGE         NODE              DESIRED STATE  CURRENT STATE          ERROR  PORTS
    bkna6bpn8r1a  redis.1  redis:alpine  ip-172-31-46-109  Running        Running 8 seconds ago
    ```

4.  Get the ID of the `redis` service task container using `docker ps`, so that
    you can use `docker container exec` to connect to the container and read the contents
    of the config data file, which defaults to being readable by all and has the
    same name as the name of the config. The first command below illustrates
    how to find the container ID, and the second and third commands use shell
    completion to do this automatically.

    ```console
    $ docker ps --filter name=redis -q

    5cb1c2348a59

    $ docker container exec $(docker ps --filter name=redis -q) ls -l /my-config

    -r--r--r--    1 root     root            12 Jun  5 20:49 my-config

    $ docker container exec $(docker ps --filter name=redis -q) cat /my-config

    This is a config
    ```

5.  Try removing the config. The removal fails because the `redis` service is
    running and has access to the config.

    ```console

    $ docker config ls

    ID                          NAME                CREATED             UPDATED
    fzwcfuqjkvo5foqu7ts7ls578   hello               31 minutes ago      31 minutes ago


    $ docker config rm my-config

    Error response from daemon: rpc error: code = 3 desc = config 'my-config' is
    in use by the following service: redis
    ```

6.  Remove access to the config from the running `redis` service by updating the
    service.

    ```console
    $ docker service update --config-rm my-config redis
    ```

7.  Repeat steps 3 and 4 again, verifying that the service no longer has access
    to the config. The container ID is different, because the
    `service update` command redeploys the service.

    ```console
    $ docker container exec -it $(docker ps --filter name=redis -q) cat /my-config

    cat: can't open '/my-config': No such file or directory
    ```

8.  Stop and remove the service, and remove the config from Docker.

    ```console
    $ docker service rm redis

    $ docker config rm my-config
    ```

### Simple example: Use configs in a Windows service

This is a very simple example which shows how to use configs with a Microsoft
IIS service running on Docker for Windows running Windows containers on
Microsoft Windows 10.  It is a naive example that stores the webpage in a config.

This example assumes that you have PowerShell installed.

1.  Save the following into a new file `index.html`.

    ```html
    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello Docker! You have deployed a HTML page.</p>
      </body>
    </html>
    ```

2.  If you have not already done so, initialize or join the swarm.

    ```powershell
    docker swarm init
    ```

3.  Save the `index.html` file as a swarm config named `homepage`.

    ```powershell
    docker config create homepage index.html
    ```

4.  Create an IIS service and grant it access to the `homepage` config.

    ```powershell
    docker service create
        --name my-iis
        --publish published=8000,target=8000
        --config src=homepage,target="\inetpub\wwwroot\index.html"
        microsoft/iis:nanoserver
    ```

5.  Access the IIS service at `http://localhost:8000/`. It should serve
    the HTML content from the first step.

6.  Remove the service and the config.

    ```powershell
    docker service rm my-iis

    docker config rm homepage
    ```

### Example: Use a templated config

To create a configuration in which the content will be generated using a
template engine, use the `--template-driver` parameter and specify the engine
name as its argument. The template will be rendered when container is created.

1.  Save the following into a new file `index.html.tmpl`.

    ```html
    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello {{ env "HELLO" }}! I'm service {{ .Service.Name }}.</p>
      </body>
    </html>
    ```

2.  Save the `index.html.tmpl` file as a swarm config named `homepage`. Provide
    parameter `--template-driver` and specify `golang` as template engine.

    ```console
    $ docker config create --template-driver golang homepage index.html.tmpl
    ```

3.  Create a service that runs Nginx and has access to the environment variable
    HELLO and to the config.

    ```console
    $ docker service create \
         --name hello-template \
         --env HELLO="Docker" \
         --config source=homepage,target=/usr/share/nginx/html/index.html \
         --publish published=3000,target=80 \
         nginx:alpine
    ```

4.  Verify that the service is operational: you can reach the Nginx server, and
    that the correct output is being served.

    ```console
    $ curl http://0.0.0.0:3000

    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello Docker! I'm service hello-template.</p>
      </body>
    </html>
    ```

### Advanced example: Use configs with a Nginx service

This example is divided into two parts.
[The first part](#generate-the-site-certificate) is all about generating
the site certificate and does not directly involve Docker configs at all, but
it sets up [the second part](#configure-the-nginx-container), where you store
and use the site certificate as a series of secrets and the Nginx configuration
as a config. The example shows how to set options on the config, such as the
target location within the container and the file permissions (`mode`).

#### Generate the site certificate

Generate a root CA and TLS certificate and key for your site. For production
sites, you may want to use a service such as `Let’s Encrypt` to generate the
TLS certificate and key, but this example uses command-line tools. This step
is a little complicated, but is only a set-up step so that you have
something to store as a Docker secret. If you want to skip these sub-steps,
you can [use Let's Encrypt](https://letsencrypt.org/getting-started/) to
generate the site key and certificate, name the files `site.key` and
`site.crt`, and skip to
[Configure the Nginx container](#configure-the-nginx-container).

1.  Generate a root key.

    ```console
    $ openssl genrsa -out "root-ca.key" 4096
    ```

2.  Generate a CSR using the root key.

    ```console
    $ openssl req \
              -new -key "root-ca.key" \
              -out "root-ca.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA'
    ```

3.  Configure the root CA. Edit a new file called `root-ca.cnf` and paste
    the following contents into it. This constrains the root CA to only sign
    leaf certificates and not intermediate CAs.

    ```ini
    [root_ca]
    basicConstraints = critical,CA:TRUE,pathlen:1
    keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
    subjectKeyIdentifier=hash
    ```

4.  Sign the certificate.

    ```console
    $ openssl x509 -req -days 3650 -in "root-ca.csr" \
                   -signkey "root-ca.key" -sha256 -out "root-ca.crt" \
                   -extfile "root-ca.cnf" -extensions \
                   root_ca
    ```

5.  Generate the site key.

    ```console
    $ openssl genrsa -out "site.key" 4096
    ```

6.  Generate the site certificate and sign it with the site key.

    ```console
    $ openssl req -new -key "site.key" -out "site.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'
    ```

7.  Configure the site certificate. Edit a new file called `site.cnf` and
    paste the following contents into it. This constrains the site
    certificate so that it can only be used to authenticate a server and
    can't be used to sign certificates.

    ```ini
    [server]
    authorityKeyIdentifier=keyid,issuer
    basicConstraints = critical,CA:FALSE
    extendedKeyUsage=serverAuth
    keyUsage = critical, digitalSignature, keyEncipherment
    subjectAltName = DNS:localhost, IP:127.0.0.1
    subjectKeyIdentifier=hash
    ```

8.  Sign the site certificate.

    ```console
    $ openssl x509 -req -days 750 -in "site.csr" -sha256 \
        -CA "root-ca.crt" -CAkey "root-ca.key" -CAcreateserial \
        -out "site.crt" -extfile "site.cnf" -extensions server
    ```

9.  The `site.csr` and `site.cnf` files are not needed by the Nginx service, but
    you need them if you want to generate a new site certificate. Protect
    the `root-ca.key` file.

#### Configure the Nginx container

1.  Produce a very basic Nginx configuration that serves static files over HTTPS.
    The TLS certificate and key are stored as Docker secrets so that they
    can be rotated easily.

    In the current directory, create a new file called `site.conf` with the
    following contents:

    ```nginx
    server {
        listen                443 ssl;
        server_name           localhost;
        ssl_certificate       /run/secrets/site.crt;
        ssl_certificate_key   /run/secrets/site.key;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
    ```

2.  Create two secrets, representing the key and the certificate. You can store
    any file as a secret as long as it is smaller than 500 KB. This allows you
    to decouple the key and certificate from the services that use them.
    In these examples, the secret name and the file name are the same.

    ```console
    $ docker secret create site.key site.key

    $ docker secret create site.crt site.crt
    ```

3.  Save the `site.conf` file in a Docker config. The first parameter is the
    name of the config, and the second parameter is the file to read it from.

    ```console
    $ docker config create site.conf site.conf
    ```

    List the configs:

    ```console
    $ docker config ls

    ID                          NAME                CREATED             UPDATED
    4ory233120ccg7biwvy11gl5z   site.conf           4 seconds ago       4 seconds ago
    ```


4.  Create a service that runs Nginx and has access to the two secrets and the
    config. Set the mode to `0440` so that the file is only readable by its
    owner and that owner's group, not the world.

    ```console
    $ docker service create \
         --name nginx \
         --secret site.key \
         --secret site.crt \
         --config source=site.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \
         --publish published=3000,target=443 \
         nginx:latest \
         sh -c "exec nginx -g 'daemon off;'"
    ```

    Within the running containers, the following three files now exist:

    - `/run/secrets/site.key`
    - `/run/secrets/site.crt`
    - `/etc/nginx/conf.d/site.conf`

5.  Verify that the Nginx service is running.

    ```console
    $ docker service ls

    ID            NAME   MODE        REPLICAS  IMAGE
    zeskcec62q24  nginx  replicated  1/1       nginx:latest

    $ docker service ps nginx

    NAME                  IMAGE         NODE  DESIRED STATE  CURRENT STATE          ERROR  PORTS
    nginx.1.9ls3yo9ugcls  nginx:latest  moby  Running        Running 3 minutes ago
    ```

6.  Verify that the service is operational: you can reach the Nginx
    server, and that the correct TLS certificate is being used.

    ```console
    $ curl --cacert root-ca.crt https://0.0.0.0:3000

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>

    <p>For online documentation and support, refer to
    <a href="https://nginx.org">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="https://www.nginx.com">www.nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    ```

    ```console
    $ openssl s_client -connect 0.0.0.0:3000 -CAfile root-ca.crt

    CONNECTED(00000003)
    depth=1 /C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    verify return:1
    depth=0 /C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
    verify return:1
    ---
    Certificate chain
     0 s:/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
       i:/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    …
    -----END CERTIFICATE-----
    subject=/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
    issuer=/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1663 bytes and written 712 bytes
    ---
    New, TLSv1/SSLv3, Cipher is AES256-SHA
    Server public key is 4096 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : AES256-SHA
        Session-ID: A1A8BF35549C5715648A12FD7B7E3D861539316B03440187D9DA6C2E48822853
        Session-ID-ctx:
        Master-Key: F39D1B12274BA16D3A906F390A61438221E381952E9E1E05D3DD784F0135FB81353DA38C6D5C021CB926E844DFC49FC4
        Key-Arg   : None
        Start Time: 1481685096
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    ```

7.  Unless you are going to continue to the next example, clean up after running
    this example by removing the `nginx` service and the stored secrets and
    config.

    ```console
    $ docker service rm nginx

    $ docker secret rm site.crt site.key

    $ docker config rm site.conf
    ```

You have now configured a Nginx service with its configuration decoupled from
its image. You could run multiple sites with exactly the same image but
separate configurations, without the need to build a custom image at all.

### Example: Rotate a config

To rotate a config, you first save a new config with a different name than the
one that is currently in use. You then redeploy the service, removing the old
config and adding the new config at the same mount point within the container.
This example builds upon the previous one by rotating the `site.conf`
configuration file.

1.  Edit the `site.conf` file locally. Add `index.php` to the `index` line, and
    save the file.

    ```nginx
    server {
        listen                443 ssl;
        server_name           localhost;
        ssl_certificate       /run/secrets/site.crt;
        ssl_certificate_key   /run/secrets/site.key;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm index.php;
        }
    }
    ```

2.  Create a new Docker config using the new `site.conf`, called `site-v2.conf`.

    ```bah
    $ docker config create site-v2.conf site.conf
    ```

3.  Update the `nginx` service to use the new config instead of the old one.

    ```console
    $ docker service update \
      --config-rm site.conf \
      --config-add source=site-v2.conf,target=/etc/nginx/conf.d/site.conf,mode=0440 \
      nginx
    ```

4.  Verify that the `nginx` service is fully re-deployed, using
    `docker service ps nginx`. When it is, you can remove the old `site.conf`
    config.

    ```console
    $ docker config rm site.conf
    ```

5.  To clean up, you can remove the `nginx` service, as well as the secrets and
    configs.

    ```console
    $ docker service rm nginx

    $ docker secret rm site.crt site.key

    $ docker config rm site-v2.conf
    ```

You have now updated your `nginx` service's configuration without the need to
rebuild its image.


---

# How swarm works

*Sección: Engine*




---

# How nodes work

*Sección: Engine*

Swarm mode lets you create a
cluster of one or more Docker Engines called a swarm. A swarm consists
of one or more nodes: physical or virtual machines running Docker
Engine.

There are two types of nodes: [managers](#manager-nodes) and
[workers](#worker-nodes).

![Swarm mode cluster](/engine/swarm/images/swarm-diagram.webp)

If you haven't already, read through the
[Swarm mode overview](../index.md) and
[key concepts](../key-concepts.md).

## Manager nodes

Manager nodes handle cluster management tasks:

* Maintaining cluster state
* Scheduling services
* Serving Swarm mode [HTTP API endpoints](../../../reference/api/engine/index.md)

Using a [Raft](https://raft.github.io/raft.pdf) implementation, the managers
maintain a consistent internal state of the entire swarm and all the services
running on it. For testing purposes it is OK to run a swarm with a single
manager. If the manager in a single-manager swarm fails, your services
continue to run, but you need to create a new cluster to recover.

To take advantage of Swarm mode's fault-tolerance features, we recommend
you implement an odd number of nodes according to your organization's
high-availability requirements. When you have multiple managers you can recover
from the failure of a manager node without downtime.

* A three-manager swarm tolerates a maximum loss of one manager.
* A five-manager swarm tolerates a maximum simultaneous loss of two
manager nodes.
* An odd number `N` of manager nodes in the cluster tolerates the loss of at most `(N-1)/2` managers.
Docker recommends a maximum of seven manager nodes for a swarm.

    > [!IMPORTANT]
    >
    > Adding more managers does NOT mean increased scalability or higher performance. In general, the opposite is true.

## Worker nodes

Worker nodes are also instances of Docker Engine whose sole purpose is to
execute containers. Worker nodes don't participate in the Raft distributed
state, make scheduling decisions, or serve the swarm mode HTTP API.

You can create a swarm of one manager node, but you cannot have a worker node
without at least one manager node. By default, all managers are also workers.
In a single manager node cluster, you can run commands like `docker service
create` and the scheduler places all tasks on the local engine.

To prevent the scheduler from placing tasks on a manager node in a multi-node
swarm, set the availability for the manager node to `Drain`. The scheduler
gracefully stops tasks on nodes in `Drain` mode and schedules the tasks on an
`Active` node. The scheduler does not assign new tasks to nodes with `Drain`
availability.

Refer to the [`docker node update`](/reference/cli/docker/node/update/)
command line reference to see how to change node availability.

## Change roles

You can promote a worker node to be a manager by running `docker node promote`.
For example, you may want to promote a worker node when you
take a manager node offline for maintenance. See [node promote](/reference/cli/docker/node/promote/).

You can also demote a manager node to a worker node. See
[node demote](/reference/cli/docker/node/demote/).


## Learn more

* Read about how Swarm mode [services](services.md) work.
* Learn how [PKI](pki.md) works in Swarm mode.


---

# Manage swarm security with public key infrastructure (PKI)

*Sección: Engine*

The Swarm mode public key infrastructure (PKI) system built into Docker
makes it simple to securely deploy a container orchestration system. The nodes
in a swarm use mutual Transport Layer Security (TLS) to authenticate, authorize,
and encrypt the communications with other nodes in the swarm.

When you create a swarm by running `docker swarm init`, Docker designates itself
as a manager node. By default, the manager node generates a new root Certificate
Authority (CA) along with a key pair, which are used to secure communications
with other nodes that join the swarm. If you prefer, you can specify your own
externally-generated root CA, using the `--external-ca` flag of the
[docker swarm init](/reference/cli/docker/swarm/init/) command.

The manager node also generates two tokens to use when you join additional nodes
to the swarm: one worker token and one manager token. Each token
includes the digest of the root CA's certificate and a randomly generated
secret. When a node joins the swarm, the joining node uses the digest to
validate the root CA certificate from the remote manager. The remote manager
uses the secret to ensure the joining node is an approved node.

Each time a new node joins the swarm, the manager issues a certificate to the
node. The certificate contains a randomly generated node ID to identify the node
under the certificate common name (CN) and the role under the organizational
unit (OU). The node ID serves as the cryptographically secure node identity for
the lifetime of the node in the current swarm.

The diagram below illustrates how manager nodes and worker nodes encrypt
communications using a minimum of TLS 1.2.

![TLS diagram](/engine/swarm/images/tls.webp?w=600)

The example below shows the information from a certificate from a worker node:

```text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            3b:1c:06:91:73:fb:16:ff:69:c3:f7:a2:fe:96:c1:73:e2:80:97:3b
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: CN=swarm-ca
        Validity
            Not Before: Aug 30 02:39:00 2016 GMT
            Not After : Nov 28 03:39:00 2016 GMT
        Subject: O=ec2adilxf4ngv7ev8fwsi61i7, OU=swarm-worker, CN=dw02poa4vqvzxi5c10gm4pq2g
...snip...
```

By default, each node in the swarm renews its certificate every three months.
You can configure this interval by running the `docker swarm update
--cert-expiry <TIME PERIOD>` command. The minimum rotation value is 1 hour.
Refer to the
[docker swarm update](/reference/cli/docker/swarm/update/) CLI
reference for details.

## Rotating the CA certificate

> [!NOTE]
>
> Mirantis Kubernetes Engine (MKE), formerly known as Docker UCP, provides an external
> certificate manager service for the swarm. If you run swarm on MKE, you shouldn't
> rotate the CA certificates manually. Instead, contact Mirantis support if you need
> to rotate a certificate.

In the event that a cluster CA key or a manager node is compromised, you can
rotate the swarm root CA so that none of the nodes trust certificates
signed by the old root CA anymore.

Run `docker swarm ca --rotate` to generate a new CA certificate and key. If you
prefer, you can pass the `--ca-cert` and `--external-ca` flags to specify the
root certificate and to use a root CA external to the swarm. Alternately,
you can pass the `--ca-cert` and `--ca-key` flags to specify the exact
certificate and key you would like the swarm to use.

When you issue the `docker swarm ca --rotate` command, the following things
happen in sequence:

1.  Docker generates a cross-signed certificate. This means that a version of
    the new root CA certificate is signed with the old root CA certificate.
    This cross-signed certificate is used as an intermediate certificate for all
    new node certificates. This ensures that nodes that still trust the old root
    CA can still validate a certificate signed by the new CA.

2.  Docker also tells all nodes to immediately renew their TLS certificates.
    This process may take several minutes, depending on the number of nodes in
    the swarm.

3.  After every node in the swarm has a new TLS certificate signed by the new CA,
    Docker forgets about the old CA certificate and key material, and tells
    all the nodes to trust the new CA certificate only.

    This also causes a change in the swarm's join tokens. The previous
    join tokens are no longer valid.

From this point on, all new node certificates issued are signed with the new
root CA, and do not contain any intermediates.

## Learn More

* Read about how [nodes](nodes.md) work.
* Learn how Swarm mode [services](services.md) work.


---

# How services work

*Sección: Engine*

To deploy an application image when Docker Engine is in Swarm mode, you create a
service. Frequently a service is the image for a microservice within the
context of some larger application. Examples of services might include an HTTP
server, a database, or any other type of executable program that you wish to run
in a distributed environment.

When you create a service, you specify which container image to use and which
commands to execute inside running containers. You also define options for the
service including:

- The port where the swarm makes the service available outside the swarm
- An overlay network for the service to connect to other services in the swarm
- CPU and memory limits and reservations
- A rolling update policy
- The number of replicas of the image to run in the swarm

## Services, tasks, and containers

When you deploy the service to the swarm, the swarm manager accepts your service
definition as the desired state for the service. Then it schedules the service
on nodes in the swarm as one or more replica tasks. The tasks run independently
of each other on nodes in the swarm.

For example, imagine you want to load balance between three instances of an HTTP
listener. The diagram below shows an HTTP listener service with three replicas.
Each of the three instances of the listener is a task in the swarm.

![HTTP listener service with three replicas](../images/services-diagram.webp?w=550)

A container is an isolated process. In the Swarm mode model, each task invokes
exactly one container. A task is analogous to a “slot” where the scheduler
places a container. Once the container is live, the scheduler recognizes that
the task is in a running state. If the container fails health checks or
terminates, the task terminates.

## Tasks and scheduling

A task is the atomic unit of scheduling within a swarm. When you declare a
desired service state by creating or updating a service, the orchestrator
realizes the desired state by scheduling tasks. For instance, you define a
service that instructs the orchestrator to keep three instances of an HTTP
listener running at all times. The orchestrator responds by creating three
tasks. Each task is a slot that the scheduler fills by spawning a container. The
container is the instantiation of the task. If an HTTP listener task subsequently
fails its health check or crashes, the orchestrator creates a new replica task
that spawns a new container.

A task is a one-directional mechanism. It progresses monotonically through a
series of states: `ASSIGNED`, `PREPARING`, `RUNNING`, etc. If the task fails, the
orchestrator removes the task and its container and then creates a new task to
replace it according to the desired state specified by the service.

The underlying logic of Docker's Swarm mode is a general purpose scheduler and
orchestrator. The service and task abstractions themselves are unaware of the
containers they implement. Hypothetically, you could implement other types of
tasks such as virtual machine tasks or non-containerized process tasks. The
scheduler and orchestrator are agnostic about the type of the task. However, Docker only supports container tasks.

The diagram below shows how Swarm mode accepts service create requests and
schedules tasks to worker nodes.

![Services flow](../images/service-lifecycle.webp?w=700)

### Pending services

A service may be configured in such a way that no node currently in the
swarm can run its tasks. In this case, the service remains in state `pending`.
Here are a few examples of when a service might remain in state `pending`.

> [!TIP]
> If your only intention is to prevent a service from
> being deployed, scale the service to 0 instead of trying to configure it in
> such a way that it remains in `pending`.

- If all nodes are paused or drained, and you create a service, it is
  pending until a node becomes available. In reality, the first node to become
  available gets all of the tasks, so this is not a good thing to do in a
  production environment.

- You can reserve a specific amount of memory for a service. If no node in the
  swarm has the required amount of memory, the service remains in a pending
  state until a node is available which can run its tasks. If you specify a very
  large value, such as 500 GB, the task stays pending forever, unless you
  really have a node which can satisfy it.

- You can impose placement constraints on the service, and the constraints may
  not be able to be honored at a given time.

This behavior illustrates that the requirements and configuration of your tasks
are not tightly tied to the current state of the swarm. As the administrator of
a swarm, you declare the desired state of your swarm, and the manager works with
the nodes in the swarm to create that state. You do not need to micro-manage the
tasks on the swarm.

## Replicated and global services

There are two types of service deployments, replicated and global.

For a replicated service, you specify the number of identical tasks you want to
run. For example, you decide to deploy an HTTP service with three replicas, each
serving the same content.

A global service is a service that runs one task on every node. There is no
pre-specified number of tasks. Each time you add a node to the swarm, the
orchestrator creates a task and the scheduler assigns the task to the new node.
Good candidates for global services are monitoring agents, anti-virus scanners
or other types of containers that you want to run on every node in the swarm.

The diagram below shows a three-service replica in gray and a global service
in black.

![Global vs replicated services](../images/replicated-vs-global.webp?w=450)

## Learn more

- Read about how Swarm mode [nodes](nodes.md) work.
- Learn how [PKI](pki.md) works in Swarm mode.


---

# Swarm task states

*Sección: Engine*

Docker lets you create services, which can start tasks. A service is a
description of a desired state, and a task does the work. Work is scheduled on
swarm nodes in this sequence:

1.  Create a service by using `docker service create`.
2.  The request goes to a Docker manager node.
3.  The Docker manager node schedules the service to run on particular nodes.
4.  Each service can start multiple tasks.
5.  Each task has a life cycle, with states like `NEW`, `PENDING`, and `COMPLETE`.

Tasks are execution units that run once to completion. When a task stops, it
isn't executed again, but a new task may take its place.

Tasks advance through a number of states until they complete or fail. Tasks are
initialized in the `NEW` state. The task progresses forward through a number of
states, and its state doesn't go backward. For example, a task never goes from
`COMPLETE` to `RUNNING`.

Tasks go through the states in the following order:

| Task state  | Description                                                                                                 |
| ----------- | ----------------------------------------------------------------------------------------------------------- |
| `NEW`       | The task was initialized.                                                                                   |
| `PENDING`   | Resources for the task were allocated.                                                                      |
| `ASSIGNED`  | Docker assigned the task to nodes.                                                                          |
| `ACCEPTED`  | The task was accepted by a worker node. If a worker node rejects the task, the state changes to `REJECTED`. |
| `READY`     | The worker node is ready to start the task                                                                  |
| `PREPARING` | Docker is preparing the task.                                                                               |
| `STARTING`  | Docker is starting the task.                                                                                |
| `RUNNING`   | The task is executing.                                                                                      |
| `COMPLETE`  | The task exited without an error code.                                                                      |
| `FAILED`    | The task exited with an error code.                                                                         |
| `SHUTDOWN`  | Docker requested the task to shut down.                                                                     |
| `REJECTED`  | The worker node rejected the task.                                                                          |
| `ORPHANED`  | The node was down for too long.                                                                             |
| `REMOVE`    | The task is not terminal but the associated service was removed or scaled down.                             |

## View task state

Run `docker service ps <service-name>` to get the state of a task. The
`CURRENT STATE` field shows the task's state and how long it's been
there.

```console
$ docker service ps webserver
ID             NAME              IMAGE    NODE        DESIRED STATE  CURRENT STATE            ERROR                              PORTS
owsz0yp6z375   webserver.1       nginx    UbuntuVM    Running        Running 44 seconds ago
j91iahr8s74p    \_ webserver.1   nginx    UbuntuVM    Shutdown       Failed 50 seconds ago    "No such container: webserver.…"
7dyaszg13mw2    \_ webserver.1   nginx    UbuntuVM    Shutdown       Failed 5 hours ago       "No such container: webserver.…"
```

## Where to go next

- [Learn about swarm tasks](https://github.com/moby/swarmkit/blob/master/design/task_model.md)


---

# Use Swarm mode routing mesh

*Sección: Engine*

Docker Engine Swarm mode makes it easy to publish ports for services to make
them available to resources outside the swarm. All nodes participate in an
ingress routing mesh. The routing mesh enables each node in the swarm to
accept connections on published ports for any service running in the swarm, even
if there's no task running on the node. The routing mesh routes all
incoming requests to published ports on available nodes to an active container.

To use the ingress network in the swarm, you need to have the following
ports open between the swarm nodes before you enable Swarm mode:

* Port `7946` TCP/UDP for container network discovery.
* Port `4789` UDP (configurable) for the container ingress network.

When setting up networking in a Swarm, special care should be taken. Consult
the [tutorial](swarm-tutorial/index.md#open-protocols-and-ports-between-the-hosts)
for an overview.

You must also open the published port between the swarm nodes and any external
resources, such as an external load balancer, that require access to the port.

You can also [bypass the routing mesh](#bypass-the-routing-mesh) for a given
service.

## Publish a port for a service

Use the `--publish` flag to publish a port when you create a service. `target`
is used to specify the port inside the container, and `published` is used to
specify the port to bind on the routing mesh. If you leave off the `published`
port, a random high-numbered port is bound for each service task. You
need to inspect the task to determine the port.

```console
$ docker service create \
  --name <SERVICE-NAME> \
  --publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <IMAGE>
```

> [!NOTE]
>
> The older form of this syntax is a colon-separated string, where
> the published port is first and the target port is second, such as
> `-p 8080:80`. The new syntax is preferred because it is easier to read and
> allows more flexibility.

The `<PUBLISHED-PORT>` is the port where the swarm makes the service available.
If you omit it, a random high-numbered port is bound.
The `<CONTAINER-PORT>` is the port where the container listens. This parameter
is required.

For example, the following command publishes port 80 in the nginx container to
port 8080 for any node in the swarm:

```console
$ docker service create \
  --name my-web \
  --publish published=8080,target=80 \
  --replicas 2 \
  nginx
```

When you access port 8080 on any node, Docker routes your request to an active
container. On the swarm nodes themselves, port 8080 may not actually be bound,
but the routing mesh knows how to route the traffic and prevents any port
conflicts from happening.

The routing mesh listens on the published port for any IP address assigned to
the node. For externally routable IP addresses, the port is available from
outside the host. For all other IP addresses the access is only available from
within the host.

![Service ingress image](images/ingress-routing-mesh.webp)

You can publish a port for an existing service using the following command:

```console
$ docker service update \
  --publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
  <SERVICE>
```

You can use `docker service inspect` to view the service's published port. For
instance:


```console
$ docker service inspect --format="{{json .Endpoint.Spec.Ports}}" my-web

[{"Protocol":"tcp","TargetPort":80,"PublishedPort":8080}]
```


The output shows the `<CONTAINER-PORT>` (labeled `TargetPort`) from the containers and the
`<PUBLISHED-PORT>` (labeled `PublishedPort`) where nodes listen for requests for the service.

### Publish a port for TCP only or UDP only

By default, when you publish a port, it is a TCP port. You can
specifically publish a UDP port instead of or in addition to a TCP port. When
you publish both TCP and UDP ports, if you omit the protocol specifier,
the port is published as a TCP port. If you use the longer syntax (recommended),
set the `protocol` key to either `tcp` or `udp`.

#### TCP only

Long syntax:

```console
$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  dns-cache
```

Short syntax:

```console
$ docker service create --name dns-cache \
  -p 53:53 \
  dns-cache
```

#### TCP and UDP

Long syntax:

```console
$ docker service create --name dns-cache \
  --publish published=53,target=53 \
  --publish published=53,target=53,protocol=udp \
  dns-cache
```

Short syntax:

```console
$ docker service create --name dns-cache \
  -p 53:53 \
  -p 53:53/udp \
  dns-cache
```

#### UDP only

Long syntax:

```console
$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp \
  dns-cache
```

Short syntax:

```console
$ docker service create --name dns-cache \
  -p 53:53/udp \
  dns-cache
```

## Bypass the routing mesh

By default, swarm services which publish ports do so using the routing mesh.
When you connect to a published port on any swarm node (whether it is running a
given service or not), you are redirected to a worker which is running that
service, transparently. Effectively, Docker acts as a load balancer for your
swarm services.

You can bypass the routing mesh, so that when you access the bound port on a
given node, you are always accessing the instance of the service running on
that node. This is referred to as `host` mode. There are a few things to keep
in mind.

- If you access a node which is not running a service task, the service does not
  listen on that port. It is possible that nothing is listening, or
  that a completely different application is listening.

- If you expect to run multiple service tasks on each node (such as when you
  have 5 nodes but run 10 replicas), you cannot specify a static target port.
  Either allow Docker to assign a random high-numbered port (by leaving off the
  `published`), or ensure that only a single instance of the service runs on a
  given node, by using a global service rather than a replicated one, or by
  using placement constraints.

To bypass the routing mesh, you must use the long `--publish` service and
set `mode` to `host`. If you omit the `mode` key or set it to `ingress`, the
routing mesh is used. The following command creates a global service using
`host` mode and bypassing the routing mesh.

```console
$ docker service create --name dns-cache \
  --publish published=53,target=53,protocol=udp,mode=host \
  --mode global \
  dns-cache
```

## Configure an external load balancer

You can configure an external load balancer for swarm services, either in
combination with the routing mesh or without using the routing mesh at all.

### Using the routing mesh

You can configure an external load balancer to route requests to a swarm
service. For example, you could configure [HAProxy](https://www.haproxy.org) to
balance requests to an nginx service published to port 8080.

![Ingress with external load balancer image](images/ingress-lb.webp)

In this case, port 8080 must be open between the load balancer and the nodes in
the swarm. The swarm nodes can reside on a private network that is accessible to
the proxy server, but that is not publicly accessible.

You can configure the load balancer to balance requests between every node in
the swarm even if there are no tasks scheduled on the node. For example, you
could have the following HAProxy configuration in `/etc/haproxy/haproxy.cfg`:

```bash
global
        log /dev/log    local0
        log /dev/log    local1 notice
...snip...

# Configure HAProxy to listen on port 80
frontend http_front
   bind *:80
   stats uri /haproxy?stats
   default_backend http_back

# Configure HAProxy to route requests to swarm nodes on port 8080
backend http_back
   balance roundrobin
   server node1 192.168.99.100:8080 check
   server node2 192.168.99.101:8080 check
   server node3 192.168.99.102:8080 check
```

When you access the HAProxy load balancer on port 80, it forwards requests to
nodes in the swarm. The swarm routing mesh routes the request to an active task.
If, for any reason the swarm scheduler dispatches tasks to different nodes, you
don't need to reconfigure the load balancer.

You can configure any type of load balancer to route requests to swarm nodes.
To learn more about HAProxy, see the [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/).

### Without the routing mesh

To use an external load balancer without the routing mesh, set `--endpoint-mode`
to `dnsrr` instead of the default value of `vip`. In this case, there is not a
single virtual IP. Instead, Docker sets up DNS entries for the service such that
a DNS query for the service name returns a list of IP addresses, and the client
connects directly to one of these.

You can't use `--endpoint-mode dnsrr` together with `--publish mode=ingress`.
You must run your own load balancer in front of the service. A DNS query for
the service name on the Docker host returns a list of IP addresses for the
nodes running the service. Configure your load balancer to consume this list
and balance the traffic across the nodes.
See [Configure service discovery](networking.md#configure-service-discovery).

## Learn more

* [Deploy services to a swarm](services.md)


---

# Join nodes to a swarm

*Sección: Engine*

When you first create a swarm, you place a single Docker Engine into
Swarm mode. To take full advantage of Swarm mode you can add nodes to the swarm:

* Adding worker nodes increases capacity. When you deploy a service to a swarm,
the engine schedules tasks on available nodes whether they are worker nodes or
manager nodes. When you add workers to your swarm, you increase the scale of
the swarm to handle tasks without affecting the manager raft consensus.
* Manager nodes increase fault-tolerance. Manager nodes perform the
orchestration and cluster management functions for the swarm. Among manager
nodes, a single leader node conducts orchestration tasks. If a leader node
goes down, the remaining manager nodes elect a new leader and resume
orchestration and maintenance of the swarm state. By default, manager nodes
also run tasks.

Docker Engine joins the swarm depending on the **join-token** you provide to
the `docker swarm join` command. The node only uses the token at join time. If
you subsequently rotate the token, it doesn't affect existing swarm nodes. Refer
to [Run Docker Engine in swarm mode](swarm-mode.md#view-the-join-command-or-update-a-swarm-join-token).

## Join as a worker node

To retrieve the join command including the join token for worker nodes, run the
following command on a manager node:

```console
$ docker swarm join-token worker

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
    192.168.99.100:2377
```

Run the command from the output on the worker to join the swarm:

```console
$ docker swarm join \
  --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
  192.168.99.100:2377

This node joined a swarm as a worker.
```

The `docker swarm join` command does the following:

* Switches Docker Engine on the current node into Swarm mode.
* Requests a TLS certificate from the manager.
* Names the node with the machine hostname.
* Joins the current node to the swarm at the manager listen address based upon the swarm token.
* Sets the current node to `Active` availability, meaning it can receive tasks
from the scheduler.
* Extends the `ingress` overlay network to the current node.

## Join as a manager node

When you run `docker swarm join` and pass the manager token, Docker Engine
switches into Swarm mode the same as for workers. Manager nodes also participate
in the raft consensus. The new nodes should be `Reachable`, but the existing
manager remains the swarm `Leader`.

Docker recommends three or five manager nodes per cluster to implement high
availability. Because Swarm-mode manager nodes share data using Raft, there
must be an odd number of managers. The swarm can continue to function after as
long as a quorum of more than half of the manager nodes are available.

For more detail about swarm managers and administering a swarm, see
[Administer and maintain a swarm of Docker Engines](admin-guide.md).

To retrieve the join command including the join token for manager nodes, run the
following command on a manager node:

```console
$ docker swarm join-token manager

To add a manager to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-61ztec5kyafptydic6jfc1i33t37flcl4nuipzcusor96k7kby-5vy9t8u35tuqm7vh67lrz9xp6 \
    192.168.99.100:2377
```

Run the command from the output on the new manager node to join it to the swarm:

```console
$ docker swarm join \
  --token SWMTKN-1-61ztec5kyafptydic6jfc1i33t37flcl4nuipzcusor96k7kby-5vy9t8u35tuqm7vh67lrz9xp6 \
  192.168.99.100:2377

This node joined a swarm as a manager.
```

## Learn More

* `swarm join` [command line reference](/reference/cli/docker/swarm/join/)
* [Swarm mode tutorial](swarm-tutorial/index.md)


---

# Swarm mode key concepts

*Sección: Engine*

This topic introduces some of the concepts unique to the cluster management and
orchestration features of Docker Engine 1.12.

## What is a swarm?

The cluster management and orchestration features embedded in Docker Engine
are built using [swarmkit](https://github.com/docker/swarmkit/). Swarmkit is a
separate project which implements Docker's orchestration layer and is used
directly within Docker.

A swarm consists of multiple Docker hosts which run in Swarm mode and act as
managers, to manage membership and delegation, and workers, which run
[swarm services](#services-and-tasks). A given Docker host can
be a manager, a worker, or perform both roles. When you create a service, you
define its optimal state - number of replicas, network and storage resources
available to it, ports the service exposes to the outside world, and more.
Docker works to maintain that desired state. For instance, if a worker node
becomes unavailable, Docker schedules that node's tasks on other nodes. A task
is a running container which is part of a swarm service and is managed by a
swarm manager, as opposed to a standalone container.

One of the key advantages of swarm services over standalone containers is that
you can modify a service's configuration, including the networks and volumes it
is connected to, without the need to manually restart the service. Docker will
update the configuration, stop the service tasks with out of date
configuration, and create new ones matching the desired configuration.

When Docker is running in Swarm mode, you can still run standalone containers
on any of the Docker hosts participating in the swarm, as well as swarm
services. A key difference between standalone containers and swarm services is
that only swarm managers can manage a swarm, while standalone containers can be
started on any daemon. Docker daemons can participate in a swarm as managers,
workers, or both.

In the same way that you can use [Docker Compose](../../compose/index.md) to define and run
containers, you can define and run [Swarm service](services.md) stacks.

Keep reading for details about concepts related to Docker swarm services,
including nodes, services, tasks, and load balancing.

## Nodes

A node is an instance of Docker Engine participating in the swarm. You can also think of this as a Docker node. You can run one or more nodes on a single physical computer or cloud server, but production swarm deployments typically include Docker nodes distributed across multiple physical and cloud machines.

To deploy your application to a swarm, you submit a service definition to a
manager node. The manager node dispatches units of work called
[tasks](#services-and-tasks) to worker nodes.

Manager nodes also perform the orchestration and cluster management functions
required to maintain the desired state of the swarm. Manager nodes select a
single leader to conduct orchestration tasks.

Worker nodes receive and execute tasks dispatched from manager nodes.
By default manager nodes also run services as worker nodes, but you can
configure them to run manager tasks exclusively and be manager-only
nodes. An agent runs on each worker node and reports on the tasks assigned to
it. The worker node notifies the manager node of the current state of its
assigned tasks so that the manager can maintain the desired state of each
worker.

## Services and tasks

A service is the definition of the tasks to execute on the manager or worker nodes. It
is the central structure of the swarm system and the primary root of user
interaction with the swarm.

When you create a service, you specify which container image to use and which
commands to execute inside running containers.

In the replicated services model, the swarm manager distributes a specific
number of replica tasks among the nodes based upon the scale you set in the
desired state.

For global services, the swarm runs one task for the service on every
available node in the cluster.

A task carries a Docker container and the commands to run inside the
container. It is the atomic scheduling unit of swarm. Manager nodes assign tasks
to worker nodes according to the number of replicas set in the service scale.
Once a task is assigned to a node, it cannot move to another node. It can only
run on the assigned node or fail.

## Load balancing

The swarm manager uses ingress load balancing to expose the services you
want to make available externally to the swarm. The swarm manager can
automatically assign the service a published port or you can configure a
published port for the service. You can specify any unused port. If you do not
specify a port, the swarm manager assigns the service a port in the 30000-32767
range.

External components, such as cloud load balancers, can access the service on the
published port of any node in the cluster whether or not the node is currently
running the task for the service. All nodes in the swarm route ingress
connections to a running task instance.

Swarm mode has an internal DNS component that automatically assigns each service
in the swarm a DNS entry. The swarm manager uses internal load balancing to
distribute requests among services within the cluster based upon the DNS name of
the service.

## What's next?

* Read the [Swarm mode overview](../../reference/api/ai-governance/index.md).
* Get started with the [Swarm mode tutorial](swarm-tutorial/index.md).


---

# Manage nodes in a swarm

*Sección: Engine*

As part of the swarm management lifecycle, you may need to:

* [List nodes in the swarm](#list-nodes)
* [Inspect an individual node](#inspect-an-individual-node)
* [Update a node](#update-a-node)
* [Leave the swarm](#leave-the-swarm)

## List nodes

To view a list of nodes in the swarm run `docker node ls` from a manager node:

```console
$ docker node ls

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
46aqrk4e473hjbt745z53cr3t    node-5    Ready   Active        Reachable
61pi3d91s0w3b90ijw3deeb2q    node-4    Ready   Active        Reachable
a5b2m3oghd48m8eu391pefq5u    node-3    Ready   Active
e7p8btxeu3ioshyuj6lxiv6g0    node-2    Ready   Active
ehkv3bcimagdese79dn78otj5 *  node-1    Ready   Active        Leader
```

The `AVAILABILITY` column shows whether or not the scheduler can assign tasks to
the node:

* `Active` means that the scheduler can assign tasks to the node.
* `Pause` means the scheduler doesn't assign new tasks to the node, but existing
  tasks remain running.
* `Drain` means the scheduler doesn't assign new tasks to the node. The
   scheduler shuts down any existing tasks and schedules them on an available
   node.

The `MANAGER STATUS` column shows node participation in the Raft consensus:

* No value indicates a worker node that does not participate in swarm
  management.
* `Leader` means the node is the primary manager node that makes all swarm
  management and orchestration decisions for the swarm.
* `Reachable` means the node is a manager node participating in the Raft
  consensus quorum. If the leader node becomes unavailable, the node is eligible for
  election as the new leader.
* `Unavailable` means the node is a manager that can't communicate with
  other managers. If a manager node becomes unavailable, you should either join a
  new manager node to the swarm or promote a worker node to be a
  manager.

For more information on swarm administration refer to the [Swarm administration guide](admin-guide.md).

## Inspect an individual node

You can run `docker node inspect <NODE-ID>` on a manager node to view the
details for an individual node. The output defaults to JSON format, but you can
pass the `--pretty` flag to print the results in human-readable format. For example:

```console
$ docker node inspect self --pretty

ID:                     ehkv3bcimagdese79dn78otj5
Hostname:               node-1
Joined at:              2016-06-16 22:52:44.9910662 +0000 utc
Status:
 State:                 Ready
 Availability:          Active
Manager Status:
 Address:               172.17.0.2:2377
 Raft Status:           Reachable
 Leader:                Yes
Platform:
 Operating System:      linux
 Architecture:          x86_64
Resources:
 CPUs:                  2
 Memory:                1.954 GiB
Plugins:
  Network:              overlay, host, bridge, overlay, null
  Volume:               local
Engine Version:         1.12.0-dev
```

## Update a node

You can modify node attributes to:

* [Change node availability](#change-node-availability)
* [Add or remove label metadata](#add-or-remove-label-metadata)
* [Change a node role](#promote-or-demote-a-node)

### Change node availability

Changing node availability lets you:

* Drain a manager node so that it only performs swarm management tasks and is
  unavailable for task assignment.
* Drain a node so you can take it down for maintenance.
* Pause a node so it can't receive new tasks.
* Restore unavailable or paused nodes availability status.

For example, to change a manager node to `Drain` availability:

```console
$ docker node update --availability drain node-1

node-1
```

See [list nodes](#list-nodes) for descriptions of the different availability
options.

### Add or remove label metadata

Node labels provide a flexible method of node organization. You can also use
node labels in service constraints. Apply constraints when you create a service
to limit the nodes where the scheduler assigns tasks for the service.

Run `docker node update --label-add` on a manager node to add label metadata to
a node. The `--label-add` flag supports either a `<key>` or a `<key>=<value>`
pair.

Pass the `--label-add` flag once for each node label you want to add:

```console
$ docker node update --label-add foo --label-add bar=baz node-1

node-1
```

The labels you set for nodes using `docker node update` apply only to the node
entity within the swarm. Do not confuse them with the Docker daemon labels for
[dockerd](../manage-resources/labels.md).

Therefore, node labels can be used to limit critical tasks to nodes that meet
certain requirements. For example, schedule only on machines where special
workloads should be run, such as machines that meet [PCI-SS
compliance](https://www.pcisecuritystandards.org/).

A compromised worker could not compromise these special workloads because it
cannot change node labels.

Engine labels, however, are still useful because some features that do not
affect secure orchestration of containers might be better off set in a
decentralized manner. For instance, an engine could have a label to indicate
that it has a certain type of disk device, which may not be relevant to security
directly. These labels are more easily "trusted" by the swarm orchestrator.

Refer to the `docker service create` [CLI reference](/reference/cli/docker/service/create/)
for more information about service constraints.

### Promote or demote a node

You can promote a worker node to the manager role. This is useful when a
manager node becomes unavailable or if you want to take a manager offline for
maintenance. Similarly, you can demote a manager node to the worker role.

> [!NOTE]
>
> Regardless of your reason to promote or demote
> a node, you must always maintain a quorum of manager nodes in the
> swarm. For more information refer to the [Swarm administration guide](admin-guide.md).

To promote a node or set of nodes, run `docker node promote` from a manager
node:

```console
$ docker node promote node-3 node-2

Node node-3 promoted to a manager in the swarm.
Node node-2 promoted to a manager in the swarm.
```

To demote a node or set of nodes, run `docker node demote` from a manager node:

```console
$ docker node demote node-3 node-2

Manager node-3 demoted in the swarm.
Manager node-2 demoted in the swarm.
```

`docker node promote` and `docker node demote` are convenience commands for
`docker node update --role manager` and `docker node update --role worker`
respectively.

## Install plugins on swarm nodes

If your swarm service relies on one or more
[plugins](/engine/extend/plugin_api/), these plugins need to be available on
every node where the service could potentially be deployed. You can manually
install the plugin on each node or script the installation. You can also deploy
the plugin in a similar way as a global service using the Docker API, by specifying
a `PluginSpec` instead of a `ContainerSpec`.

> [!NOTE]
>
> There is currently no way to deploy a plugin to a swarm using the
> Docker CLI or Docker Compose. In addition, it is not possible to install
> plugins from a private repository.

The [`PluginSpec`](/engine/extend/plugin_api/#json-specification)
is defined by the plugin developer. To add the plugin to all Docker nodes, use
the [`service/create`](/reference/api/engine/v1.31/#operation/ServiceCreate) API, passing
the `PluginSpec` JSON defined in the `TaskTemplate`.

## Leave the swarm

Run the `docker swarm leave` command on a node to remove it from the swarm.

For example to leave the swarm on a worker node:

```console
$ docker swarm leave

Node left the swarm.
```

When a node leaves the swarm, Docker Engine stops running in Swarm
mode. The orchestrator no longer schedules tasks to the node.

If the node is a manager node, you receive a warning about maintaining the
quorum. To override the warning, pass the `--force` flag. If the last manager
node leaves the swarm, the swarm becomes unavailable requiring you to take
disaster recovery measures.

For information about maintaining a quorum and disaster recovery, refer to the
[Swarm administration guide](admin-guide.md).

After a node leaves the swarm, you can run `docker node rm` on a
manager node to remove the node from the node list.

For instance:

```console
$ docker node rm node-2
```

## Learn more

* [Swarm administration guide](admin-guide.md)
* [Docker Engine command line reference](/reference/cli/docker/)
* [Swarm mode tutorial](swarm-tutorial/index.md)


---

# Manage swarm service networks

*Sección: Engine*

This page describes networking for swarm services.

## Swarm and types of traffic

A Docker swarm generates two different kinds of traffic:

- Control and management plane traffic: This includes swarm management
  messages, such as requests to join or leave the swarm. This traffic is
  always encrypted.

- Application data plane traffic: This includes container traffic and
  traffic to and from external clients.

## Key network concepts

The following three network concepts are important to swarm services:

- Overlay networks manage communications among the Docker daemons
  participating in the swarm. You can create overlay networks, in the same way
  as user-defined networks for standalone containers. You can attach a service
  to one or more existing overlay networks as well, to enable service-to-service
  communication. Overlay networks are Docker networks that use the `overlay`
  network driver.

- The ingress network is a special overlay network that facilitates
  load balancing among a service's nodes. When any swarm node receives a
  request on a published port, it hands that request off to a module called
  `IPVS`. `IPVS` keeps track of all the IP addresses participating in that
  service, selects one of them, and routes the request to it, over the
  `ingress` network.

  The `ingress` network is created automatically when you initialize or join a
  swarm. Most users do not need to customize its configuration, but Docker allows
  you to do so.

- The docker_gwbridge is a bridge network that connects the overlay
  networks (including the `ingress` network) to an individual Docker daemon's
  physical network. By default, each container a service is running is connected
  to its local Docker daemon host's `docker_gwbridge` network.

  The `docker_gwbridge` network is created automatically when you initialize or
  join a swarm. Most users do not need to customize its configuration, but
  Docker allows you to do so.

> [!TIP]
>
> See also [Networking overview](../network/index.md) for more details about Swarm networking in general.

## Firewall considerations

Docker daemons participating in a swarm need the ability to communicate with
each other over the following ports:

* Port `7946` TCP/UDP for container network discovery.
* Port `4789` UDP (configurable) for the overlay network (including ingress) data path.

When setting up networking in a Swarm, special care should be taken. Consult
the [tutorial](swarm-tutorial/index.md#open-protocols-and-ports-between-the-hosts)
for an overview.

## Overlay networking

When you initialize a swarm or join a Docker host to an existing swarm, two
new networks are created on that Docker host:

- An overlay network called `ingress`, which handles the control and data traffic
  related to swarm services. When you create a swarm service and do not
  connect it to a user-defined overlay network, it connects to the `ingress`
  network by default.
- A bridge network called `docker_gwbridge`, which connects the individual
  Docker daemon to the other daemons participating in the swarm.

### Create an overlay network

To create an overlay network, specify the `overlay` driver when using the
`docker network create` command:

```console
$ docker network create \
  --driver overlay \
  my-network
```

The above command doesn't specify any custom options, so Docker assigns a
subnet and uses default options. You can see information about the network using
`docker network inspect`.

When no containers are connected to the overlay network, its configuration is
not very exciting:

```console
$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "fsf1dmx3i9q75an49z36jycxd",
        "Created": "0001-01-01T00:00:00Z",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": []
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "Containers": null,
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
        },
        "Labels": null
    }
]
```

In the above output, notice that the driver is `overlay` and that the scope is
`swarm`, rather than `local`, `host`, or `global` scopes you might see in
other types of Docker networks. This scope indicates that only hosts which are
participating in the swarm can access this network.

The network's subnet and gateway are dynamically configured when a service
connects to the network for the first time. The following example shows
the same network as above, but with three containers of a `redis` service
connected to it.

```console
$ docker network inspect my-network
[
    {
        "Name": "my-network",
        "Id": "fsf1dmx3i9q75an49z36jycxd",
        "Created": "2017-05-31T18:35:58.877628262Z",
        "Scope": "swarm",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "Containers": {
            "0e08442918814c2275c31321f877a47569ba3447498db10e25d234e47773756d": {
                "Name": "my-redis.1.ka6oo5cfmxbe6mq8qat2djgyj",
                "EndpointID": "950ce63a3ace13fe7ef40724afbdb297a50642b6d47f83a5ca8636d44039e1dd",
                "MacAddress": "02:42:0a:00:00:03",
                "IPv4Address": "10.0.0.3/24",
                "IPv6Address": ""
            },
            "88d55505c2a02632c1e0e42930bcde7e2fa6e3cce074507908dc4b827016b833": {
                "Name": "my-redis.2.s7vlybipal9xlmjfqnt6qwz5e",
                "EndpointID": "dd822cb68bcd4ae172e29c321ced70b731b9994eee5a4ad1d807d9ae80ecc365",
                "MacAddress": "02:42:0a:00:00:05",
                "IPv4Address": "10.0.0.5/24",
                "IPv6Address": ""
            },
            "9ed165407384f1276e5cfb0e065e7914adbf2658794fd861cfb9b991eddca754": {
                "Name": "my-redis.3.hbz3uk3hi5gb61xhxol27hl7d",
                "EndpointID": "f62c686a34c9f4d70a47b869576c37dffe5200732e1dd6609b488581634cf5d2",
                "MacAddress": "02:42:0a:00:00:04",
                "IPv4Address": "10.0.0.4/24",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
        },
        "Labels": {},
        "Peers": [
            {
                "Name": "moby-e57c567e25e2",
                "IP": "192.168.65.2"
            }
        ]
    }
]
```

### Customize an overlay network

There may be situations where you don't want to use the default configuration
for an overlay network. For a full list of configurable options, run the
command `docker network create --help`. The following are some of the most
common options to change.

#### Configure the subnet and gateway

By default, the network's subnet and gateway are configured automatically when
the first service is connected to the network. You can configure these when
creating a network using the `--subnet` and `--gateway` flags. The following
example extends the previous one by configuring the subnet and gateway.

```console
$ docker network create \
  --driver overlay \
  --subnet 10.0.9.0/24 \
  --gateway 10.0.9.99 \
  my-network
```

##### Using custom default address pools

To customize subnet allocation for your Swarm networks, you can [optionally configure them](swarm-mode.md) during `swarm init`.

For example, the following command is used when initializing Swarm:

```console
$ docker swarm init --default-addr-pool 10.20.0.0/16 --default-addr-pool-mask-length 26
```

Whenever a user creates a network, but does not use the `--subnet` command line option, the subnet for this network will be allocated sequentially from the next available subnet from the pool. If the specified network is already allocated, that network will not be used for Swarm. 

Multiple pools can be configured if discontiguous address space is required. However, allocation from specific pools is not supported. Network subnets will be allocated sequentially from the IP pool space and subnets will be reused as they are deallocated from networks that are deleted.

The default mask length can be configured and is the same for all networks. It is set to `/24` by default. To change the default subnet mask length, use the `--default-addr-pool-mask-length` command line option.

> [!NOTE]
>
> Default address pools can only be configured on `swarm init` and cannot be altered after cluster creation.

##### Overlay network size limitations

Docker recommends creating overlay networks with `/24` blocks. The `/24` overlay network blocks limit the network to 256 IP addresses. 

This recommendation addresses [limitations with swarm mode](https://github.com/moby/moby/issues/30820). 
If you need more than 256 IP addresses, do not increase the IP block size. You can either use `dnsrr` 
endpoint mode with an external load balancer, or use multiple smaller overlay networks. See 
[Configure service discovery](#configure-service-discovery) for more information about different endpoint modes.

#### Use direct server return

Direct server return (DSR) changes east-west overlay load balancing so that
IPVS routes packets by changing the destination MAC address. The source IP and
destination virtual IP (VIP) remain unchanged.

Create an overlay network that uses DSR:

```console
$ docker network create \
  --driver overlay \
  --opt dsr \
  dsr-net
```

> [!NOTE]
>
> DSR is supported only for traffic between services on Linux nodes. The
> ingress routing mesh does not use DSR.

#### Configure encryption of application data {#encryption}

Management and control plane data related to a swarm is always encrypted.
For more details about the encryption mechanisms, see the
[Docker swarm mode overlay network security model](../network/drivers/overlay.md).

Application data among swarm nodes is not encrypted by default. To encrypt this
traffic on a given overlay network, use the `--opt encrypted` flag on `docker
network create`. This enables IPSEC encryption at the level of the vxlan. This
encryption imposes a non-negligible performance penalty, so you should test this
option before using it in production.

> [!NOTE]
>
> You must [customize the automatically created ingress](#customize-ingress)
> to enable encryption. By default, all ingress traffic is unencrypted, as encryption
> is a network-level option.

## Attach a service to an overlay network

To attach a service to an existing overlay network, pass the `--network` flag to
`docker service create`, or the `--network-add` flag to `docker service update`.

```console
$ docker service create \
  --replicas 3 \
  --name my-web \
  --network my-network \
  nginx
```

Service containers connected to an overlay network can communicate with
each other across it.

To see which networks a service is connected to, use `docker service ls` to find
the name of the service, then `docker service ps <service-name>` to list the
networks. Alternately, to see which services' containers are connected to a
network, use `docker network inspect <network-name>`. You can run these commands
from any swarm node which is joined to the swarm and is in a `running` state.

### Configure service discovery

Service discovery is the mechanism Docker uses to route a request from your
service's external clients to an individual swarm node, without the client
needing to know how many nodes are participating in the service or their
IP addresses or ports. You don't need to publish ports which are used between
services on the same network. For instance, if you have a
WordPress service that stores its data in a MySQL service, and they are connected to the same overlay network, you do not need to publish
the MySQL port to the client, only the WordPress HTTP port.

Service discovery can work in two different ways: internal connection-based
load-balancing at Layers 3 and 4 using the embedded DNS and a virtual IP (VIP),
or external and customized request-based load-balancing at Layer 7 using DNS
round robin (DNSRR). You can configure this per service.

- By default, when you attach a service to a network and that service publishes
  one or more ports, Docker assigns the service a virtual IP (VIP), which is the
  "front end" for clients to reach the service. Docker keeps a list of all
  worker nodes in the service, and routes requests between the client and one of
  the nodes. Each request from the client might be routed to a different node.

- If you configure a service to use DNS round-robin (DNSRR) service discovery,
  there is not a single virtual IP. Instead, Docker sets up DNS entries for the
  service such that a DNS query for the service name returns a list of IP
  addresses, and the client connects directly to one of these.

  DNS round-robin is useful in cases where you want to use your own load
  balancer, such as HAProxy. To configure a service to use DNSRR, use the flag
  `--endpoint-mode dnsrr` when creating a new service or updating an existing
  one.

### Container discovery

For most situations, connect to the service name. Docker load-balances
requests across all running tasks ("containers") backing the service. To
resolve the IP addresses of all individual tasks backing a service directly,
perform a DNS lookup for `tasks.<service-name>`. Docker returns a list of
all task IP addresses for that service, one per running replica.

## Customize the ingress network {#customize-ingress}

Most users never need to configure the `ingress` network, but Docker allows you
to do so. This can be useful if the automatically-chosen subnet
conflicts with one that already exists on your network, or you need to customize
other low-level network settings such as the MTU, or if you want to
[enable encryption](#encryption).

Customizing the `ingress` network involves removing and recreating it. This is
usually done before you create any services in the swarm. If you have existing
services which publish ports, those services need to be removed before you can
remove the `ingress` network.

During the time that no `ingress` network exists, existing services which do not
publish ports continue to function but are not load-balanced. This affects
services which publish ports, such as a WordPress service which publishes port
80.

1.  Inspect the `ingress` network using `docker network inspect ingress`, and
    remove any services whose containers are connected to it. These are services
    that publish ports, such as a WordPress service which publishes port 80. If
    all such services are not stopped, the next step fails.

2.  Remove the existing `ingress` network:

    ```console
    $ docker network rm ingress

    WARNING! Before removing the routing-mesh network, make sure all the nodes
    in your swarm run the same docker engine version. Otherwise, removal may not
    be effective and functionality of newly created ingress networks will be
    impaired.
    Are you sure you want to continue? [y/N]
    ```

3.  Create a new overlay network using the `--ingress` flag, along  with the
    custom options you want to set. This example sets the MTU to 1200, sets
    the subnet to `10.11.0.0/16`, and sets the gateway to `10.11.0.2`.

    ```console
    $ docker network create \
      --driver overlay \
      --ingress \
      --subnet=10.11.0.0/16 \
      --gateway=10.11.0.2 \
      --opt com.docker.network.driver.mtu=1200 \
      my-ingress
    ```

    > [!NOTE]
    >
    > You can name your `ingress` network something other than
    > `ingress`, but you can only have one. An attempt to create a second one
    > fails.

4.  Restart the services that you stopped in the first step.

## Customize the docker_gwbridge

The `docker_gwbridge` is a virtual bridge that connects the overlay networks
(including the `ingress` network) to an individual Docker daemon's physical
network. Docker creates it automatically when you initialize a swarm or join a
Docker host to a swarm, but it is not a Docker device. It exists in the kernel
of the Docker host. If you need to customize its settings, you must do so before
joining the Docker host to the swarm, or after temporarily removing the host
from the swarm.

You need to have the `brctl` application installed on your operating system in
order to delete an existing bridge. The package name is `bridge-utils`.

1.  Stop Docker.

2.  Use the `brctl show docker_gwbridge` command to check whether a bridge
    device exists called `docker_gwbridge`. If so, remove it using
    `brctl delbr docker_gwbridge`.

3.  Start Docker. Do not join or initialize the swarm.

4.  Create or re-create the `docker_gwbridge` bridge with your custom settings.
    This example uses the subnet `10.11.0.0/16`. For a full list of customizable
    options, see [Bridge driver options](/reference/cli/docker/network/create/#bridge-driver-options).

    ```console
    $ docker network create \
    --subnet 10.11.0.0/16 \
    --opt com.docker.network.bridge.name=docker_gwbridge \
    --opt com.docker.network.bridge.enable_icc=false \
    --opt com.docker.network.bridge.enable_ip_masquerade=true \
    docker_gwbridge
    ```

5.  Initialize or join the swarm.

## Use a separate interface for control and data traffic

By default, all swarm traffic is sent over the same interface, including control
and management traffic for maintaining the swarm itself and data traffic to and
from the service containers.

You can separate this traffic by passing
the `--data-path-addr` flag when initializing or joining the swarm. If there are
multiple interfaces, `--advertise-addr` must be specified explicitly, and
`--data-path-addr` defaults to `--advertise-addr` if not specified. Traffic about
joining, leaving, and managing the swarm is sent over the
`--advertise-addr` interface, and traffic among a service's containers is sent 
over the `--data-path-addr` interface. These flags can take an IP address or
a network device name, such as `eth0`.

This example initializes a swarm with a separate `--data-path-addr`. It assumes
that your Docker host has two different network interfaces: 10.0.0.1 should be
used for control and management traffic and 192.168.0.1 should be used for
traffic relating to services.

```console
$ docker swarm init --advertise-addr 10.0.0.1 --data-path-addr 192.168.0.1
```

This example joins the swarm managed by host `192.168.99.100:2377` and sets the
`--advertise-addr` flag to `eth0` and the `--data-path-addr` flag to `eth1`.

```console
$ docker swarm join \
  --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2d7c \
  --advertise-addr eth0 \
  --data-path-addr eth1 \
  192.168.99.100:2377
```

## Publish ports on an overlay network

Swarm services connected to the same overlay network effectively expose all
ports to each other. For a port to be accessible outside of the service, that
port must be _published_ using the `-p` or `--publish` flag on `docker service
create` or `docker service update`. Both the legacy colon-separated syntax and
the newer comma-separated value syntax are supported. The longer syntax is
preferred because it is somewhat self-documenting.

<table>
<thead>
<tr>
<th>Flag value</th>
<th>Description</th>
</tr>
</thead>
<tr>
<td><tt>-p 8080:80</tt> or<br /><tt>-p published=8080,target=80</tt></td>
<td>Map TCP port 80 on the service to port 8080 on the routing mesh.</td>
</tr>
<tr>
<td><tt>-p 8080:80/udp</tt> or<br /><tt>-p published=8080,target=80,protocol=udp</tt></td>
<td>Map UDP port 80 on the service to port 8080 on the routing mesh.</td>
</tr>
<tr>
<td><tt>-p 8080:80/tcp -p 8080:80/udp</tt> or <br /><tt>-p published=8080,target=80,protocol=tcp -p published=8080,target=80,protocol=udp</tt></td>
<td>Map TCP port 80 on the service to TCP port 8080 on the routing mesh, and map UDP port 80 on the service to UDP port 8080 on the routing mesh.</td>
</tr>
</table>

## Learn more

* [Deploy services to a swarm](services.md)
* [Swarm administration guide](admin-guide.md)
* [Swarm mode tutorial](swarm-tutorial/index.md)
* [Networking overview](../network/index.md)
* [Docker CLI reference](/reference/cli/docker/)


---

# Raft consensus in swarm mode

*Sección: Engine*

When Docker Engine runs in Swarm mode, manager nodes implement the
[Raft Consensus Algorithm](http://thesecretlivesofdata.com/raft/) to manage the global cluster state.

The reason why Swarm mode is using a consensus algorithm is to make sure that
all the manager nodes that are in charge of managing and scheduling tasks in the cluster
are storing the same consistent state.

Having the same consistent state across the cluster means that in case of a failure,
any Manager node can pick up the tasks and restore the services to a stable state.
For example, if the Leader Manager which is responsible for scheduling tasks in the
cluster dies unexpectedly, any other Manager can pick up the task of scheduling and
re-balance tasks to match the desired state.

Systems using consensus algorithms to replicate logs in a distributed systems
do require special care. They ensure that the cluster state stays consistent
in the presence of failures by requiring a majority of nodes to agree on values.

Raft tolerates up to `(N-1)/2` failures and requires a majority or quorum of
`(N/2)+1` members to agree on values proposed to the cluster. This means that in
a cluster of 5 Managers running Raft, if 3 nodes are unavailable, the system
cannot process any more requests to schedule additional tasks. The existing
tasks keep running but the scheduler cannot rebalance tasks to
cope with failures if the manager set is not healthy.

The implementation of the consensus algorithm in Swarm mode means it features
the properties inherent to distributed systems:

- Agreement on values in a fault tolerant system. (Refer to [FLP impossibility theorem](https://www.the-paper-trail.org/post/2008-08-13-a-brief-tour-of-flp-impossibility/)
 and the [Raft Consensus Algorithm paper](https://www.usenix.org/system/files/conference/atc14/atc14-paper-ongaro.pdf))
- Mutual exclusion through the leader election process
- Cluster membership management
- Globally consistent object sequencing and CAS (compare-and-swap) primitives


---

# Manage sensitive data with Docker secrets

*Sección: Engine*

## About secrets

In terms of Docker Swarm services, a _secret_ is a blob of data, such as a
password, SSH private key, SSL certificate, or another piece of data that should
not be transmitted over a network or stored unencrypted in a Dockerfile or in
your application's source code. You can use Docker _secrets_ to centrally manage
this data and securely transmit it to only those containers that need access to
it. Secrets are encrypted during transit and at rest in a Docker swarm. A given
secret is only accessible to those services which have been granted explicit
access to it, and only while those service tasks are running.

You can use secrets to manage any sensitive data which a container needs at
runtime but you don't want to store in the image or in source control, such as:

- Usernames and passwords
- TLS certificates and keys
- SSH keys
- Other important data such as the name of a database or internal server
- Generic strings or binary content (up to 500 kb in size)

> [!NOTE]
>
> Docker secrets are only available to swarm services, not to
> standalone containers. To use this feature, consider adapting your container
> to run as a service. Stateful containers can typically run with a scale of 1
> without changing the container code.

Another use case for using secrets is to provide a layer of abstraction between
the container and a set of credentials. Consider a scenario where you have
separate development, test, and production environments for your application.
Each of these environments can have different credentials, stored in the
development, test, and production swarms with the same secret name. Your
containers only need to know the name of the secret to function in all
three environments.

You can also use secrets to manage non-sensitive data, such as configuration
files. However, Docker supports the use of [configs](configs.md)
for storing non-sensitive data. Configs are mounted into the container's
filesystem directly, without the use of a RAM disk.

### Windows support

Docker includes support for secrets on Windows containers. Where there are
differences in the implementations, they are called out in the
examples below. Keep the following notable differences in mind:

- Microsoft Windows has no built-in driver for managing RAM disks, so within
  running Windows containers, secrets are persisted in clear text to the
  container's root disk. However, the secrets are explicitly removed when a
  container stops. In addition, Windows does not support persisting a running
  container as an image using `docker commit` or similar commands.

- On Windows, we recommend enabling
  [BitLocker](https://technet.microsoft.com/en-us/library/cc732774(v=ws.11).aspx)
  on the volume containing the Docker root directory on the host machine to
  ensure that secrets for running containers are encrypted at rest.

- Secret files with custom targets are not directly bind-mounted into Windows
  containers, since Windows does not support non-directory file bind-mounts.
  Instead, secrets for a container are all mounted in
  `C:\ProgramData\Docker\internal\secrets` (an implementation detail which
  should not be relied upon by applications) within the container. Symbolic
  links are used to point from there to the desired target of the secret within
  the container. The default target is `C:\ProgramData\Docker\secrets`.

- When creating a service which uses Windows containers, the options to specify
  UID, GID, and mode are not supported for secrets. Secrets are currently only
  accessible by administrators and users with `system` access within the
  container.

## How Docker manages secrets

When you add a secret to the swarm, Docker sends the secret to the swarm manager
over a mutual TLS connection. The secret is stored in the Raft log, which is
encrypted. The entire Raft log is replicated across the other managers, ensuring
the same high availability guarantees for secrets as for the rest of the swarm
management data.

When you grant a newly-created or running service access to a secret, the
decrypted secret is mounted into the container in an in-memory filesystem. The
location of the mount point within the container defaults to
`/run/secrets/<secret_name>` in Linux containers, or
`C:\ProgramData\Docker\secrets` in Windows containers. You can also specify a
custom location.

You can update a service to grant it access to additional secrets or revoke its
access to a given secret at any time.

A node only has access to (encrypted) secrets if the node is a swarm manager or
if it is running service tasks which have been granted access to the secret.
When a container task stops running, the decrypted secrets shared to it are
unmounted from the in-memory filesystem for that container and flushed from the
node's memory.

If a node loses connectivity to the swarm while it is running a task container
with access to a secret, the task container still has access to its secrets, but
cannot receive updates until the node reconnects to the swarm.

You can add or inspect an individual secret at any time, or list all
secrets. You cannot remove a secret that a running service is
using. See [Rotate a secret](secrets.md#example-rotate-a-secret) for a way to
remove a secret without disrupting running services.

To update or roll back secrets more easily, consider adding a version
number or date to the secret name. This is made easier by the ability to control
the mount point of the secret within a given container.

## Read more about `docker secret` commands

Use these links to read about specific commands, or continue to the
[example about using secrets with a service](secrets.md#simple-example-get-started-with-secrets).

- [`docker secret create`](/reference/cli/docker/secret/create/)
- [`docker secret inspect`](/reference/cli/docker/secret/inspect/)
- [`docker secret ls`](/reference/cli/docker/secret/ls/)
- [`docker secret rm`](/reference/cli/docker/secret/rm/)
- [`--secret`](/reference/cli/docker/service/create/#secret) flag for `docker service create`
- [`--secret-add` and `--secret-rm`](/reference/cli/docker/service/update/#secret-add) flags for `docker service update`

## Defining and using secrets in Compose files

Using secrets in a Compose file alongside Docker Swarm is as simple as defining a secret
using `docker secret create`.

```console
$ printf "my-secret" | docker secret create some_secret -
```

In the `compose.yml` file you can declare the secret as `external` in the top-level `secrets` attribute.

```yaml
services:
    api:
        image: my-web-app
        environment:
            MY_ENV: /run/secrets/some_secret
        secrets:
            - some_secret

secrets:
    some_secret:
        external: true
```

Both the `docker compose` and `docker stack` commands support defining secrets
in a Compose file. See
[the Compose file reference](../../reference/compose-file/secrets.md) for details.

## Examples

This section includes three graduated examples which illustrate how to use
Docker secrets. The images used in these examples have been updated to make it
easier to use Docker secrets. To find out how to modify your own images in
a similar way, see
[Build support for Docker Secrets into your images](#build-support-for-docker-secrets-into-your-images).

> [!NOTE]
>
> These examples use a single-Engine swarm and unscaled services for
> simplicity. The examples use Linux containers, but Windows containers also
> support secrets. See [Windows support](#windows-support).

### Simple example: Get started with secrets

This simple example shows how secrets work in just a few commands. For a
real-world example, continue to
[Intermediate example: Use secrets with a Nginx service](#intermediate-example-use-secrets-with-a-nginx-service).

1.  Add a secret to Docker. The `docker secret create` command reads standard
    input because the last argument, which represents the file to read the
    secret from, is set to `-`.

    ```console
    $ printf "This is a secret" | docker secret create my_secret_data -
    ```

2.  Create a `redis` service and grant it access to the secret. By default,
    the container can access the secret at `/run/secrets/<secret_name>`, but
    you can customize the file name on the container using the `target` option.

    ```console
    $ docker service  create --name redis --secret my_secret_data redis:alpine
    ```

3.  Verify that the task is running without issues using `docker service ps`. If
    everything is working, the output looks similar to this:

    ```console
    $ docker service ps redis

    ID            NAME     IMAGE         NODE              DESIRED STATE  CURRENT STATE          ERROR  PORTS
    bkna6bpn8r1a  redis.1  redis:alpine  ip-172-31-46-109  Running        Running 8 seconds ago  
    ```

    If there were an error, and the task were failing and repeatedly restarting,
    you would see something like this:

    ```console
    $ docker service ps redis

    NAME                      IMAGE         NODE  DESIRED STATE  CURRENT STATE          ERROR                      PORTS
    redis.1.siftice35gla      redis:alpine  moby  Running        Running 4 seconds ago                             
     \_ redis.1.whum5b7gu13e  redis:alpine  moby  Shutdown       Failed 20 seconds ago      "task: non-zero exit (1)"  
     \_ redis.1.2s6yorvd9zow  redis:alpine  moby  Shutdown       Failed 56 seconds ago      "task: non-zero exit (1)"  
     \_ redis.1.ulfzrcyaf6pg  redis:alpine  moby  Shutdown       Failed about a minute ago  "task: non-zero exit (1)"  
     \_ redis.1.wrny5v4xyps6  redis:alpine  moby  Shutdown       Failed 2 minutes ago       "task: non-zero exit (1)"
    ```

4.  Get the ID of the `redis` service task container using `docker ps` , so that
    you can use `docker container exec` to connect to the container and read the contents
    of the secret data file, which defaults to being readable by all and has the
    same name as the name of the secret. The first command below illustrates
    how to find the container ID, and the second and third commands use shell
    completion to do this automatically.

    ```console
    $ docker ps --filter name=redis -q

    5cb1c2348a59

    $ docker container exec $(docker ps --filter name=redis -q) ls -l /run/secrets

    total 4
    -r--r--r--    1 root     root            17 Dec 13 22:48 my_secret_data

    $ docker container exec $(docker ps --filter name=redis -q) cat /run/secrets/my_secret_data

    This is a secret
    ```

5.  Verify that the secret is not available if you commit the container.

    ```console
    $ docker commit $(docker ps --filter name=redis -q) committed_redis

    $ docker run --rm -it committed_redis cat /run/secrets/my_secret_data

    cat: can't open '/run/secrets/my_secret_data': No such file or directory
    ```

6.  Try removing the secret. The removal fails because the `redis` service is
    running and has access to the secret.

    ```console
    $ docker secret ls

    ID                          NAME                CREATED             UPDATED
    wwwrxza8sxy025bas86593fqs   my_secret_data      4 hours ago         4 hours ago


    $ docker secret rm my_secret_data

    Error response from daemon: rpc error: code = 3 desc = secret
    'my_secret_data' is in use by the following service: redis
    ```

7.  Remove access to the secret from the running `redis` service by updating the
    service.

    ```console
    $ docker service update --secret-rm my_secret_data redis
    ```

8.  Repeat steps 3 and 4 again, verifying that the service no longer has access
    to the secret. The container ID is different, because the
    `service update` command redeploys the service.

    ```console
    $ docker container exec -it $(docker ps --filter name=redis -q) cat /run/secrets/my_secret_data

    cat: can't open '/run/secrets/my_secret_data': No such file or directory
    ```

9.  Stop and remove the service, and remove the secret from Docker.

    ```console
    $ docker service rm redis

    $ docker secret rm my_secret_data
    ```

### Simple example: Use secrets in a Windows service

This is a very simple example which shows how to use secrets with a Microsoft
IIS service running on Docker for Windows running Windows containers on
Microsoft Windows 10. It is a naive example that stores the webpage in a secret.

This example assumes that you have PowerShell installed.

1.  Save the following into a new file `index.html`.

    ```html
    <html lang="en">
      <head><title>Hello Docker</title></head>
      <body>
        <p>Hello Docker! You have deployed a HTML page.</p>
      </body>
    </html>
    ```

2.  If you have not already done so, initialize or join the swarm.

    ```console
    > docker swarm init
    ```

3.  Save the `index.html` file as a swarm secret named `homepage`.

    ```console
    > docker secret create homepage index.html
    ```

4.  Create an IIS service and grant it access to the `homepage` secret.

    ```console
    > docker service create `
        --name my-iis `
        --publish published=8000,target=8000 `
        --secret src=homepage,target="\inetpub\wwwroot\index.html" `
        microsoft/iis:nanoserver
    ```

    > [!NOTE]
    >
    > There is technically no reason to use secrets for this
    > example; [configs](configs.md) are a better fit. This example is
    > for illustration only.

5.  Access the IIS service at `http://localhost:8000/`. It should serve
    the HTML content from the first step.

6.  Remove the service and the secret.

    ```console
    > docker service rm my-iis
    > docker secret rm homepage
    > docker image remove secret-test
    ```

### Intermediate example: Use secrets with a Nginx service

This example is divided into two parts.
[The first part](#generate-the-site-certificate) is all about generating
the site certificate and does not directly involve Docker secrets at all, but
it sets up [the second part](#configure-the-nginx-container), where you store
and use the site certificate and Nginx configuration as secrets.

#### Generate the site certificate

Generate a root CA and TLS certificate and key for your site. For production
sites, you may want to use a service such as `Let’s Encrypt` to generate the
TLS certificate and key, but this example uses command-line tools. This step
is a little complicated, but is only a set-up step so that you have
something to store as a Docker secret. If you want to skip these sub-steps,
you can [use Let's Encrypt](https://letsencrypt.org/getting-started/) to
generate the site key and certificate, name the files `site.key` and
`site.crt`, and skip to
[Configure the Nginx container](#configure-the-nginx-container).

1.  Generate a root key.

    ```console
    $ openssl genrsa -out "root-ca.key" 4096
    ```

2.  Generate a CSR using the root key.

    ```console
    $ openssl req \
              -new -key "root-ca.key" \
              -out "root-ca.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA'
    ```

3.  Configure the root CA. Edit a new file called `root-ca.cnf` and paste
    the following contents into it. This constrains the root CA to signing leaf
    certificates and not intermediate CAs.

    ```ini
    [root_ca]
    basicConstraints = critical,CA:TRUE,pathlen:1
    keyUsage = critical, nonRepudiation, cRLSign, keyCertSign
    subjectKeyIdentifier=hash
    ```

4.  Sign the certificate.

    ```console
    $ openssl x509 -req  -days 3650  -in "root-ca.csr" \
                   -signkey "root-ca.key" -sha256 -out "root-ca.crt" \
                   -extfile "root-ca.cnf" -extensions \
                   root_ca
    ```

5.  Generate the site key.

    ```console
    $ openssl genrsa -out "site.key" 4096
    ```

6.  Generate the site certificate and sign it with the site key.

    ```console
    $ openssl req -new -key "site.key" -out "site.csr" -sha256 \
              -subj '/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost'
    ```

7.  Configure the site certificate. Edit a new file  called `site.cnf` and
    paste the following contents into it. This constrains the site
    certificate so that it can only be used to authenticate a server and
    can't be used to sign certificates.

    ```ini
    [server]
    authorityKeyIdentifier=keyid,issuer
    basicConstraints = critical,CA:FALSE
    extendedKeyUsage=serverAuth
    keyUsage = critical, digitalSignature, keyEncipherment
    subjectAltName = DNS:localhost, IP:127.0.0.1
    subjectKeyIdentifier=hash
    ```

8.  Sign the site certificate.

    ```console
    $ openssl x509 -req -days 750 -in "site.csr" -sha256 \
        -CA "root-ca.crt" -CAkey "root-ca.key"  -CAcreateserial \
        -out "site.crt" -extfile "site.cnf" -extensions server
    ```

9.  The `site.csr` and `site.cnf` files are not needed by the Nginx service, but
    you need them if you want to generate a new site certificate. Protect
    the `root-ca.key` file.

#### Configure the Nginx container

1.  Produce a very basic Nginx configuration that serves static files over HTTPS.
    The TLS certificate and key are stored as Docker secrets so that they
    can be rotated easily.

    In the current directory, create a new file called `site.conf` with the
    following contents:

    ```nginx
    server {
        listen                443 ssl;
        server_name           localhost;
        ssl_certificate       /run/secrets/site.crt;
        ssl_certificate_key   /run/secrets/site.key;

        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
    ```

2.  Create three secrets, representing the key, the certificate, and the
    `site.conf`. You can store any file as a secret as long as it is smaller
    than 500 KB. This allows you to decouple the key, certificate, and
    configuration from the services that use them. In each of these
    commands, the last argument represents the path to the file to read the
    secret from on the host machine's filesystem. In these examples, the secret
    name and the file name are the same.

    ```console
    $ docker secret create site.key site.key

    $ docker secret create site.crt site.crt

    $ docker secret create site.conf site.conf
    ```

    ```console
    $ docker secret ls

    ID                          NAME                  CREATED             UPDATED
    2hvoi9mnnaof7olr3z5g3g7fp   site.key       58 seconds ago      58 seconds ago
    aya1dh363719pkiuoldpter4b   site.crt       24 seconds ago      24 seconds ago
    zoa5df26f7vpcoz42qf2csth8   site.conf      11 seconds ago      11 seconds ago
    ```

3.  Create a service that runs Nginx and has access to the three secrets. The
    last part of the `docker service create` command creates a symbolic link
    from the location of the `site.conf` secret to `/etc/nginx.conf.d/`, where
    Nginx looks for extra configuration files. This step happens before Nginx
    actually starts, so you don't need to rebuild your image if you change the
    Nginx configuration.

    > [!NOTE]
    >
    > Normally you would create a Dockerfile which copies the `site.conf`
    > into place, build the image, and run a container using your custom image.
    > This example does not require a custom image. It puts the `site.conf`
    > into place and runs the container all in one step.

    Secrets are located within the `/run/secrets/` directory in the container
    by default, which may require extra steps in the container to make the
    secret available in a different path. The example below creates a symbolic
    link to the true location of the `site.conf` file so that Nginx can read it:

    ```console
    $ docker service create \
         --name nginx \
         --secret site.key \
         --secret site.crt \
         --secret site.conf \
         --publish published=3000,target=443 \
         nginx:latest \
         sh -c "ln -s /run/secrets/site.conf /etc/nginx/conf.d/site.conf && exec nginx -g 'daemon off;'"
    ```

    Instead of creating symlinks, secrets allow you to specify a custom location
    using the `target` option. The example below illustrates how the `site.conf`
    secret is made available at `/etc/nginx/conf.d/site.conf` inside the container
    without the use of symbolic links:

    ```console
    $ docker service create \
         --name nginx \
         --secret site.key \
         --secret site.crt \
         --secret source=site.conf,target=/etc/nginx/conf.d/site.conf \
         --publish published=3000,target=443 \
         nginx:latest \
         sh -c "exec nginx -g 'daemon off;'"
    ```

    The `site.key` and `site.crt` secrets use the short-hand syntax, without a 
    custom `target` location set. The short syntax mounts the secrets in `/run/secrets/
    with the same name as the secret. Within the running containers, the following
    three files now exist:

    - `/run/secrets/site.key`
    - `/run/secrets/site.crt`
    - `/etc/nginx/conf.d/site.conf`

4.  Verify that the Nginx service is running.

    ```console
    $ docker service ls

    ID            NAME   MODE        REPLICAS  IMAGE
    zeskcec62q24  nginx  replicated  1/1       nginx:latest

    $ docker service ps nginx

    NAME                  IMAGE         NODE  DESIRED STATE  CURRENT STATE          ERROR  PORTS
    nginx.1.9ls3yo9ugcls  nginx:latest  moby  Running        Running 3 minutes ago
    ```

5.  Verify that the service is operational: you can reach the Nginx
    server, and that the correct TLS certificate is being used.

    ```console
    $ curl --cacert root-ca.crt https://localhost:3000

    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
        }
    </style>
    </head>
    <body>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>

    <p>For online documentation and support. refer to
    <a href="https://nginx.org">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="https://www.nginx.com">nginx.com</a>.</p>

    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    ```

    ```console
    $ openssl s_client -connect localhost:3000 -CAfile root-ca.crt

    CONNECTED(00000003)
    depth=1 /C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    verify return:1
    depth=0 /C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
    verify return:1
    ---
    Certificate chain
     0 s:/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
       i:/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    …
    -----END CERTIFICATE-----
    subject=/C=US/ST=CA/L=San Francisco/O=Docker/CN=localhost
    issuer=/C=US/ST=CA/L=San Francisco/O=Docker/CN=Swarm Secret Example CA
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1663 bytes and written 712 bytes
    ---
    New, TLSv1/SSLv3, Cipher is AES256-SHA
    Server public key is 4096 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : AES256-SHA
        Session-ID: A1A8BF35549C5715648A12FD7B7E3D861539316B03440187D9DA6C2E48822853
        Session-ID-ctx:
        Master-Key: F39D1B12274BA16D3A906F390A61438221E381952E9E1E05D3DD784F0135FB81353DA38C6D5C021CB926E844DFC49FC4
        Key-Arg   : None
        Start Time: 1481685096
        Timeout   : 300 (sec)
        Verify return code: 0 (ok)
    ```

6.  To clean up after running this example, remove the `nginx` service and the
    stored secrets.

    ```console
    $ docker service rm nginx

    $ docker secret rm site.crt site.key site.conf
    ```

### Advanced example: Use secrets with a WordPress service

In this example, you create a single-node MySQL service with a custom root
password, add the credentials as secrets, and create a single-node WordPress
service which uses these credentials to connect to MySQL. The
[next example](#example-rotate-a-secret) builds on this one and shows you how to
rotate the MySQL password and update the services so that the WordPress service
can still connect to MySQL.

This example illustrates some techniques to use Docker secrets to avoid saving
sensitive credentials within your image or passing them directly on the command
line.

> [!NOTE]
>
> This example uses a single-Engine swarm for simplicity, and uses a
> single-node MySQL service because a single MySQL server instance cannot be
> scaled by simply using a replicated service, and setting up a MySQL cluster is
> beyond the scope of this example.
>
> Also, changing a MySQL root passphrase isn’t as simple as changing
> a file on disk. You must use a query or a `mysqladmin` command to change the
> password in MySQL.

1.  Generate a random alphanumeric password for MySQL and store it as a Docker
    secret with the name `mysql_password` using the `docker secret create`
    command. To make the password shorter or longer, adjust the last argument of
    the `openssl` command. This is just one way to create a relatively random
    password. You can use another command to generate the password if you
    choose.

    > [!NOTE]
    >
    > After you create a secret, you cannot update it. You can only
    > remove and re-create it, and you cannot remove a secret that a service is
    > using. However, you can grant or revoke a running service's access to
    > secrets using `docker service update`. If you need the ability to update a
    > secret, consider adding a version component to the secret name, so that you
    > can later add a new version, update the service to use it, then remove the
    > old version.

    The last argument is set to `-`, which indicates that the input is read from
    standard input.

    ```console
    $ openssl rand -base64 20 | docker secret create mysql_password -

    l1vinzevzhj4goakjap5ya409
    ```

    The value returned is not the password, but the ID of the secret. In the
    remainder of this tutorial, the ID output is omitted.

    Generate a second secret for the MySQL `root` user. This secret isn't
    shared with the WordPress service created later. It's only needed to
    bootstrap the `mysql` service.

    ```console
    $ openssl rand -base64 20 | docker secret create mysql_root_password -
    ```

    List the secrets managed by Docker using `docker secret ls`:

    ```console
    $ docker secret ls

    ID                          NAME                  CREATED             UPDATED
    l1vinzevzhj4goakjap5ya409   mysql_password        41 seconds ago      41 seconds ago
    yvsczlx9votfw3l0nz5rlidig   mysql_root_password   12 seconds ago      12 seconds ago
    ```

    The secrets are stored in the encrypted Raft logs for the swarm.

2.  Create a user-defined overlay network which is used for communication
    between the MySQL and WordPress services. There is no need to expose the
    MySQL service to any external host or container.

    ```console
    $ docker network create -d overlay mysql_private
    ```

3.  Create the MySQL service. The MySQL service has the following
    characteristics:

    - Because the scale is set to `1`, only a single MySQL task runs.
      Load-balancing MySQL is left as an exercise to the reader and involves
      more than just scaling the service.
    - Only reachable by other containers on the `mysql_private` network.
    - Uses the volume `mydata` to store the MySQL data, so that it persists
      across restarts to the `mysql` service.
    - The secrets are each mounted in a `tmpfs` filesystem at
      `/run/secrets/mysql_password` and `/run/secrets/mysql_root_password`.
      They are never exposed as environment variables, nor can they be committed
      to an image if the `docker commit` command is run. The `mysql_password`
      secret is the one used by the non-privileged WordPress container to
      connect to MySQL.
    - Sets the environment variables `MYSQL_PASSWORD_FILE` and
      `MYSQL_ROOT_PASSWORD_FILE` to point to the
      files `/run/secrets/mysql_password` and `/run/secrets/mysql_root_password`.
      The `mysql` image reads the password strings from those files when
      initializing the system database for the first time. Afterward, the
      passwords are stored in the MySQL system database itself.
    - Sets environment variables `MYSQL_USER` and `MYSQL_DATABASE`. A new
      database called `wordpress` is created when the container starts, and the
      `wordpress` user has full permissions for this database only. This
      user cannot create or drop databases or change the MySQL
      configuration.

      ```console
      $ docker service create \
           --name mysql \
           --replicas 1 \
           --network mysql_private \
           --mount type=volume,source=mydata,destination=/var/lib/mysql \
           --secret source=mysql_root_password,target=mysql_root_password \
           --secret source=mysql_password,target=mysql_password \
           -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/mysql_root_password" \
           -e MYSQL_PASSWORD_FILE="/run/secrets/mysql_password" \
           -e MYSQL_USER="wordpress" \
           -e MYSQL_DATABASE="wordpress" \
           mysql:latest
      ```

4.  Verify that the `mysql` container is running using the `docker service ls` command.

    ```console
    $ docker service ls

    ID            NAME   MODE        REPLICAS  IMAGE
    wvnh0siktqr3  mysql  replicated  1/1       mysql:latest
    ```

5.  Now that MySQL is set up, create a WordPress service that connects to the
    MySQL service. The WordPress service has the following characteristics:

    - Because the scale is set to `1`, only a single WordPress task runs.
      Load-balancing WordPress is left as an exercise to the reader, because of
      limitations with storing WordPress session data on the container
      filesystem.
    - Exposes WordPress on port 30000 of the host machine, so that you can access
      it from external hosts. You can expose port 80 instead if you do not have
      a web server running on port 80 of the host machine.
    - Connects to the `mysql_private` network so it can communicate with the
      `mysql` container, and also publishes port 80 to port 30000 on all swarm
      nodes.
    - Has access to the `mysql_password` secret, but specifies a different
      target file name within the container. The WordPress container uses
      the mount point `/run/secrets/wp_db_password`.
    - Sets the environment variable `WORDPRESS_DB_PASSWORD_FILE` to the file
      path where the secret is mounted. The WordPress service reads the
      MySQL password string from that file and add it to the `wp-config.php`
      configuration file.
    - Connects to the MySQL container using the username `wordpress` and the
      password in `/run/secrets/wp_db_password` and creates the `wordpress`
      database if it does not yet exist.
    - Stores its data, such as themes and plugins, in a volume called `wpdata`
      so these files  persist when the service restarts.

    ```console
    $ docker service create \
         --name wordpress \
         --replicas 1 \
         --network mysql_private \
         --publish published=30000,target=80 \
         --mount type=volume,source=wpdata,destination=/var/www/html \
         --secret source=mysql_password,target=wp_db_password \
         -e WORDPRESS_DB_USER="wordpress" \
         -e WORDPRESS_DB_PASSWORD_FILE="/run/secrets/wp_db_password" \
         -e WORDPRESS_DB_HOST="mysql:3306" \
         -e WORDPRESS_DB_NAME="wordpress" \
         wordpress:latest
    ```

6.  Verify the service is running using `docker service ls` and
    `docker service ps` commands.

    ```console
    $ docker service ls

    ID            NAME       MODE        REPLICAS  IMAGE
    wvnh0siktqr3  mysql      replicated  1/1       mysql:latest
    nzt5xzae4n62  wordpress  replicated  1/1       wordpress:latest
    ```

    ```console
    $ docker service ps wordpress

    ID            NAME         IMAGE             NODE  DESIRED STATE  CURRENT STATE           ERROR  PORTS
    aukx6hgs9gwc  wordpress.1  wordpress:latest  moby  Running        Running 52 seconds ago   
    ```

    At this point, you could actually revoke the WordPress service's access to
    the `mysql_password` secret, because WordPress has copied the secret to its
    configuration file `wp-config.php`. Don't do that for now, because we
    use it later to facilitate rotating the MySQL password.

7.  Access `http://localhost:30000/` from any swarm node and set up WordPress
    using the web-based wizard. All of these settings are stored in the MySQL
    `wordpress` database. WordPress automatically generates a password for your
    WordPress user, which is completely different from the password WordPress
    uses to access MySQL. Store this password securely, such as in a password
    manager. You need it to log into WordPress after
    [rotating the secret](#example-rotate-a-secret).

    Go ahead and write a blog post or two and install a WordPress plugin or
    theme to verify that WordPress is fully operational and its state is saved
    across service restarts.

8.  Do not clean up any services or secrets if you intend to proceed to the next
    example, which demonstrates how to rotate the MySQL root password.

### Example: Rotate a secret

This example builds upon the previous one. In this scenario, you create a new
secret with a new MySQL password, update the `mysql` and `wordpress` services to
use it, then remove the old secret.

> [!NOTE]
>
> Changing the password on a MySQL database involves running extra
> queries or commands, as opposed to just changing a single environment variable
> or a file, since the image only sets the MySQL password if the database doesn’t
> already exist, and MySQL stores the password within a MySQL database by default.
> Rotating passwords or other secrets may involve additional steps outside of
> Docker.

1.  Create the new password and store it as a secret named `mysql_password_v2`.

    ```console
    $ openssl rand -base64 20 | docker secret create mysql_password_v2 -
    ```

2.  Update the MySQL service to give it access to both the old and new secrets.
    Remember that you cannot update or rename a secret, but you can revoke a
    secret and grant access to it using a new target filename.

    ```console
    $ docker service update \
         --secret-rm mysql_password mysql

    $ docker service update \
         --secret-add source=mysql_password,target=old_mysql_password \
         --secret-add source=mysql_password_v2,target=mysql_password \
         mysql
    ```

    Updating a service causes it to restart, and when the MySQL service restarts
    the second time, it has access to the old secret under
    `/run/secrets/old_mysql_password` and the new secret under
    `/run/secrets/mysql_password`.

    Even though the MySQL service has access to both the old and new secrets
    now, the MySQL password for the WordPress user has not yet been changed.

    > [!NOTE]
    >
    > This example does not rotate the MySQL `root` password.

3.  Now, change the MySQL password for the `wordpress` user using the
    `mysqladmin` CLI. This command reads the old and new password from the files
    in `/run/secrets` but does not expose them on the command line or save them
    in the shell history.

    Do this quickly and move on to the next step, because WordPress loses
    the ability to connect to MySQL.

    First, find the ID of the `mysql` container task.

    ```console
    $ docker ps --filter name=mysql -q

    c7705cf6176f
    ```

    Substitute the ID in the command below, or use the second variant which
    uses shell expansion to do it all in a single step.

    ```console
    $ docker container exec <CONTAINER_ID> \
        bash -c 'mysqladmin --user=wordpress --password="$(< /run/secrets/old_mysql_password)" password "$(< /run/secrets/mysql_password)"'
    ```

    Or:

    ```console
    $ docker container exec $(docker ps --filter name=mysql -q) \
        bash -c 'mysqladmin --user=wordpress --password="$(< /run/secrets/old_mysql_password)" password "$(< /run/secrets/mysql_password)"'
    ```

4.  Update the `wordpress` service to use the new password, keeping the target
    path at `/run/secrets/wp_db_password`. This triggers a rolling restart of
    the WordPress service and the new secret is used.

    ```console
    $ docker service update \
         --secret-rm mysql_password \
         --secret-add source=mysql_password_v2,target=wp_db_password \
         wordpress    
    ```

5.  Verify that WordPress works by browsing to http://localhost:30000/ on any
    swarm node again. Use the WordPress username and password
    from when you ran through the WordPress wizard in the previous task.

    Verify that the blog post you wrote still exists, and if you changed any
    configuration values, verify that they are still changed.

6.  Revoke access to the old secret from the MySQL service and
    remove the old secret from Docker.

    ```console
    $ docker service update \
         --secret-rm mysql_password \
         mysql

    $ docker secret rm mysql_password
    ```


7.  Run the following commands to remove the WordPress service, the MySQL container,
    the `mydata` and `wpdata` volumes, and the Docker secrets:

    ```console
    $ docker service rm wordpress mysql

    $ docker volume rm mydata wpdata

    $ docker secret rm mysql_password_v2 mysql_root_password
    ```

## Build support for Docker Secrets into your images

If you develop a container that can be deployed as a service and requires
sensitive data, such as a credential, as an environment variable, consider
adapting your image to take advantage of Docker secrets. One way to do this is
to ensure that each parameter you pass to the image when creating the container
can also be read from a file.

Many of the Docker Official Images in the
[Docker library](https://github.com/docker-library/), such as the
[wordpress](https://github.com/docker-library/wordpress/)
image used in the above examples, have been updated in this way.

When you start a WordPress container, you provide it with the parameters it
needs by setting them as environment variables. The WordPress image has been
updated so that the environment variables which contain important data for
WordPress, such as `WORDPRESS_DB_PASSWORD`, also have variants which can read
their values from a file (`WORDPRESS_DB_PASSWORD_FILE`). This strategy ensures
that backward compatibility is preserved, while allowing your container to read
the information from a Docker-managed secret instead of being passed directly.

> [!NOTE]
>
> Docker secrets do not set environment variables directly. This was a
> conscious decision, because environment variables can unintentionally be leaked
> between containers (for instance, if you use `--link`).

## Use Secrets in Compose

```yaml

services:
   db:
     image: mysql:latest
     volumes:
       - db_data:/var/lib/mysql
     environment:
       MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_root_password
       - db_password

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     ports:
       - "8000:80"
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password
     secrets:
       - db_password


secrets:
   db_password:
     file: db_password.txt
   db_root_password:
     file: db_root_password.txt

volumes:
    db_data:
```

This example creates a simple WordPress site using two secrets in
a Compose file.

The top-level element `secrets` defines two secrets `db_password` and
`db_root_password`.

When deploying, Docker creates these two secrets and populates them with the
content from the file specified in the Compose file.

The `db` service uses both secrets, and `wordpress` is using one.

When you deploy, Docker mounts a file under `/run/secrets/<secret_name>` in the
services. These files are never persisted on disk, but are managed in memory.

Each service uses environment variables to specify where the service should look
for that secret data.

More information on short and long syntax for secrets can be found in the
[Compose Specification](../../reference/compose-file/secrets.md).


---

# Deploy services to a swarm

*Sección: Engine*

Swarm services use a declarative model, which means that you define the
desired state of the service, and rely upon Docker to maintain this state. The
state includes information such as (but not limited to):

- The image name and tag the service containers should run
- How many containers participate in the service
- Whether any ports are exposed to clients outside the swarm
- Whether the service should start automatically when Docker starts
- The specific behavior that happens when the service is restarted (such as
  whether a rolling restart is used)
- Characteristics of the nodes where the service can run (such as resource
  constraints and placement preferences)

For an overview of Swarm mode, see [Swarm mode key concepts](key-concepts.md).
For an overview of how services work, see
[How services work](how-swarm-mode-works/services.md).

## Create a service

To create a single-replica service with no extra configuration, you only need
to supply the image name. This command starts an Nginx service with a
randomly-generated name and no published ports. This is a naive example, since
you can't interact with the Nginx service.

```console
$ docker service create nginx
```

The service is scheduled on an available node. To confirm that the service
was created and started successfully, use the `docker service ls` command:

```console
$ docker service ls

ID                  NAME                MODE                REPLICAS            IMAGE                                                                                             PORTS
a3iixnklxuem        quizzical_lamarr    replicated          1/1                 docker.io/library/nginx@sha256:41ad9967ea448d7c2b203c699b429abe1ed5af331cd92533900c6d77490e0268
```

Created services do not always run right away. A service can be in a pending
state if its image is unavailable, if no node meets the requirements you
configure for the service, or for other reasons. See
[Pending services](how-swarm-mode-works/services.md#pending-services) for more
information.

To provide a name for your service, use the `--name` flag:

```console
$ docker service create --name my_web nginx
```

Just like with standalone containers, you can specify a command that the
service's containers should run, by adding it after the image name. This example
starts a service called `helloworld` which uses an `alpine` image and runs the
command `ping docker.com`:

```console
$ docker service create --name helloworld alpine ping docker.com
```

You can also specify an image tag for the service to use. This example modifies
the previous one to use the `alpine:3.6` tag:

```console
$ docker service create --name helloworld alpine:3.6 ping docker.com
```

For more details about image tag resolution, see
[Specify the image version the service should use](#specify-the-image-version-a-service-should-use).

### gMSA for Swarm

> [!NOTE]
>
> This example only works for a Windows container.

Swarm now allows using a Docker config as a gMSA credential spec - a requirement for Active Directory-authenticated applications. This reduces the burden of distributing credential specs to the nodes they're used on. 

The following example assumes a gMSA and its credential spec (called credspec.json) already exists, and that the nodes being deployed to are correctly configured for the gMSA.

To use a config as a credential spec, first create the Docker config containing the credential spec:

```console
$ docker config create credspec credspec.json
```

Now, you should have a Docker config named credspec, and you can create a service using this credential spec. To do so, use the --credential-spec flag with the config name, like this:

```console
$ docker service create --credential-spec="config://credspec" <your image>
```

Your service uses the gMSA credential spec when it starts, but unlike a typical Docker config (used by passing the --config flag), the credential spec is not mounted into the container.

### Create a service using an image on a private registry

If your image is available on a private registry which requires login, use the
`--with-registry-auth` flag with `docker service create`, after logging in. If
your image is stored on `registry.example.com`, which is a private registry, use
a command like the following:

```console
$ docker login registry.example.com

$ docker service  create \
  --with-registry-auth \
  --name my_service \
  registry.example.com/acme/my_image:latest
```

This passes the login token from your local client to the swarm nodes where the
service is deployed, using the encrypted WAL logs. With this information, the
nodes are able to log into the registry and pull the image.

### Provide credential specs for managed service accounts

 In Enterprise Edition 3.0, security is improved through the centralized distribution and management of Group Managed Service Account(gMSA) credentials using Docker config functionality. Swarm now allows using a Docker config as a gMSA credential spec, which reduces the burden of distributing credential specs to the nodes on which they are used. 

> [!NOTE]
>
> This option is only applicable to services using Windows containers.

 Credential spec files are applied at runtime, eliminating the need for host-based credential spec files or registry entries - no gMSA credentials are written to disk on worker nodes. You can make credential specs available to Docker Engine running swarm kit worker nodes before a container starts. When deploying a service using a gMSA-based config, the credential spec is passed directly to the runtime of containers in that service.

 The `--credential-spec` must be in one of the following formats:

 - `file://<filename>`: The referenced file must be present in the `CredentialSpecs` subdirectory in the docker data directory, which defaults to `C:\ProgramData\Docker\` on Windows. For example, specifying `file://spec.json` loads `C:\ProgramData\Docker\CredentialSpecs\spec.json`.
- `registry://<value-name>`: The credential spec is read from the Windows registry on the daemon’s host. 
- `config://<config-name>`: The config name is automatically converted to the config ID in the CLI. 
The credential spec contained in the specified `config` is used.

 The following simple example retrieves the gMSA name and JSON contents from your Active Directory (AD) instance:

 ```console
$ name="mygmsa"
$ contents="{...}"
$ echo $contents > contents.json
```

Make sure that the nodes to which you are deploying are correctly configured for the gMSA.

 To use a config as a credential spec, create a Docker config in a credential spec file named `credpspec.json`. 
 You can specify any name for the name of the `config`. 

```console
$ docker config create --label com.docker.gmsa.name=mygmsa credspec credspec.json
```

Now you can create a service using this credential spec. Specify the `--credential-spec` flag with the config name:

```console
$ docker service create --credential-spec="config://credspec" <your image>
```

 Your service uses the gMSA credential spec when it starts, but unlike a typical Docker config (used by passing the --config flag), the credential spec is not mounted into the container.

## Update a service

You can change almost everything about an existing service using the
`docker service update` command. When you update a service, Docker stops its
containers and restarts them with the new configuration.

Since Nginx is a web service, it works much better if you publish port 80
to clients outside the swarm. You can specify this when you create the service,
using the `-p` or `--publish` flag. When updating an existing service, the flag
is `--publish-add`. There is also a `--publish-rm` flag to remove a port that
was previously published.

Assuming that the `my_web` service from the previous section still exists, use
the following command to update it to publish port 80.

```console
$ docker service update --publish-add 80 my_web
```

To verify that it worked, use `docker service ls`:

```console
$ docker service ls

ID                  NAME                MODE                REPLICAS            IMAGE                                                                                             PORTS
4nhxl7oxw5vz        my_web              replicated          1/1                 docker.io/library/nginx@sha256:41ad9967ea448d7c2b203c699b429abe1ed5af331cd92533900c6d77490e0268   *:0->80/tcp
```

For more information on how publishing ports works, see
[publish ports](#publish-ports).

You can update almost every configuration detail about an existing service,
including the image name and tag it runs. See
[Update a service's image after creation](#update-a-services-image-after-creation).

## Remove a service

To remove a service, use the `docker service remove` command. You can remove a
service by its ID or name, as shown in the output of the `docker service ls`
command. The following command removes the `my_web` service.

```console
$ docker service remove my_web
```

## Service configuration details

The following sections provide details about service configuration. This topic
does not cover every flag or scenario. In almost every instance where you can
define a configuration at service creation, you can also update an existing
service's configuration in a similar way.

See the command-line references for
[`docker service create`](/reference/cli/docker/service/create/) and
[`docker service update`](/reference/cli/docker/service/update/), or run
one of those commands with the `--help` flag.

### Configure the runtime environment

You can configure the following options for the runtime environment in the
container:

* Environment variables using the `--env` flag
* The working directory inside the container using the `--workdir` flag
* The username or UID using the `--user` flag

The following service's containers have an environment variable `$MYVAR`
set to `myvalue`, run from the `/tmp/` directory, and run as the
`my_user` user.

```console
$ docker service create --name helloworld \
  --env MYVAR=myvalue \
  --workdir /tmp \
  --user my_user \
  alpine ping docker.com
```

### Update the command an existing service runs

To update the command an existing service runs, you can use the `--args` flag.
The following example updates an existing service called `helloworld` so that
it runs the command `ping docker.com` instead of whatever command it was running
before:

```console
$ docker service update --args "ping docker.com" helloworld
```

### Specify the image version a service should use

When you create a service without specifying any details about the version of
the image to use, the service uses the version tagged with the `latest` tag.
You can force the service to use a specific version of the image in a few
different ways, depending on your desired outcome.

An image version can be expressed in several different ways:

- If you specify a tag, the manager (or the Docker client, if you use
  [content trust](../security/trust/index.md)) resolves that tag to a digest.
  When the request to create a container task is received on a worker node, the
  worker node only sees the digest, not the tag.

  ```console
  $ docker service create --name="myservice" ubuntu:16.04
  ```

  Some tags represent discrete releases, such as `ubuntu:16.04`. Tags like this
  almost always resolve to a stable digest over time. It is recommended
  that you use this kind of tag when possible.

  Other types of tags, such as `latest` or `nightly`, may resolve to a new
  digest often, depending on how often an image's author updates the tag. It is
  not recommended to run services using a tag which is updated frequently, to
  prevent different service replica tasks from using different image versions.

- If you don't specify a version at all, by convention the image's `latest` tag
  is resolved to a digest. Workers use the image at this digest when creating
  the service task.

  Thus, the following two commands are equivalent:

  ```console
  $ docker service create --name="myservice" ubuntu

  $ docker service create --name="myservice" ubuntu:latest
  ```

- If you specify a digest directly, that exact version of the image is always
  used when creating service tasks.

  ```console
  $ docker service create \
      --name="myservice" \
      ubuntu:16.04@sha256:35bc48a1ca97c3971611dc4662d08d131869daa692acb281c7e9e052924e38b1
  ```

When you create a service, the image's tag is resolved to the specific digest
the tag points to **at the time of service creation**. Worker nodes for that
service use that specific digest forever unless the service is explicitly
updated. This feature is particularly important if you do use often-changing tags
such as `latest`, because it ensures that all service tasks use the same version
of the image.

> [!NOTE]>
>
> If [content trust](../security/trust/index.md) is
> enabled, the client actually resolves the image's tag to a digest before
> contacting the swarm manager, to verify that the image is signed.
> Thus, if you use content trust, the swarm manager receives the request
> pre-resolved. In this case, if the client cannot resolve the image to a
> digest, the request fails.

If the manager can't resolve the tag to a digest, each worker
node is responsible for resolving the tag to a digest, and different nodes may
use different versions of the image. If this happens, a warning like the
following is logged, substituting the placeholders for real information.

```text
unable to pin image <IMAGE-NAME> to digest: <REASON>
```

To see an image's current digest, issue the command
`docker inspect <IMAGE>:<TAG>` and look for the `RepoDigests` line. The
following is the current digest for `ubuntu:latest` at the time this content
was written. The output is truncated for clarity.

```console
$ docker inspect ubuntu:latest
```

```json
"RepoDigests": [
    "ubuntu@sha256:35bc48a1ca97c3971611dc4662d08d131869daa692acb281c7e9e052924e38b1"
],
```

After you create a service, its image is never updated unless you explicitly run
`docker service update` with the `--image` flag as described below. Other update
operations such as scaling the service, adding or removing networks or volumes,
renaming the service, or any other type of update operation do not update the
service's image.

### Update a service's image after creation

Each tag represents a digest, similar to a Git hash. Some tags, such as
`latest`, are updated often to point to a new digest. Others, such as
`ubuntu:16.04`, represent a released software version and are not expected to
update to point to a new digest often if at all. When you create a service, it
is constrained to create tasks using a specific digest of an image until you
update the service using `service update` with the `--image` flag.

When you run `service update` with the `--image` flag, the swarm manager queries
Docker Hub or your private Docker registry for the digest the tag currently
points to and updates the service tasks to use that digest.

> [!NOTE]
>
> If you use [content trust](../security/trust/index.md), the Docker
> client resolves image and the swarm manager receives the image and digest,
>  rather than a tag.

Usually, the manager can resolve the tag to a new digest and the service
updates, redeploying each task to use the new image. If the manager can't
resolve the tag or some other problem occurs, the next two sections outline what
to expect.

#### If the manager resolves the tag

If the swarm manager can resolve the image tag to a digest, it instructs the
worker nodes to redeploy the tasks and use the image at that digest.

- If a worker has cached the image at that digest, it uses it.

- If not, it attempts to pull the image from Docker Hub or the private registry.

  - If it succeeds, the task is deployed using the new image.

  - If the worker fails to pull the image, the service fails to deploy on that
    worker node. Docker tries again to deploy the task, possibly on a different
    worker node.

#### If the manager cannot resolve the tag

If the swarm manager cannot resolve the image to a digest, all is not lost:

- The manager instructs the worker nodes to redeploy the tasks using the image
  at that tag.

- If the worker has a locally cached image that resolves to that tag, it uses
  that image.

- If the worker does not have a locally cached image that resolves to the tag,
  the worker tries to connect to Docker Hub or the private registry to pull the
  image at that tag.

  - If this succeeds, the worker uses that image.

  - If this fails, the task fails to deploy and the manager tries again to deploy
    the task, possibly on a different worker node.

### Publish ports

When you create a swarm service, you can publish that service's ports to hosts
outside the swarm in two ways:

- [You can rely on the routing mesh](#publish-a-services-ports-using-the-routing-mesh).
  When you publish a service port, the swarm makes the service accessible at the
  target port on every node, regardless of whether there is a task for the
  service running on that node or not. This is less complex and is the right
  choice for many types of services.

- [You can publish a service task's port directly on the swarm node](#publish-a-services-ports-directly-on-the-swarm-node)
  where that service is running. This bypasses the routing mesh and provides the
  maximum flexibility, including the ability for you to develop your own routing
  framework. However, you are responsible for keeping track of where each task is
  running and routing requests to the tasks, and load-balancing across the nodes.

Keep reading for more information and use cases for each of these methods.

#### Publish a service's ports using the routing mesh

To publish a service's ports externally to the swarm, use the
`--publish <PUBLISHED-PORT>:<SERVICE-PORT>` flag. The swarm makes the service
accessible at the published port on every swarm node. If an external host
connects to that port on any swarm node, the routing mesh routes it to a task.
The external host does not need to know the IP addresses or internally-used
ports of the service tasks to interact with the service. When a user or process
connects to a service, any worker node running a service task may respond. For
more details about swarm service networking, see
[Manage swarm service networks](networking.md).

##### Example: Run a three-task Nginx service on 10-node swarm

Imagine that you have a 10-node swarm, and you deploy an Nginx service running
three tasks on a 10-node swarm:

```console
$ docker service create --name my_web \
                        --replicas 3 \
                        --publish published=8080,target=80 \
                        nginx
```

Three tasks run on up to three nodes. You don't need to know which nodes
are running the tasks; connecting to port 8080 on any of the 10 nodes
connects you to one of the three `nginx` tasks. You can test this using `curl`.
The following example assumes that `localhost` is one of the swarm nodes. If
this is not the case, or `localhost` does not resolve to an IP address on your
host, substitute the host's IP address or resolvable host name.

The HTML output is truncated:

```console
$ curl localhost:8080

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...truncated...
</html>
```

Subsequent connections may be routed to the same swarm node or a different one.

#### Publish a service's ports directly on the swarm node

Using the routing mesh may not be the right choice for your application if you
need to make routing decisions based on application state or you need total
control of the process for routing requests to your service's tasks. To publish
a service's port directly on the node where it is running, use the `mode=host`
option to the `--publish` flag.

> [!NOTE]
>
> If you publish a service's ports directly on the swarm node using
> `mode=host` and also set `published=<PORT>` this creates an implicit
> limitation that you can only run one task for that service on a given swarm
> node. You can work around this by specifying `published` without a port
> definition, which causes Docker to assign a random port for each task.
>
> In addition, if you use `mode=host` and you do not use the
> `--mode=global` flag on `docker service create`, it is difficult to know
> which nodes are running the service to route work to them.

##### Example: Run an `nginx` web server service on every swarm node

[nginx](https://hub.docker.com/_/nginx/) is an open source reverse proxy, load
balancer, HTTP cache, and a web server. If you run nginx as a service using the
routing mesh, connecting to the nginx port on any swarm node shows you the
web page for (effectively) a random swarm node running the service.

The following example runs nginx as a service on each node in your swarm and
exposes nginx port locally on each swarm node.

```console
$ docker service create \
  --mode global \
  --publish mode=host,target=80,published=8080 \
  --name=nginx \
  nginx:latest
```

You can reach the nginx server on port 8080 of every swarm node. If you add a
node to the swarm, a nginx task is started on it. You cannot start another
service or container on any swarm node which binds to port 8080.

> [!NOTE]
>
> This is a purely illustrative example. Creating an application-layer
> routing framework for a multi-tiered service is complex and out of scope for
> this topic.

### Connect the service to an overlay network

You can use overlay networks to connect one or more services within the swarm.

First, create overlay network on a manager node using the `docker network create`
command with the `--driver overlay` flag.

```console
$ docker network create --driver overlay my-network
```

After you create an overlay network in swarm mode, all manager nodes have access
to the network.

You can create a new service and pass the `--network` flag to attach the service
to the overlay network:

```console
$ docker service create \
  --replicas 3 \
  --network my-network \
  --name my-web \
  nginx
```

The swarm extends `my-network` to each node running the service.

You can also connect an existing service to an overlay network using the
`--network-add` flag.

```console
$ docker service update --network-add my-network my-web
```

To disconnect a running service from a network, use the `--network-rm` flag.

```console
$ docker service update --network-rm my-network my-web
```

For more information on overlay networking and service discovery, refer to
[Attach services to an overlay network](networking.md) and
[Docker swarm mode overlay network security model](../network/drivers/overlay.md).

### Grant a service access to secrets

To create a service with access to Docker-managed secrets, use the `--secret`
flag. For more information, see
[Manage sensitive strings (secrets) for Docker services](secrets.md)

### Customize a service's isolation mode

> [!IMPORTANT]
>
> This setting applies to Windows hosts only and is ignored for Linux hosts.

Docker allows you to specify a swarm service's isolation
mode. The isolation mode can be one of the following:

- `default`: Use the default isolation mode configured for the Docker host, as
  configured by the `-exec-opt` flag or `exec-opts` array in `daemon.json`. If
  the daemon does not specify an isolation technology, `process` is the default
  for Windows Server, and `hyperv` is the default (and only) choice for
  Windows 10.

- `process`: Run the service tasks as a separate process on the host.

  > [!NOTE]
  >
  > `process` isolation mode is only supported on Windows Server.
  > Windows 10 only supports `hyperv` isolation mode.

- `hyperv`: Run the service tasks as isolated `hyperv` tasks. This increases
  overhead but provides more isolation.

You can specify the isolation mode when creating or updating a new service using
the `--isolation` flag.

### Control service placement

Swarm services provide a few different ways for you to control scale and
placement of services on different nodes.

- You can specify whether the service needs to run a specific number of replicas
  or should run globally on every worker node. See
  [Replicated or global services](#replicated-or-global-services).

- You can configure the service's
  [CPU or memory requirements](#reserve-memory-or-cpus-for-a-service), and the
  service only runs on nodes which can meet those requirements.

- [Placement constraints](#placement-constraints) let you configure the service
  to run only on nodes with specific (arbitrary) metadata set, and cause the
  deployment to fail if appropriate nodes do not exist. For instance, you can
  specify that your service should only run on nodes where an arbitrary label
  `pci_compliant` is set to `true`.

- [Placement preferences](#placement-preferences) let you apply an arbitrary
  label with a range of values to each node, and spread your service's tasks
  across those nodes using an algorithm. Currently, the only supported algorithm
  is `spread`, which tries to place them evenly. For instance, if you
  label each node with a label `rack` which has a value from 1-10, then specify
  a placement preference keyed on `rack`, then service tasks are placed as
  evenly as possible across all nodes with the label `rack`, after taking other
  placement constraints, placement preferences, and other node-specific
  limitations into account.

  Unlike constraints, placement preferences are best-effort, and a service does
  not fail to deploy if no nodes can satisfy the preference. If you specify a
  placement preference for a service, nodes that match that preference are
  ranked higher when the swarm managers decide which nodes should run the
  service tasks. Other factors, such as high availability of the service,
  also factor into which nodes are scheduled to run service tasks. For
  example, if you have N nodes with the rack label (and then some others), and
  your service is configured to run N+1 replicas, the +1 is scheduled on a
  node that doesn't already have the service on it if there is one, regardless
  of whether that node has the `rack` label or not.


#### Replicated or global services

Swarm mode has two types of services: replicated and global. For replicated
services, you specify the number of replica tasks for the swarm manager to
schedule onto available nodes. For global services, the scheduler places one
task on each available node that meets the service's
[placement constraints](#placement-constraints) and
[resource requirements](#reserve-memory-or-cpus-for-a-service).

You control the type of service using the `--mode` flag. If you don't specify a
mode, the service defaults to `replicated`. For replicated services, you specify
the number of replica tasks you want to start using the `--replicas` flag. For
example, to start a replicated nginx service with 3 replica tasks:

```console
$ docker service create \
  --name my_web \
  --replicas 3 \
  nginx
```

To start a global service on each available node, pass `--mode global` to
`docker service create`. Every time a new node becomes available, the scheduler
places a task for the global service on the new node. For example to start a
service that runs alpine on every node in the swarm:

```console
$ docker service create \
  --name myservice \
  --mode global \
  alpine top
```

Service constraints let you set criteria for a node to meet before the scheduler
deploys a service to the node. You can apply constraints to the
service based upon node attributes and metadata or engine metadata. For more
information on constraints, refer to the `docker service create`
[CLI reference](/reference/cli/docker/service/create/).

#### Reserve memory or CPUs for a service

To reserve a given amount of memory or number of CPUs for a service, use the
`--reserve-memory` or `--reserve-cpu` flags. If no available nodes can satisfy
the requirement (for instance, if you request 4 CPUs and no node in the swarm
has 4 CPUs), the service remains in a pending state until an appropriate node is
available to run its tasks.

##### Out Of Memory Exceptions (OOME)

If your service attempts to use more memory than the swarm node has available,
you may experience an Out Of Memory Exception (OOME) and a container, or the
Docker daemon, might be killed by the kernel OOM killer. To prevent this from
happening, ensure that your application runs on hosts with adequate memory and
see
[Understand the risks of running out of memory](../containers/resource-constraints.md#understand-the-risks-of-running-out-of-memory).

Swarm services allow you to use resource constraints, placement preferences, and
labels to ensure that your service is deployed to the appropriate swarm nodes.

#### Placement constraints

Use placement constraints to control the nodes a service can be assigned to. In
the following example, the service only runs on nodes with the
[label](manage-nodes.md#add-or-remove-label-metadata) `region` set
to `east`. If no appropriately-labelled nodes are available, tasks will wait in
`Pending` until they become available. The `--constraint` flag uses an equality
operator (`==` or `!=`). For replicated services, it is possible that all
services run on the same node, or each node only runs one replica, or that some
nodes don't run any replicas. For global services, the service runs on every
node that meets the placement constraint and any [resource requirements](#reserve-memory-or-cpus-for-a-service).

```console
$ docker service create \
  --name my-nginx \
  --replicas 5 \
  --constraint node.labels.region==east \
  nginx
```

You can also use the `constraint` service-level key in a `compose.yaml`
file.

If you specify multiple placement constraints, the service only deploys onto
nodes where they are all met. The following example limits the service to run on
all nodes where `region` is set to `east` and `type` is not set to `devel`:

```console
$ docker service create \
  --name my-nginx \
  --mode global \
  --constraint node.labels.region==east \
  --constraint node.labels.type!=devel \
  nginx
```

You can also use placement constraints in conjunction with placement preferences
and CPU/memory constraints. Be careful not to use settings that are not
possible to fulfill.

For more information on constraints, refer to the `docker service create`
[CLI reference](/reference/cli/docker/service/create/).

#### Placement preferences

While [placement constraints](#placement-constraints) limit the nodes a service
can run on, _placement preferences_ try to place tasks on appropriate nodes
in an algorithmic way (currently, only spread evenly). For instance, if you
assign each node a `rack` label, you can set a placement preference to spread
the service evenly across nodes with the `rack` label, by value. This way, if
you lose a rack, the service is still running on nodes on other racks.

Placement preferences are not strictly enforced. If no node has the label
you specify in your preference, the service is deployed as though the
preference were not set.

> [!NOTE]
>
> Placement preferences are ignored for global services.

The following example sets a preference to spread the deployment across nodes
based on the value of the `datacenter` label. If some nodes have
`datacenter=us-east` and others have `datacenter=us-west`, the service is
deployed as evenly as possible across the two sets of nodes.

```console
$ docker service create \
  --replicas 9 \
  --name redis_2 \
  --placement-pref 'spread=node.labels.datacenter' \
  redis:7.4.0
```

> [!NOTE]
>
> Nodes which are missing the label used to spread still receive
> task assignments. As a group, these nodes receive tasks in equal
> proportion to any of the other groups identified by a specific label
> value. In a sense, a missing label is the same as having the label with
> a null value attached to it. If the service should only run on
> nodes with the label being used for the spread preference, the
> preference should be combined with a constraint.

You can specify multiple placement preferences, and they are processed in the
order they are encountered. The following example sets up a service with
multiple placement preferences. Tasks are spread first over the various
datacenters, and then over racks (as indicated by the respective labels):

```console
$ docker service create \
  --replicas 9 \
  --name redis_2 \
  --placement-pref 'spread=node.labels.datacenter' \
  --placement-pref 'spread=node.labels.rack' \
  redis:7.4.0
```

You can also use placement preferences in conjunction with placement constraints
or CPU/memory constraints. Be careful not to use settings that are not
possible to fulfill.

This diagram illustrates how placement preferences work:

![How placement preferences work](images/placement_prefs.png)

When updating a service with `docker service update`, `--placement-pref-add`
appends a new placement preference after all existing placement preferences.
`--placement-pref-rm` removes an existing placement preference that matches the
argument.


### Configure a service's update behavior

When you create a service, you can specify a rolling update behavior for how the
swarm should apply changes to the service when you run `docker service update`.
You can also specify these flags as part of the update, as arguments to
`docker service update`.

The `--update-delay` flag configures the time delay between updates to a service
task or sets of tasks. You can describe the time `T` as a combination of the
number of seconds `Ts`, minutes `Tm`, or hours `Th`. So `10m30s` indicates a 10
minute 30 second delay.

By default the scheduler updates 1 task at a time. You can pass the
`--update-parallelism` flag to configure the maximum number of service tasks
that the scheduler updates simultaneously.

When an update to an individual task returns a state of `RUNNING`, the scheduler
continues the update by continuing to another task until all tasks are updated.
If at any time during an update a task returns `FAILED`, the scheduler pauses
the update. You can control the behavior using the `--update-failure-action`
flag for `docker service create` or `docker service update`.

In the example service below, the scheduler applies updates to a maximum of 2
replicas at a time. When an updated task returns either `RUNNING` or `FAILED`,
the scheduler waits 10 seconds before stopping the next task to update:

```console
$ docker service create \
  --replicas 10 \
  --name my_web \
  --update-delay 10s \
  --update-parallelism 2 \
  --update-failure-action continue \
  alpine
```

The `--update-max-failure-ratio` flag controls what fraction of tasks can fail
during an update before the update as a whole is considered to have failed. For
example, with `--update-max-failure-ratio 0.1 --update-failure-action pause`,
after 10% of the tasks being updated fail, the update is paused.

An individual task update is considered to have failed if the task doesn't
start up, or if it stops running within the monitoring period specified with
the `--update-monitor` flag. The default value for `--update-monitor` is 30
seconds, which means that a task failing in the first 30 seconds after it's
started counts towards the service update failure threshold, and a failure
after that is not counted.

### Roll back to the previous version of a service

In case the updated version of a service doesn't function as expected, it's
possible to manually roll back to the previous version of the service using
`docker service update`'s `--rollback` flag. This reverts the service
to the configuration that was in place before the most recent
`docker service update` command.

Other options can be combined with `--rollback`; for example,
`--update-delay 0s`, to execute the rollback without a delay between tasks:

```console
$ docker service update \
  --rollback \
  --update-delay 0s
  my_web
```

You can configure a service to roll back automatically if a service update fails
to deploy. See [Automatically roll back if an update fails](#automatically-roll-back-if-an-update-fails).

Manual rollback is handled at the server side, which allows manually-initiated
rollbacks to respect the new rollback parameters. Note that `--rollback` cannot
be used in conjunction with other flags to `docker service update`.

### Automatically roll back if an update fails

You can configure a service in such a way that if an update to the service
causes redeployment to fail, the service can automatically roll back to the
previous configuration. This helps protect service availability. You can set
one or more of the following flags at service creation or update. If you do not
set a value, the default is used.

| Flag                           | Default | Description                                                                                                                                                                                                                                                                                                             |
|:-------------------------------|:--------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `--rollback-delay`             | `0s`    | Amount of time to wait after rolling back a task before rolling back the next one. A value of `0` means to roll back the second task immediately after the first rolled-back task deploys.                                                                                                                              |
| `--rollback-failure-action`    | `pause` | When a task fails to roll back, whether to `pause` or `continue` trying to roll back other tasks.                                                                                                                                                                                                                       |
| `--rollback-max-failure-ratio` | `0`     | The failure rate to tolerate during a rollback, specified as a floating-point number between 0 and 1. For instance, given 5 tasks, a failure ratio of `.2` would tolerate one task failing to roll back. A value of `0` means no failure are tolerated, while a value of `1` means any number of failure are tolerated. |
| `--rollback-monitor`           | `5s`    | Duration after each task rollback to monitor for failure. If a task stops before this time period has elapsed, the rollback is considered to have failed.                                                                                                                                                               |
| `--rollback-parallelism`       | `1`     | The maximum number of tasks to roll back in parallel. By default, one task is rolled back at a time. A value of `0` causes all tasks to be rolled back in parallel.                                                                                                                                                     |

The following example configures a `redis` service to roll back automatically
if a `docker service update` fails to deploy. Two tasks can be rolled back in
parallel. Tasks are monitored for 20 seconds after rollback to be sure they do
not exit, and a maximum failure ratio of 20% is tolerated. Default values are
used for `--rollback-delay` and `--rollback-failure-action`.

```console
$ docker service create --name=my_redis \
                        --replicas=5 \
                        --rollback-parallelism=2 \
                        --rollback-monitor=20s \
                        --rollback-max-failure-ratio=.2 \
                        redis:latest
```

### Give a service access to volumes or bind mounts

For best performance and portability, you should avoid writing important data
directly into a container's writable layer. You should instead use data volumes
or bind mounts. This principle also applies to services.

You can create two types of mounts for services in a swarm, `volume` mounts or
`bind` mounts. Regardless of which type of mount you use, configure it using the
`--mount` flag when you create a service, or the `--mount-add` or `--mount-rm`
flag when updating an existing service. The default is a data volume if you
don't specify a type.

#### Data volumes

Data volumes are storage that exist independently of a container. The
lifecycle of data volumes under swarm services is similar to that under
containers. Volumes outlive tasks and services, so their removal must be
managed separately. Volumes can be created before deploying a service, or if
they don't exist on a particular host when a task is scheduled there, they are
created automatically according to the volume specification on the service.

To use existing data volumes with a service use the `--mount` flag:

```console
$ docker service create \
  --mount src=<VOLUME-NAME>,dst=<CONTAINER-PATH> \
  --name myservice \
  <IMAGE>
```

If a volume with the name `<VOLUME-NAME>` doesn't exist when a task is
scheduled to a particular host, then one is created. The default volume
driver is `local`.  To use a different volume driver with this create-on-demand
pattern, specify the driver and its options with the `--mount` flag:

```console
$ docker service create \
  --mount type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=<DRIVER>,volume-opt=<KEY0>=<VALUE0>,volume-opt=<KEY1>=<VALUE1>
  --name myservice \
  <IMAGE>
```

For more information on how to create data volumes and the use of volume
drivers, see [Use volumes](../storage/volumes.md).


#### Bind mounts

Bind mounts are file system paths from the host where the scheduler deploys
the container for the task. Docker mounts the path into the container. The
file system path must exist before the swarm initializes the container for the
task.

The following examples show bind mount syntax:

- To mount a read-write bind:

  ```console
  $ docker service create \
    --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH> \
    --name myservice \
    <IMAGE>
  ```

- To mount a read-only bind:

  ```console
  $ docker service create \
    --mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH>,readonly \
    --name myservice \
    <IMAGE>
  ```

> [!IMPORTANT]
>
> Bind mounts can be useful but they can also cause problems. In
> most cases, it is recommended that you architect your application such that
> mounting paths from the host is unnecessary. The main risks include the
> following:
>
> - If you bind mount a host path into your service’s containers, the path
>   must exist on every swarm node. The Docker swarm mode scheduler can schedule
>   containers on any machine that meets resource availability requirements
>   and satisfies all constraints and placement preferences you specify.
>
> - The Docker swarm mode scheduler may reschedule your running service
>   containers at any time if they become unhealthy or unreachable.
>
> - Host bind mounts are non-portable. When you use bind mounts, there is no
>   guarantee that your application runs the same way in development as it does
>   in production.

### Create services using templates

You can use templates for some flags of `service create`, using the syntax
provided by the Go's [text/template](https://golang.org/pkg/text/template/)
package.

The following flags are supported:

- `--hostname`
- `--mount`
- `--env`

Valid placeholders for the Go template are:

| Placeholder       | Description    |
|:------------------|:---------------|
| `.Service.ID`     | Service ID     |
| `.Service.Name`   | Service name   |
| `.Service.Labels` | Service labels |
| `.Node.ID`        | Node ID        |
| `.Node.Hostname`  | Node hostname  |
| `.Task.Name`      | Task name      |
| `.Task.Slot`      | Task slot      |

#### Template example

This example sets the template of the created containers based on the
service's name and the ID of the node where the container is running:


```console
$ docker service create --name hosttempl \
                        --hostname="{{.Node.ID}}-{{.Service.Name}}"\
                         busybox top
```


To see the result of using the template, use the `docker service ps` and
`docker inspect` commands.

```console
$ docker service ps va8ew30grofhjoychbr6iot8c

ID            NAME         IMAGE                                                                                   NODE          DESIRED STATE  CURRENT STATE               ERROR  PORTS
wo41w8hg8qan  hosttempl.1  busybox:latest@sha256:29f5d56d12684887bdfa50dcd29fc31eea4aaf4ad3bec43daf19026a7ce69912  2e7a8a9c4da2  Running        Running about a minute ago
```


```console
$ docker inspect --format="{{.Config.Hostname}}" hosttempl.1.wo41w8hg8qanxwjwsg4kxpprj
```


## Learn More

* [Swarm administration guide](admin-guide.md)
* [Docker Engine command line reference](/reference/cli/docker/)
* [Swarm mode tutorial](swarm-tutorial/index.md)


---

# Deploy a stack to a swarm

*Sección: Engine*

When running Docker Engine in swarm mode, you can use `docker stack deploy` to
deploy a complete application stack to the swarm. The `deploy` command accepts
a stack description in the form of a [Compose file](../../reference/compose-file/legacy-versions.md).

{{% include "swarm-compose-compat.md" %}}

To run through this tutorial, you need:

1.  A Docker Engine running in [Swarm mode](swarm-mode.md).
    If you're not familiar with Swarm mode, you might want to read
    [Swarm mode key concepts](key-concepts.md)
    and [How services work](how-swarm-mode-works/services.md).

    > [!NOTE]
    >
    > If you're trying things out on a local development environment,
    > you can put your engine into Swarm mode with `docker swarm init`.
    >
    > If you've already got a multi-node swarm running, keep in mind that all
    > `docker stack` and `docker service` commands must be run from a manager
    > node.

2.  A current version of [Docker Compose](../../compose/install/index.md).

## Set up a Docker registry

Because a swarm consists of multiple Docker Engines, a registry is required to
distribute images to all of them. You can use the
[Docker Hub](https://hub.docker.com) or maintain your own. Here's how to create
a throwaway registry, which you can discard afterward.

1.  Start the registry as a service on your swarm:

    ```console
    $ docker service create --name registry --publish published=5000,target=5000 registry:2
    ```

2.  Check its status with `docker service ls`:

    ```console
    $ docker service ls

    ID            NAME      REPLICAS  IMAGE                                                                               COMMAND
    l7791tpuwkco  registry  1/1       registry:2@sha256:1152291c7f93a4ea2ddc95e46d142c31e743b6dd70e194af9e6ebe530f782c17
    ```

    Once it reads `1/1` under `REPLICAS`, it's running. If it reads `0/1`, it's
    probably still pulling the image.

3.  Check that it's working with `curl`:

    ```console
    $ curl http://127.0.0.1:5000/v2/

    {}
    ```

## Create the example application

The app used in this guide is based on the hit counter app in the
[Get started with Docker Compose](../../compose/gettingstarted.md) guide. It consists
of a Python app which maintains a counter in a Redis instance and increments the
counter whenever you visit it.

1.  Create a directory for the project:

    ```console
    $ mkdir stackdemo
    $ cd stackdemo
    ```

2.  Create a file called `app.py` in the project directory and paste this in:

    ```python
    from flask import Flask
    from redis import Redis

    app = Flask(__name__)
    redis = Redis(host='redis', port=6379)

    @app.route('/')
    def hello():
        count = redis.incr('hits')
        return 'Hello World! I have been seen {} times.\n'.format(count)

    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=8000, debug=True)
    ```

3.  Create a file called `requirements.txt` and paste these two lines in:

    ```text
    flask
    redis
    ```

4.  Create a file called `Dockerfile` and paste this in:

    ```dockerfile
    # syntax=docker/dockerfile:1
    FROM python:3.4-alpine
    ADD . /code
    WORKDIR /code
    RUN pip install -r requirements.txt
    CMD ["python", "app.py"]
    ```

5.  Create a file called `compose.yaml` and paste this in:

    ```yaml
      services:
        web:
          image: 127.0.0.1:5000/stackdemo
          build: .
          ports:
            - "8000:8000"
        redis:
          image: redis:alpine
    ```

    The image for the web app is built using the Dockerfile defined
    above. It's also tagged with `127.0.0.1:5000` - the address of the registry
    created earlier. This is important when distributing the app to the
    swarm.


## Test the app with Compose

1.  Start the app with `docker compose up`. This builds the web app image,
    pulls the Redis image if you don't already have it, and creates two
    containers.

    You see a warning about the Engine being in swarm mode. This is because
    Compose doesn't take advantage of swarm mode, and deploys everything to a
    single node. You can safely ignore this.

    ```console
    $ docker compose up -d

    WARNING: The Docker Engine you're using is running in swarm mode.

    Compose does not use swarm mode to deploy services to multiple nodes in
    a swarm. All containers are scheduled on the current node.

    To deploy your application across the swarm, use `docker stack deploy`.

    Creating network "stackdemo_default" with the default driver
    Building web
    ...(build output)...
    Creating stackdemo_redis_1
    Creating stackdemo_web_1
    ```

2.  Check that the app is running with `docker compose ps`:

    ```console
    $ docker compose ps

          Name                     Command               State           Ports
    -----------------------------------------------------------------------------------
    stackdemo_redis_1   docker-entrypoint.sh redis ...   Up      6379/tcp
    stackdemo_web_1     python app.py                    Up      0.0.0.0:8000->8000/tcp
    ```

    You can test the app with `curl`:

    ```console
    $ curl http://localhost:8000
    Hello World! I have been seen 1 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 2 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 3 times.
    ```

3.  Bring the app down:

    ```console
    $ docker compose down --volumes

    Stopping stackdemo_web_1 ... done
    Stopping stackdemo_redis_1 ... done
    Removing stackdemo_web_1 ... done
    Removing stackdemo_redis_1 ... done
    Removing network stackdemo_default
    ```


## Push the generated image to the registry

To distribute the web app's image across the swarm, it needs to be pushed to the
registry you set up earlier. With Compose, this is very simple:

```console
$ docker compose push

Pushing web (127.0.0.1:5000/stackdemo:latest)...
The push refers to a repository [127.0.0.1:5000/stackdemo]
5b5a49501a76: Pushed
be44185ce609: Pushed
bd7330a79bcf: Pushed
c9fc143a069a: Pushed
011b303988d2: Pushed
latest: digest: sha256:a81840ebf5ac24b42c1c676cbda3b2cb144580ee347c07e1bc80e35e5ca76507 size: 1372
```

The stack is now ready to be deployed.


## Deploy the stack to the swarm

1.  Create the stack with `docker stack deploy`:

    ```console
    $ docker stack deploy --compose-file compose.yaml stackdemo

    Ignoring unsupported options: build

    Creating network stackdemo_default
    Creating service stackdemo_web
    Creating service stackdemo_redis
    ```

    The last argument is a name for the stack. Each network, volume and service
    name is prefixed with the stack name.

2.  Check that it's running with `docker stack services stackdemo`:

    ```console
    $ docker stack services stackdemo

    ID            NAME             MODE        REPLICAS  IMAGE
    orvjk2263y1p  stackdemo_redis  replicated  1/1       redis:3.2-alpine@sha256:f1ed3708f538b537eb9c2a7dd50dc90a706f7debd7e1196c9264edeea521a86d
    s1nf0xy8t1un  stackdemo_web    replicated  1/1       127.0.0.1:5000/stackdemo@sha256:adb070e0805d04ba2f92c724298370b7a4eb19860222120d43e0f6351ddbc26f
    ```

    Once it's running, you should see `1/1` under `REPLICAS` for both services.
    This might take some time if you have a multi-node swarm, as images need to
    be pulled.

    As before, you can test the app with `curl`:

    ```console
    $ curl http://localhost:8000
    Hello World! I have been seen 1 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 2 times.

    $ curl http://localhost:8000
    Hello World! I have been seen 3 times.
    ```

    With Docker's built-in routing mesh, you can access any node in the
    swarm on port `8000` and get routed to the app:

    ```console
    $ curl http://address-of-other-node:8000
    Hello World! I have been seen 4 times.
    ```

3.  Bring the stack down with `docker stack rm`:

    ```console
    $ docker stack rm stackdemo

    Removing service stackdemo_web
    Removing service stackdemo_redis
    Removing network stackdemo_default
    ```

4.  Bring the registry down with `docker service rm`:

    ```console
    $ docker service rm registry
    ```

5.  If you're just testing things out on a local machine and want to bring your
    Docker Engine out of Swarm mode, use `docker swarm leave`:

    ```console
    $ docker swarm leave --force

    Node left the swarm.
    ```


---

# Run Docker Engine in swarm mode

*Sección: Engine*

When you first install and start working with Docker Engine, Swarm mode is
disabled by default. When you enable Swarm mode, you work with the concept of
services managed through the `docker service` command.

There are two ways to run the engine in Swarm mode:

* Create a new swarm, covered in this article.
* [Join an existing swarm](join-nodes.md).

When you run the engine in Swarm mode on your local machine, you can create and
test services based upon images you've created or other available images. In
your production environment, Swarm mode provides a fault-tolerant platform with
cluster management features to keep your services running and available.

These instructions assume you have installed the Docker Engine on
a machine to serve as a manager node in your swarm.

If you haven't already, read through the [Swarm mode key concepts](key-concepts.md)
and try the [Swarm mode tutorial](swarm-tutorial/index.md).

## Create a swarm

When you run the command to create a swarm, Docker Engine starts running in Swarm mode.

Run [`docker swarm init`](/reference/cli/docker/swarm/init/)
to create a single-node swarm on the current node. The engine sets up the swarm
as follows:

* Switches the current node into Swarm mode.
* Creates a swarm named `default`.
* Designates the current node as a leader manager node for the swarm.
* Names the node with the machine hostname.
* Configures the manager to listen on an active network interface on port `2377`.
* Sets the current node to `Active` availability, meaning it can receive tasks
from the scheduler.
* Starts an internal distributed data store for Engines participating in the
swarm to maintain a consistent view of the swarm and all services running on it.
* By default, generates a self-signed root CA for the swarm.
* By default, generates tokens for worker and manager nodes to join the
swarm.
* Creates an overlay network named `ingress` for publishing service ports
external to the swarm.
* Creates an overlay default IP addresses and subnet mask for your networks

The output for `docker swarm init` provides the connection command to use when
you join new worker nodes to the swarm:

```console
$ docker swarm init
Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
    192.168.99.100:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
```

### Configuring default address pools

By default Swarm mode uses a default address pool `10.0.0.0/8` for global scope (overlay) networks. Every 
network that does not have a subnet specified will have a subnet sequentially allocated from this pool. In 
some circumstances it may be desirable to use a different default IP address pool for networks. 

For example, if the default `10.0.0.0/8` range conflicts with already allocated address space in your network, 
then it is desirable to ensure that networks use a different range without requiring swarm users to specify 
each subnet with the `--subnet` command. 

To configure custom default address pools, you must define pools at swarm initialization using the 
`--default-addr-pool` command line option. This command line option uses CIDR notation for defining the subnet mask.
To create the custom address pool for Swarm, you must define at least one default address pool, and an optional default address pool subnet mask. For example, for the `10.0.0.0/27`, use the value `27`.

Docker allocates subnet addresses from the address ranges specified by the `--default-addr-pool` option. For example, a command line option `--default-addr-pool 10.10.0.0/16` indicates that Docker will allocate subnets from that `/16` address range. If `--default-addr-pool-mask-len` were unspecified or set explicitly to 24, this would result in 256 `/24` networks of the form `10.10.X.0/24`.

The subnet range comes from the `--default-addr-pool`, (such as `10.10.0.0/16`). The size of 16 there represents the number of networks one can create within that `default-addr-pool` range. The `--default-addr-pool` option may occur multiple times with each option providing additional addresses for docker to use for overlay subnets.

The format of the command is:

```console
$ docker swarm init --default-addr-pool <IP range in CIDR> [--default-addr-pool <IP range in CIDR> --default-addr-pool-mask-length <CIDR value>]
```

The command to create a default IP address pool with a /16 (class B) for the `10.20.0.0` network looks like this:

```console
$ docker swarm init --default-addr-pool 10.20.0.0/16
```

The command to create a default IP address pool with a `/16` (class B) for the `10.20.0.0` and `10.30.0.0` networks, and to 
create a subnet mask of `/26` for each network looks like this:

```console
$ docker swarm init --default-addr-pool 10.20.0.0/16 --default-addr-pool 10.30.0.0/16 --default-addr-pool-mask-length 26
```

In this example, `docker network create -d overlay net1` will result in `10.20.0.0/26` as the allocated subnet for `net1`, 
and `docker network create -d overlay net2` will result in `10.20.0.64/26` as the allocated subnet for `net2`. This continues until 
all the subnets are exhausted. 

Refer to the following pages for more information:
- [Swarm networking](networking.md) for more information about the default address pool usage
- `docker swarm init` [CLI reference](/reference/cli/docker/swarm/init/) for more detail on the `--default-addr-pool` flag.

### Configure the advertise address

Manager nodes use an advertise address to allow other nodes in the swarm access
to the Swarmkit API and overlay networking. The other nodes on the swarm must be
able to access the manager node on its advertise address.

If you don't specify an advertise address, Docker checks if the system has a
single IP address. If so, Docker uses the IP address with the listening port
`2377` by default. If the system has multiple IP addresses, you must specify the
correct `--advertise-addr` to enable inter-manager communication and overlay
networking:

```console
$ docker swarm init --advertise-addr <MANAGER-IP>
```

You must also specify the `--advertise-addr` if the address where other nodes
reach the first manager node is not the same address the manager sees as its
own. For instance, in a cloud setup that spans different regions, hosts have
both internal addresses for access within the region and external addresses that
you use for access from outside that region. In this case, specify the external
address with `--advertise-addr` so that the node can propagate that information
to other nodes that subsequently connect to it.

Refer to the `docker swarm init` [CLI reference](/reference/cli/docker/swarm/init/)
for more detail on the advertise address.

### View the join command or update a swarm join token

Nodes require a secret token to join the swarm. The token for worker nodes is
different from the token for manager nodes. Nodes only use the join-token at the
moment they join the swarm. Rotating the join token after a node has already
joined a swarm does not affect the node's swarm membership. Token rotation
ensures an old token cannot be used by any new nodes attempting to join the
swarm.

To retrieve the join command including the join token for worker nodes, run:

```console
$ docker swarm join-token worker

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
    192.168.99.100:2377

This node joined a swarm as a worker.
```

To view the join command and token for manager nodes, run:

```console
$ docker swarm join-token manager

To add a manager to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-59egwe8qangbzbqb3ryawxzk3jn97ifahlsrw01yar60pmkr90-bdjfnkcflhooyafetgjod97sz \
    192.168.99.100:2377
```

Pass the `--quiet` flag to print only the token:

```console
$ docker swarm join-token --quiet worker

SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c
```

Be careful with the join tokens because they are the secrets necessary to join
the swarm. In particular, checking a secret into version control is a bad
practice because it would allow anyone with access to the application source
code to add new nodes to the swarm. Manager tokens are especially sensitive
because they allow a new manager node to join and gain control over the whole
swarm.

We recommend that you rotate the join tokens in the following circumstances:

* If a token was checked-in by accident into a version control system, group
chat or accidentally printed to your logs.
* If you suspect a node has been compromised.
* If you wish to guarantee that no new nodes can join the swarm.

Additionally, it is a best practice to implement a regular rotation schedule for
any secret including swarm join tokens. We recommend that you rotate your tokens
at least every 6 months.

Run `swarm join-token --rotate` to invalidate the old token and generate a new
token. Specify whether you want to rotate the token for `worker` or `manager`
nodes:

```console
$ docker swarm join-token  --rotate worker

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-2kscvs0zuymrsc9t0ocyy1rdns9dhaodvpl639j2bqx55uptag-ebmn5u927reawo27s3azntd44 \
    192.168.99.100:2377
```

## Learn more

* [Join nodes to a swarm](join-nodes.md)
* `swarm init` [command line reference](/reference/cli/docker/swarm/init/)
* [Swarm mode tutorial](swarm-tutorial/index.md)


---

# Getting started with Swarm mode

*Sección: Engine*

This tutorial introduces you to the features of Docker Engine Swarm mode. You
may want to familiarize yourself with the [key concepts](../key-concepts.md)
before you begin.

The tutorial guides you through:

* Initializing a cluster of Docker Engines in swarm mode
* Adding nodes to the swarm
* Deploying application services to the swarm
* Managing the swarm once you have everything running

This tutorial uses Docker Engine CLI commands entered on the command line of a
terminal window.

If you are brand new to Docker, see [About Docker Engine](../../index.md).

## Set up

To run this tutorial, you need:

- [Set up](#set-up)
  - [Three networked host machines](#three-networked-host-machines)
    - [Install Docker Engine on Linux machines](#install-docker-engine-on-linux-machines)
  - [The IP address of the manager machine](#the-ip-address-of-the-manager-machine)
  - [Open protocols and ports between the hosts](#open-protocols-and-ports-between-the-hosts)
- [Next steps](#next-steps)

### Three networked host machines

This tutorial requires three Linux hosts which have Docker installed and can
communicate over a network. These can be physical machines, virtual machines,
Amazon EC2 instances, or hosted in some other way.

One of these machines is a manager (called `manager1`) and two of them are
workers (`worker1` and `worker2`).

> [!NOTE]
>
> You can follow many of the tutorial steps to test single-node swarm as well, in which case you need only one host. Multi-node commands do not work, but you can initialize a swarm, create services, and scale them.

#### Install Docker Engine on Linux machines

If you are using Linux based physical computers or cloud-provided computers as
hosts, simply follow the [Linux install instructions](../../install/index.md)
for your platform. Spin up the three machines, and you are ready. You can test both
single-node and multi-node swarm scenarios on Linux machines.

### The IP address of the manager machine

The IP address must be assigned to a network interface available to the host
operating system. All nodes in the swarm need to connect to the manager at
the IP address.

Because other nodes contact the manager node on its IP address, you should use a
fixed IP address.

You can run `ip addr` on Linux, or `ifconfig` on macOS, to see a list of the
available network interfaces.

The tutorial uses `manager1` : `192.168.99.100`.

### Open protocols and ports between the hosts

The following ports must be available. On some systems, these ports are open by default.

* Port `2377` TCP for communication with and between manager nodes
* Port `7946` TCP/UDP for overlay network node discovery
* Port `4789` UDP (configurable) for overlay network traffic

If you plan on creating an overlay network with encryption (`--opt encrypted`),
you also need to ensure IP protocol 50 (IPSec ESP) traffic is allowed.

Port `4789` is the default value for the Swarm data path port, also known as the VXLAN port.
It is important to prevent any untrusted traffic from reaching this port, as VXLAN does not
provide authentication. This port should only be opened to a trusted network, and never at a
perimeter firewall.

If the network which Swarm traffic traverses is not fully trusted, it is strongly suggested that
encrypted overlay networks be used. If encrypted overlay networks are in exclusive use, some
additional hardening is suggested:

* [Customize the default ingress network](../networking.md) to use encryption
* Only accept encrypted packets on the Data Path Port:

```bash
# Example iptables rule (order and other tools may require customization)
iptables -I INPUT -m udp --dport 4789 -m policy --dir in --pol none -j DROP
```

## Next steps

Next, you'll create a swarm. 

{{< button text="Create a swarm" url="create-swarm.md" >}}


---

# Add nodes to the swarm

*Sección: Engine*

Once you've [created a swarm](create-swarm.md) with a manager node, you're ready
to add worker nodes.

1.  Open a terminal and ssh into the machine where you want to run a worker node.
    This tutorial uses the name `worker1`.

2.  Run the command produced by the `docker swarm init` output from the
    [Create a swarm](create-swarm.md) tutorial step to create a worker node
    joined to the existing swarm:

    ```console
    $ docker swarm join \
      --token  SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
      192.168.99.100:2377

    This node joined a swarm as a worker.
    ```

    If you don't have the command available, you can run the following command
    on a manager node to retrieve the join command for a worker:

    ```console
    $ docker swarm join-token worker

    To add a worker to this swarm, run the following command:

        docker swarm join \
        --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
        192.168.99.100:2377
    ```

3.  Open a terminal and ssh into the machine where you want to run a second
    worker node. This tutorial uses the name `worker2`.

4.  Run the command produced by the `docker swarm init` output from the
    [Create a swarm](create-swarm.md) tutorial step to create a second worker
    node joined to the existing swarm:

    ```console
    $ docker swarm join \
      --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
      192.168.99.100:2377

    This node joined a swarm as a worker.
    ```

5.  Open a terminal and ssh into the machine where the manager node runs and
    run the `docker node ls` command to see the worker nodes:

    ```console
    $ docker node ls
    ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
    03g1y59jwfg7cf99w4lt0f662    worker2   Ready   Active
    9j68exjopxe7wfl6yuxml7a7j    worker1   Ready   Active
    dxn1zf6l61qsb1josjja83ngz *  manager1  Ready   Active        Leader
    ```

    The `MANAGER` column identifies the manager nodes in the swarm. The empty
    status in this column for `worker1` and `worker2` identifies them as worker nodes.

    Swarm management commands like `docker node ls` only work on manager nodes.


## What's next?

Now your swarm consists of a manager and two worker nodes. Next, you'll deploy a service.

{{< button text="Deploy a service" url="deploy-service.md" >}}


---

# Create a swarm

*Sección: Engine*

After you complete the [tutorial setup](../../../reference/api/ai-governance/index.md) steps, you're ready
to create a swarm. Make sure the Docker Engine daemon is started on the host
machines.

1.  Open a terminal and ssh into the machine where you want to run your manager
    node. This tutorial uses a machine named `manager1`. 

2.  Run the following command to create a new swarm:

    ```console
    $ docker swarm init --advertise-addr <MANAGER-IP>
    ```

    In the tutorial, the following command creates a swarm on the `manager1`
    machine:

    ```console
    $ docker swarm init --advertise-addr 192.168.99.100
    Swarm initialized: current node (dxn1zf6l61qsb1josjja83ngz) is now a manager.

    To add a worker to this swarm, run the following command:

        docker swarm join \
        --token SWMTKN-1-49nj1cmql0jkz5s954yi3oex3nedyz0fb0xx14ie39trti4wxv-8vxv8rssmk743ojnwacrr2e7c \
        192.168.99.100:2377

    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
    ```

    The `--advertise-addr` flag configures the manager node to publish its
    address as `192.168.99.100`. The other nodes in the swarm must be able
    to access the manager at the IP address.

    The output includes the commands to join new nodes to the swarm. Nodes will
    join as managers or workers depending on the value for the `--token`
    flag.

3.  Run `docker info` to view the current state of the swarm:

    ```console
    $ docker info

    Containers: 2
    Running: 0
    Paused: 0
    Stopped: 2
      ...snip...
    Swarm: active
      NodeID: dxn1zf6l61qsb1josjja83ngz
      Is Manager: true
      Managers: 1
      Nodes: 1
      ...snip...
    ```

4.  Run the `docker node ls` command to view information about nodes:

    ```console
    $ docker node ls

    ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
    dxn1zf6l61qsb1josjja83ngz *  manager1  Ready   Active        Leader

    ```

    The `*` next to the node ID indicates that you're currently connected on
    this node.

    Docker Engine Swarm mode automatically names the node with the machine host
    name. The tutorial covers other columns in later steps.

## Next steps

Next, you'll add two more nodes to the cluster. 

{{< button text="Add two more nodes" url="add-nodes.md" >}}


---

# Delete the service running on the swarm

*Sección: Engine*

The remaining steps in the tutorial don't use the `helloworld` service, so now
you can delete the service from the swarm.

1.  If you haven't already, open a terminal and ssh into the machine where you
    run your manager node. For example, the tutorial uses a machine named
    `manager1`.

2.  Run `docker service rm helloworld` to remove the `helloworld` service.

    ```console
    $ docker service rm helloworld

    helloworld
    ```

3.  Run `docker service inspect <SERVICE-ID>` to verify that the swarm manager
    removed the service. The CLI returns a message that the service is not
    found:

    ```console
    $ docker service inspect helloworld
    []
    Status: Error: no such service: helloworld, Code: 1
    ```

4.  Even though the service no longer exists, the task containers take a few
    seconds to clean up. You can use `docker ps` on the nodes to verify when the
    tasks have been removed.

    ```console
    $ docker ps

    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS     NAMES
    db1651f50347        alpine:latest       "ping docker.com"        44 minutes ago      Up 46 seconds                 helloworld.5.9lkmos2beppihw95vdwxy1j3w
    43bf6e532a92        alpine:latest       "ping docker.com"        44 minutes ago      Up 46 seconds                 helloworld.3.a71i8rp6fua79ad43ycocl4t2
    5a0fb65d8fa7        alpine:latest       "ping docker.com"        44 minutes ago      Up 45 seconds                 helloworld.2.2jpgensh7d935qdc857pxulfr
    afb0ba67076f        alpine:latest       "ping docker.com"        44 minutes ago      Up 46 seconds                 helloworld.4.1c47o7tluz7drve4vkm2m5olx
    688172d3bfaa        alpine:latest       "ping docker.com"        45 minutes ago      Up About a minute             helloworld.1.74nbhb3fhud8jfrhigd7s29we

    $ docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS     NAMES

    ```

## Next steps

Next, you'll set up a new service and apply a rolling update.

{{< button text="Apply rolling updates" url="rolling-update.md" >}}


---

# Deploy a service to the swarm

*Sección: Engine*

After you [create a swarm](create-swarm.md), you can deploy a service to the
swarm. For this tutorial, you also [added worker nodes](add-nodes.md), but that
is not a requirement to deploy a service.

1.  Open a terminal and ssh into the machine where you run your manager node.
    For example, the tutorial uses a machine named `manager1`.

2.  Run the following command:

    ```console
    $ docker service create --replicas 1 --name helloworld alpine ping docker.com

    9uk4639qpg7npwf3fn2aasksr
    ```

    * The `docker service create` command creates the service.
    * The `--name` flag names the service `helloworld`.
    * The `--replicas` flag specifies the desired state of 1 running instance.
    * The arguments `alpine ping docker.com` define the service as an Alpine
    Linux container that executes the command `ping docker.com`.

3.  Run `docker service ls` to see the list of running services:

    ```console
    $ docker service ls

    ID            NAME        SCALE  IMAGE   COMMAND
    9uk4639qpg7n  helloworld  1/1    alpine  ping docker.com
    ```

## Next steps

Now you're ready to inspect the service.

{{< button text="Inspect the service" url="inspect-service.md" >}}


---

# Drain a node on the swarm

*Sección: Engine*

In earlier steps of the tutorial, all the nodes have been running with `Active`
availability. The swarm manager can assign tasks to any `Active` node, so up to
now all nodes have been available to receive tasks.

Sometimes, such as planned maintenance times, you need to set a node to `Drain`
availability. `Drain` availability  prevents a node from receiving new tasks
from the swarm manager. It also means the manager stops tasks running on the
node and launches replica tasks on a node with `Active` availability.

> [!IMPORTANT]: 
>
> Setting a node to `Drain` does not remove standalone containers from that node,
> such as those created with `docker run`, `docker compose up`, or the Docker Engine
> API. A node's status, including `Drain`, only affects the node's ability to schedule
> swarm service workloads.

1.  If you haven't already, open a terminal and ssh into the machine where you
    run your manager node. For example, the tutorial uses a machine named
    `manager1`.

2.  Verify that all your nodes are actively available.

    ```console
    $ docker node ls

    ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS
    1bcef6utixb0l0ca7gxuivsj0    worker2   Ready   Active
    38ciaotwjuritcdtn9npbnkuz    worker1   Ready   Active
    e216jshn25ckzbvmwlnh5jr3g *  manager1  Ready   Active        Leader
    ```

3.  If you aren't still running the `redis` service from the
    [rolling update](rolling-update.md) tutorial, start it now:

    ```console
    $ docker service create --replicas 3 --name redis --update-delay 10s redis:7.4.0

    c5uo6kdmzpon37mgj9mwglcfw
    ```

4.  Run `docker service ps redis` to see how the swarm manager assigned the
tasks to different nodes:

    ```console
    $ docker service ps redis

    NAME                               IMAGE        NODE     DESIRED STATE  CURRENT STATE
    redis.1.7q92v0nr1hcgts2amcjyqg3pq  redis:7.4.0  manager1 Running        Running 26 seconds
    redis.2.7h2l8h3q3wqy5f66hlv9ddmi6  redis:7.4.0  worker1  Running        Running 26 seconds
    redis.3.9bg7cezvedmkgg6c8yzvbhwsd  redis:7.4.0  worker2  Running        Running 26 seconds
    ```

    In this case the swarm manager distributed one task to each node. You may
    see the tasks distributed differently among the nodes in your environment.

5.  Run `docker node update --availability drain <NODE-ID>` to drain a node that
had a task assigned to it:

    ```console
    $ docker node update --availability drain worker1

    worker1
    ```

6.  Inspect the node to check its availability:

    ```console
    $ docker node inspect --pretty worker1

    ID:			38ciaotwjuritcdtn9npbnkuz
    Hostname:		worker1
    Status:
     State:			Ready
     Availability:		Drain
    ...snip...
    ```

    The drained node shows `Drain` for `Availability`.

7.  Run `docker service ps redis` to see how the swarm manager updated the
task assignments for the `redis` service:

    ```console
    $ docker service ps redis

    NAME                                    IMAGE        NODE      DESIRED STATE  CURRENT STATE           ERROR
    redis.1.7q92v0nr1hcgts2amcjyqg3pq       redis:7.4.0  manager1  Running        Running 4 minutes
    redis.2.b4hovzed7id8irg1to42egue8       redis:7.4.0  worker2   Running        Running About a minute
     \_ redis.2.7h2l8h3q3wqy5f66hlv9ddmi6   redis:7.4.0  worker1   Shutdown       Shutdown 2 minutes ago
    redis.3.9bg7cezvedmkgg6c8yzvbhwsd       redis:7.4.0  worker2   Running        Running 4 minutes
    ```

    The swarm manager maintains the desired state by ending the task on a node
    with `Drain` availability and creating a new task on a node with `Active`
    availability.

8.  Run  `docker node update --availability active <NODE-ID>` to return the
drained node to an active state:

    ```console
    $ docker node update --availability active worker1

    worker1
    ```

9.  Inspect the node to see the updated state:

    ```console
    $ docker node inspect --pretty worker1

    ID:			38ciaotwjuritcdtn9npbnkuz
    Hostname:		worker1
    Status:
     State:			Ready
     Availability:		Active
    ...snip...
    ```

    When you set the node back to `Active` availability, it can receive new tasks:

    * during a service update to scale up
    * during a rolling update
    * when you set another node to `Drain` availability
    * when a task fails on another active node

## Next steps

Next, you'll learn how to use a Swarm mode routing mesh

{{< button text="Use a Swarm mode routing mesh" url="../ingress.md" >}}


---

# Inspect a service on the swarm

*Sección: Engine*

When you have [deployed a service](deploy-service.md) to your swarm, you can use
the Docker CLI to see details about the service running in the swarm.

1.  If you haven't already, open a terminal and ssh into the machine where you
    run your manager node. For example, the tutorial uses a machine named
    `manager1`.

2.  Run `docker service inspect --pretty <SERVICE-ID>` to display the details
    about a service in an easily readable format.

    To see the details on the `helloworld` service:

    ```console
    [manager1]$ docker service inspect --pretty helloworld

    ID:		9uk4639qpg7npwf3fn2aasksr
    Name:		helloworld
    Service Mode:	REPLICATED
     Replicas:		1
    Placement:
    UpdateConfig:
     Parallelism:	1
    ContainerSpec:
     Image:		alpine
     Args:	ping docker.com
    Resources:
    Endpoint Mode:  vip
    ```

    > [!TIP]
    >
    > To return the service details in json format, run the same command
    without the `--pretty` flag.

    ```console
    [manager1]$ docker service inspect helloworld
    [
    {
        "ID": "9uk4639qpg7npwf3fn2aasksr",
        "Version": {
            "Index": 418
        },
        "CreatedAt": "2016-06-16T21:57:11.622222327Z",
        "UpdatedAt": "2016-06-16T21:57:11.622222327Z",
        "Spec": {
            "Name": "helloworld",
            "TaskTemplate": {
                "ContainerSpec": {
                    "Image": "alpine",
                    "Args": [
                        "ping",
                        "docker.com"
                    ]
                },
                "Resources": {
                    "Limits": {},
                    "Reservations": {}
                },
                "RestartPolicy": {
                    "Condition": "any",
                    "MaxAttempts": 0
                },
                "Placement": {}
            },
            "Mode": {
                "Replicated": {
                    "Replicas": 1
                }
            },
            "UpdateConfig": {
                "Parallelism": 1
            },
            "EndpointSpec": {
                "Mode": "vip"
            }
        },
        "Endpoint": {
            "Spec": {}
        }
    }
    ]
    ```

3.  Run `docker service ps <SERVICE-ID>` to see which nodes are running the
    service:

    ```console
    [manager1]$ docker service ps helloworld

    NAME                                    IMAGE   NODE     DESIRED STATE  CURRENT STATE           ERROR               PORTS
    helloworld.1.8p1vev3fq5zm0mi8g0as41w35  alpine  worker2  Running        Running 3 minutes
    ```

    In this case, the one instance of the `helloworld` service is running on the
    `worker2` node. You may see the service running on your manager node. By
    default, manager nodes in a swarm can execute tasks just like worker nodes.

    Swarm also shows you the `DESIRED STATE` and `CURRENT STATE` of the service
    task so you can see if tasks are running according to the service
    definition.

4.  Run `docker ps` on the node where the task is running to see details about
    the container for the task.

    > [!TIP]
    >
    > If `helloworld` is running on a node other than your manager node,
    you must ssh to that node.

    ```console
    [worker2]$ docker ps

    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    e609dde94e47        alpine:latest       "ping docker.com"   3 minutes ago       Up 3 minutes                            helloworld.1.8p1vev3fq5zm0mi8g0as41w35
    ```

## Next steps

Next, you'll change the scale for the service running in the swarm.

{{< button text="Change the scale" url="scale-service.md" >}}


---

# Apply rolling updates to a service

*Sección: Engine*

In a previous step of the tutorial, you [scaled](scale-service.md) the number of
instances of a service. In this part of the tutorial, you deploy a service based
on the Redis 7.4.0 container tag. Then you upgrade the service to use the
Redis 7.4.1 container image using rolling updates.

1.  If you haven't already, open a terminal and ssh into the machine where you
    run your manager node. For example, the tutorial uses a machine named
    `manager1`.

2.  Deploy your Redis tag to the swarm and configure the swarm with a 10 second
    update delay. Note that the following example shows an older Redis tag:

    ```console
    $ docker service create \
      --replicas 3 \
      --name redis \
      --update-delay 10s \
      redis:7.4.0

    0u6a4s31ybk7yw2wyvtikmu50
    ```

    You configure the rolling update policy at service deployment time.

    The `--update-delay` flag configures the time delay between updates to a
    service task or sets of tasks. You can describe the time `T` as a
    combination of the number of seconds `Ts`, minutes `Tm`, or hours `Th`. So
    `10m30s` indicates a 10 minute 30 second delay.

    By default the scheduler updates 1 task at a time. You can pass the
    `--update-parallelism` flag to configure the maximum number of service tasks
    that the scheduler updates simultaneously.

    By default, when an update to an individual task returns a state of
    `RUNNING`, the scheduler schedules another task to update until all tasks
    are updated. If at any time during an update a task returns `FAILED`, the
    scheduler pauses the update. You can control the behavior using the
    `--update-failure-action` flag for `docker service create` or
    `docker service update`.

3.  Inspect the `redis` service:

    ```console
    $ docker service inspect --pretty redis

    ID:             0u6a4s31ybk7yw2wyvtikmu50
    Name:           redis
    Service Mode:   Replicated
     Replicas:      3
    Placement:
     Strategy:	    Spread
    UpdateConfig:
     Parallelism:   1
     Delay:         10s
    ContainerSpec:
     Image:         redis:7.4.0
    Resources:
    Endpoint Mode:  vip
    ```

4.  Now you can update the container image for `redis`. The swarm  manager
    applies the update to nodes according to the `UpdateConfig` policy:

    ```console
    $ docker service update --image redis:7.4.1 redis
    redis
    ```

    The scheduler applies rolling updates as follows by default:

    * Stop the first task.
    * Schedule update for the stopped task.
    * Start the container for the updated task.
    * If the update to a task returns `RUNNING`, wait for the
      specified delay period then start the next task.
    * If, at any time during the update, a task returns `FAILED`, pause the
      update.

5.  Run `docker service inspect --pretty redis` to see the new image in the
    desired state:

    ```console
    $ docker service inspect --pretty redis

    ID:             0u6a4s31ybk7yw2wyvtikmu50
    Name:           redis
    Service Mode:   Replicated
     Replicas:      3
    Placement:
     Strategy:	    Spread
    UpdateConfig:
     Parallelism:   1
     Delay:         10s
    ContainerSpec:
     Image:         redis:7.4.1
    Resources:
    Endpoint Mode:  vip
    ```

    The output of `service inspect` shows if your update paused due to failure:

    ```console
    $ docker service inspect --pretty redis

    ID:             0u6a4s31ybk7yw2wyvtikmu50
    Name:           redis
    ...snip...
    Update status:
     State:      paused
     Started:    11 seconds ago
     Message:    update paused due to failure or early termination of task 9p7ith557h8ndf0ui9s0q951b
    ...snip...
    ```

    To restart a paused update run `docker service update <SERVICE-ID>`. For example:

    ```console
    $ docker service update redis
    ```

    To avoid repeating certain update failures, you may need to reconfigure the
    service by passing flags to `docker service update`.

6.  Run `docker service ps <SERVICE-ID>` to watch the rolling update:

    ```console
    $ docker service ps redis

    NAME                                   IMAGE        NODE       DESIRED STATE  CURRENT STATE            ERROR
    redis.1.dos1zffgeofhagnve8w864fco      redis:7.4.1  worker1    Running        Running 37 seconds
     \_ redis.1.88rdo6pa52ki8oqx6dogf04fh  redis:7.4.0  worker2    Shutdown       Shutdown 56 seconds ago
    redis.2.9l3i4j85517skba5o7tn5m8g0      redis:7.4.1  worker2    Running        Running About a minute
     \_ redis.2.66k185wilg8ele7ntu8f6nj6i  redis:7.4.0  worker1    Shutdown       Shutdown 2 minutes ago
    redis.3.egiuiqpzrdbxks3wxgn8qib1g      redis:7.4.1  worker1    Running        Running 48 seconds
     \_ redis.3.ctzktfddb2tepkr45qcmqln04  redis:7.4.0  mmanager1  Shutdown       Shutdown 2 minutes ago
    ```

    Before Swarm updates all of the tasks, you can see that some are running
    `redis:7.4.0` while others are running `redis:7.4.1`. The output above shows
    the state once the rolling updates are done.

## Next steps

Next, you'll learn how to drain a node in the swarm.

{{< button text="Drain a node" url="drain-node.md" >}}


---

# Scale the service in the swarm

*Sección: Engine*

Once you have [deployed a service](deploy-service.md) to a swarm, you are ready
to use the Docker CLI to scale the number of containers in
the service. Containers running in a service are called tasks.

1.  If you haven't already, open a terminal and ssh into the machine where you
    run your manager node. For example, the tutorial uses a machine named
    `manager1`.

2.  Run the following command to change the desired state of the
    service running in the swarm:

    ```console
    $ docker service scale <SERVICE-ID>=<NUMBER-OF-TASKS>
    ```

    For example:

    ```console
    $ docker service scale helloworld=5

    helloworld scaled to 5
    ```

3.  Run `docker service ps <SERVICE-ID>` to see the updated task list:

    ```console
    $ docker service ps helloworld

    NAME                                    IMAGE   NODE      DESIRED STATE  CURRENT STATE
    helloworld.1.8p1vev3fq5zm0mi8g0as41w35  alpine  worker2   Running        Running 7 minutes
    helloworld.2.c7a7tcdq5s0uk3qr88mf8xco6  alpine  worker1   Running        Running 24 seconds
    helloworld.3.6crl09vdcalvtfehfh69ogfb1  alpine  worker1   Running        Running 24 seconds
    helloworld.4.auky6trawmdlcne8ad8phb0f1  alpine  manager1  Running        Running 24 seconds
    helloworld.5.ba19kca06l18zujfwxyc5lkyn  alpine  worker2   Running        Running 24 seconds
    ```

    You can see that swarm has created 4 new tasks to scale to a total of 5
    running instances of Alpine Linux. The tasks are distributed between the
    three nodes of the swarm. One is running on `manager1`.

4.  Run `docker ps` to see the containers running on the node where you're
    connected. The following example shows the tasks running on `manager1`:

    ```console
    $ docker ps

    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    528d68040f95        alpine:latest       "ping docker.com"   About a minute ago   Up About a minute                       helloworld.4.auky6trawmdlcne8ad8phb0f1
    ```

    If you want to see the containers running on other nodes, ssh into
    those nodes and run the `docker ps` command.

## Next steps

At this point in the tutorial, you're finished with the `helloworld` service. Next, you'll delete the service

{{< button text="Delete the service" url="delete-service.md" >}}


---

# Lock your swarm to protect its encryption key

*Sección: Engine*

The Raft logs used by swarm managers are encrypted on disk by default. This at-rest
encryption protects your service's configuration and data from attackers who gain
access to the encrypted Raft logs. One of the reasons this feature was introduced
was in support of the [Docker secrets](secrets.md) feature.

When Docker restarts, both the TLS key used to encrypt communication among swarm
nodes and the key used to encrypt and decrypt Raft logs on disk are loaded
into each manager node's memory. Docker has the ability to protect the mutual TLS
encryption key and the key used to encrypt and decrypt Raft logs at rest, by
allowing you to take ownership of these keys and to require manual unlocking of
your managers. This feature is called autolock.

When Docker restarts, you must
[unlock the swarm](#unlock-a-swarm) first, using a
key encryption key generated by Docker when the swarm was locked. You can
rotate this key encryption key at any time.

> [!NOTE]
>
> You don't need to unlock the swarm when a new node joins the swarm,
> because the key is propagated to it over mutual TLS.

## Initialize a swarm with autolocking enabled

When you initialize a new swarm, you can use the `--autolock` flag to
enable autolocking of swarm manager nodes when Docker restarts.

```console
$ docker swarm init --autolock

Swarm initialized: current node (k1q27tfyx9rncpixhk69sa61v) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-0j52ln6hxjpxk2wgk917abcnxywj3xed0y8vi1e5m9t3uttrtu-7bnxvvlz2mrcpfonjuztmtts9 \
    172.31.46.109:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

To unlock a swarm manager after it restarts, run the `docker swarm unlock`
command and provide the following key:

    SWMKEY-1-WuYH/IX284+lRcXuoVf38viIDK3HJEKY13MIHX+tTt8
```

Store the key in a safe place, such as in a password manager.

When Docker restarts, you need to [unlock the swarm](#unlock-a-swarm). A locked
swarm causes an error like the following when you try to start or restart a
service:

```console
$ sudo service docker restart

$ docker service ls

Error response from daemon: Swarm is encrypted and needs to be unlocked before it can be used. Use "docker swarm unlock" to unlock it.
```

## Enable or disable autolock on an existing swarm

To enable autolock on an existing swarm, set the `autolock` flag to `true`.

```console
$ docker swarm update --autolock=true

Swarm updated.
To unlock a swarm manager after it restarts, run the `docker swarm unlock`
command and provide the following key:

    SWMKEY-1-+MrE8NgAyKj5r3NcR4FiQMdgu+7W72urH0EZeSmP/0Y

Please remember to store this key in a password manager, since without it you
will not be able to restart the manager.
```

To disable autolock, set `--autolock` to `false`. The mutual TLS key and the
encryption key used to read and write Raft logs are stored unencrypted on
disk. There is a trade-off between the risk of storing the encryption key
unencrypted at rest and the convenience of restarting a swarm without
needing to unlock each manager.

```console
$ docker swarm update --autolock=false
```

Keep the unlock key around for a short time after disabling autolocking, in case
a manager goes down while it is still configured to lock using the old key.

## Unlock a swarm

To unlock a locked swarm, use `docker swarm unlock`.

```console
$ docker swarm unlock

Please enter unlock key:
```

Enter the encryption key that was generated and shown in the command output when
you locked the swarm or rotated the key, and the swarm unlocks.

## View the current unlock key for a running swarm

Consider a situation where your swarm is running as expected, then a manager
node becomes unavailable. You troubleshoot the problem and bring the physical
node back online, but you need to unlock the manager by providing the unlock
key to read the encrypted credentials and Raft logs.

If the key has not been rotated since the node left the swarm, and you have a
quorum of functional manager nodes in the swarm, you can view the current unlock
key using `docker swarm unlock-key` without any arguments.

```console
$ docker swarm unlock-key

To unlock a swarm manager after it restarts, run the `docker swarm unlock`
command and provide the following key:

    SWMKEY-1-8jDgbUNlJtUe5P/lcr9IXGVxqZpZUXPzd+qzcGp4ZYA

Please remember to store this key in a password manager, since without it you
will not be able to restart the manager.
```

If the key was rotated after the swarm node became unavailable and you do not
have a record of the previous key, you may need to force the manager to leave
the swarm and join it back to the swarm as a new manager.

## Rotate the unlock key

You should rotate the locked swarm's unlock key on a regular schedule.

```console
$ docker swarm unlock-key --rotate

Successfully rotated manager unlock key.

To unlock a swarm manager after it restarts, run the `docker swarm unlock`
command and provide the following key:

    SWMKEY-1-8jDgbUNlJtUe5P/lcr9IXGVxqZpZUXPzd+qzcGp4ZYA

Please remember to store this key in a password manager, since without it you
will not be able to restart the manager.
```

> [!WARNING]
>
> When you rotate the unlock key, keep a record of the old key
> around for a few minutes, so that if a manager goes down before it gets the new
> key, it may still be unlocked with the old one.


---

# Deploy Docker Desktop

*Sección: Enterprise*

Docker Desktop supports scalable deployment options tailored for enterprise IT environments. Whether you're rolling out Docker across hundreds of developer workstations or enforcing consistent configuration through MDM solutions like Intune or Jamf, this section provides everything you need to install, configure, and manage Docker Desktop in a secure, repeatable way. Learn how to use MSI and PKG installers, configure default settings, control updates, and ensure compliance with your organization's policies—across Windows, macOS, and Linux systems.

{{< grid >}}


---

# Dev box

*Sección: Enterprise*

Docker Desktop is available as a pre-configured image in the Microsoft Azure Marketplace for use with Microsoft Dev Box, allowing developers to quickly set up consistent development environments in the cloud.

Microsoft Dev Box provides cloud-based, pre-configured developer workstations that allow you to code, build, and test applications without configuring a local development environment. The Docker Desktop image for Microsoft Dev Box comes with Docker Desktop and its dependencies pre-installed, giving you a ready-to-use containerized development environment.

## Key benefits

- Docker Desktop, WSL2, and dependencies pre-installed
- Identical environment for every team member
- More compute and storage than a typical local machine
- Session state persists between uses
- Works with your existing Docker subscription

## Setup

### Prerequisites

- An Azure subscription
- Access to Microsoft Dev Box
- A Docker subscription (Pro, Team, or Business). You can use Docker Desktop in Microsoft Dev Box with any of the following subscription options:
  - An existing or new Docker subscription
  - A new Docker subscription purchased through Azure Marketplace
  - A Docker Business subscription with SSO configured for your organization

### Set up Docker Desktop in Dev Box

1. Navigate to the [Docker Desktop for Microsoft Dev Box](https://azuremarketplace.microsoft.com/en-us/marketplace/apps/dockerinc1694120899427.devbox_azuremachine?tab=Overview) listing in Azure Marketplace.
2. Select **Get It Now** to add the virtual machine image to your subscription.
3. Follow the Azure workflow to complete the setup.
4. Use the image to create VMs, assign to Dev Centers, or create Dev Box Pools according to your organization's setup.

### Activate Docker Desktop

Once your Dev Box is provisioned with the Docker Desktop image:

1. Start your Dev Box instance.
2. Launch Docker Desktop.
3. Sign in with your Docker ID.

## Support

For issues related to:

- Docker Desktop configuration, usage, or licensing: Create a support ticket through [Docker Support](https://hub.docker.com/support).
- Dev Box creation, Azure portal configuration, or networking: Contact Azure Support.

## Limitations

- Microsoft Dev Box is only available on Windows 10 and 11 (Linux VMs are not supported).
- Performance may vary based on your Dev Box configuration and network conditions.


---

# Enterprise deployment FAQs

*Sección: Enterprise*

## MSI

Common questions about installing Docker Desktop using the MSI installer.

### What happens to user data if they have an older Docker Desktop installation (i.e. `.exe`)?

Users must [uninstall](../../desktop/uninstall.md) older `.exe` installations before using the new MSI version. The `.exe` installer includes a `-keep-data` flag that removes Docker Desktop while preserving underlying resources such as the container VMs:

```powershell
# For all-user installations
& 'C:\Program Files\Docker\Docker\Docker Desktop Installer.exe' uninstall -keep-data

# For per-user installations
& '%LOCALAPPDATA%\Programs\DockerDesktop\Docker Desktop Installer.exe' uninstall -keep-data

```

### What happens if the user's machine has an older `.exe` installation?

The MSI installer detects older `.exe` installations and blocks the installation until the previous version is uninstalled. It prompts the user to uninstall their current/old version first, before retrying to install the MSI version.

### My installation failed, how do I find out what happened?

MSI installations may fail silently, offering little diagnostic feedback.

To debug a failed installation, run the install again with verbose logging enabled:

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log"
```

After the installation has failed, open the log file and search for occurrences of `value 3`. This is the exit code Windows Installer outputs when it has failed. Just above the line, you will find the reason for the failure.

### Why does the installer prompt for a reboot at the end of every fresh installation?

The installer prompts for a reboot because it assumes that changes have been made to the system that require a reboot to finish their configuration.

For example, if you select the WSL engine, the installer adds the required Windows features. After these features are installed, the system reboots to complete configurations so the WSL engine is functional.

You can suppress reboots by using the `/norestart` option when launching the installer from the command line:

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log" /norestart
```

### Why isn't the `docker-users` group populated when the MSI is installed with Intune or another MDM solution?

It's common for MDM solutions to install applications in the context of the system account. This means that the `docker-users` group isn't populated with the user's account, as the system account doesn't have access to the user's context.

As an example, you can reproduce this by running the installer with `psexec` in an elevated command prompt:

```powershell
psexec -i -s msiexec /i "DockerDesktop.msi"
```
The installation should complete successfully, but the `docker-users` group won't be populated.

As a workaround, you can create a script that runs in the context of the user account.

The script would be responsible for ensuring the `docker-users` group exists and populating it with the correct user.

> [!WARNING]
>
> Membership in `docker-users` grants access to the Docker daemon socket, which is equivalent to granting administrative privileges on the host. Only add users who require access to Windows containers or Hyper-V VM management. For Linux containers using the WSL 2 backend, this group membership is not required. See [Protect the Docker daemon socket](../../engine/security/protect-access.md) for further information.

Here's an example script that creates the `docker-users` group if needed and adds the current user to it (requirements may vary depending on environment):

```powershell
$Group = "docker-users"
$CurrentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name

# Create the group if it doesn't exist
if (-not (Get-LocalGroup -Name $Group -ErrorAction SilentlyContinue)) {
    New-LocalGroup -Name $Group
}

# Add the user to the group
Add-LocalGroupMember -Group $Group -Member $CurrentUser
```

> [!NOTE]
>
> After adding a new user to the `docker-users` group, the user must sign out and then sign back in for the changes to take effect.

## MDM

Common questions about deploying Docker Desktop using mobile device management
(MDM) tools such as Jamf, Intune, or Workspace ONE.

### Why doesn't my MDM tool apply all Docker Desktop configuration settings at once?

Some MDM tools, such as Workspace ONE, may not support applying multiple
configuration settings in a single XML file. In these cases, you may need to
deploy each setting in a separate XML file.

Refer to your MDM provider's documentation for specific deployment
requirements or limitations.


---

# Install Docker Desktop from the Microsoft Store on Windows

*Sección: Enterprise*

You can deploy Docker Desktop for Windows through the [Microsoft app store](https://apps.microsoft.com/detail/xp8cbj40xlbwkx?hl=en-GB&gl=GB).

The Microsoft Store version of Docker Desktop provides the same functionality as the standard installer but has a different update behavior depending on whether your developers install it themselves or if installation is handled by an MDM tool such as Intune. This is described in the following section. 

Choose the installation method that best aligns with your environment's requirements and management practices.

## Update behavior

### Developer-managed installations

For developers who install Docker Desktop directly:

- The Microsoft Store does not automatically update Win32 apps like Docker Desktop for most users.
- Only a subset of users (approximately 20%) may receive update notifications on the Microsoft Store page.
- Most users must manually check for and apply updates within the Store.

### Intune-managed installations

In environments managed with Intune:
- Intune checks for updates approximately every 8 hours.
- When a new version is detected, Intune triggers a `winget` upgrade.  
- If appropriate policies are configured, updates can occur automatically without user intervention. 
- Updates are handled by Intune's management infrastructure rather than the Microsoft Store itself.

## WSL considerations

Docker Desktop for Windows integrates closely with WSL. When updating Docker Desktop installed from the Microsoft Store:
- Make sure you have quit Docker Desktop and that it is no longer running so updates can complete successfully
- In some environments, virtual hard disk (VHDX) file locks may prevent the update from completing.

## Recommendations for Intune management

If using Intune to manage Docker Desktop for Windows:
- Ensure your Intune policies are configured to handle application updates
- Be aware that the update process uses WinGet APIs rather than direct Store mechanisms
- Consider testing the update process in a controlled environment to verify proper functionality


---

# MSI installer

*Sección: Enterprise*

{{< summary-bar feature_name="MSI installer" >}}

The MSI package supports various MDM (Mobile Device Management) solutions, making it ideal for bulk installations and eliminating the need for manual setups by individual users. With this package, IT administrators can ensure standardized, policy-driven installations of Docker Desktop, enhancing efficiency and software management across their organizations.

## Install interactively

1. In [Docker Home](http://app.docker.com), choose your organization.
2. Select **Docker Desktop**, then **Deploy**.
3. From the **Windows OS** tab, select the **Download MSI installer** button.
4. Once downloaded, double-click `Docker Desktop Installer.msi` to run the installer.
5. After accepting the license agreement, choose the install location. By default, Docker Desktop is installed at `C:\Program Files\Docker\Docker`(all-user installations) or `%LOCALAPPDATA%\Programs\DockerDesktop` (per-user installations)
6. Configure the Docker Desktop installation. You can:
   - Create a desktop shortcut

   - Set the Docker Desktop service startup type to automatic

   - Disable Windows Container usage

   - Select the Docker Desktop backend: WSL or Hyper-V. If only one is supported by your system, you won't be able to choose.

7. Follow the instructions on the installation wizard to authorize the installer and proceed with the install.
8. When the installation is successful, select **Finish** to complete the installation process.

If your administrator account is different from your user account, you must add the user to the **docker-users** group to access features that require higher privileges, such as creating and managing the Hyper-V VM, or using Windows containers:

1. Run **Computer Management** as an **administrator**.
2. Navigate to **Local Users and Groups** > **Groups** > **docker-users**.
3. Right-click to add the user to the group.
4. Sign out and sign back in for the changes to take effect.

> [!NOTE]
>
> When installing Docker Desktop with the MSI, in-app updates are automatically disabled by default. This ensures organizations can maintain version consistency and prevent unapproved updates.
> Starting with Docker Desktop version 4.60 and later, in-app updates from an MSI installation can be enabled by changing the `disableUpdate` setting to `false` through [Settings Management](../security/hardened-desktop/settings-management/).
>
> Docker Desktop notifies you when an update is available. To update Docker Desktop, download the latest installer from Docker Home. Navigate to the **Deploy** page.
>
> To keep up to date with new releases, check the [release notes](../../desktop/release-notes.md) page.

## Install from the command line

This section covers command line installations of Docker Desktop using PowerShell. It provides common installation commands that you can run. You can also add additional arguments which are outlined in [configuration options](#configuration-options).

When installing Docker Desktop, you can choose between interactive or non-interactive installations.

Interactive installations, without specifying `/quiet` or `/qn`, display the user interface and let you select your own properties.

When installing via the user interface it's possible to:

- Choose the destination folder
- Create a desktop shortcut
- Configure the Docker Desktop service startup type
- Disable Windows Containers
- Choose between the WSL or Hyper-V engine

Non-interactive installations are silent and any additional configuration must be passed as arguments.

### Common installation commands

Admin rights are required to run any of the following commands.

#### Install interactively with verbose logging

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log"
```

#### Install interactively without verbose logging

```powershell
msiexec /i "DockerDesktop.msi"
```

#### Install non-interactively with verbose logging

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log" /quiet
```

#### Install non-interactively and suppressing reboots

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log" /quiet /norestart
```

#### Install non-interactively with admin settings

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log" /quiet /norestart ADMINSETTINGS="{""configurationFileVersion"":2,""enhancedContainerIsolation"":{""value"":true,""locked"":false}}" ALLOWEDORG="your-organization"
```

#### Install interactively and allow users to switch to Windows containers without admin rights

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log" /quiet /norestart ALLOWEDORG="your-organization" ALWAYSRUNSERVICE=1
```

#### Install interactively specifying a PAC file

```powershell
PowerShell
 msiexec --% /i "DockerDesktop.msi" /L*V ".\msi.log"  PROXYHTTPMODE="manual" OVERRIDEPROXYPAC="http://localhost:8080/myproxy.pac"
```

#### Install interactively specifying a PAC script

```powershell
PowerShell
 msiexec --% /i "DockerDesktop.msi" /L*V ".\msi.log"  PROXYHTTPMODE="manual" OVERRIDEPROXYEMBEDDEDPAC="function FindProxyForURL(url,host) {return ""DIRECT"" ;; }"
```

#### Install with the passive display option

You can use the `/passive` display option instead of `/quiet` when you want to perform a non-interactive installation but show a progress dialog.

In passive mode the installer doesn't display any prompts or error messages to the user and the installation cannot be cancelled.

For example:

```powershell
msiexec /i "DockerDesktop.msi" /L*V ".\msi.log" /passive /norestart
```

> [!TIP]
>
> When creating a value that expects a JSON string:
>
> - The property expects a JSON formatted string
> - The string should be wrapped in double quotes
> - The string shouldn't contain any whitespace
> - Property names are expected to be in double quotes

### Common uninstall commands

When uninstalling Docker Desktop, you need to use the same `.msi` file that was originally used to install the application.

If you no longer have the original `.msi` file, you need to use the product code associated with the installation. To find the product code, run:

```powershell
Get-WmiObject Win32_Product | Select-Object IdentifyingNumber, Name | Where-Object {$_.Name -eq "Docker Desktop"}
```

It should return output similar to the following:

```text
IdentifyingNumber                      Name
-----------------                      ----
{10FC87E2-9145-4D7D-B493-2E99E8D8E103} Docker Desktop
```

> [!NOTE]
>
> This command may take some time, depending on the number of installed applications.

`IdentifyingNumber` is the applications product code and can be used to uninstall Docker Desktop. For example:

```powershell
msiexec /x {10FC87E2-9145-4D7D-B493-2E99E8D8E103} /L*V ".\msi.log" /quiet
```

#### Uninstall interactively with verbose logging

```powershell
msiexec /x "DockerDesktop.msi" /L*V ".\msi.log"
```

#### Uninstall interactively without verbose logging

```powershell
msiexec /x "DockerDesktop.msi"
```

#### Uninstall non-interactively with verbose logging

```powershell
msiexec /x "DockerDesktop.msi" /L*V ".\msi.log" /quiet
```

#### Uninstall non-interactively without verbose logging

```powershell
msiexec /x "DockerDesktop.msi" /quiet
```

### Configuration options

In addition to the following custom properties, the Docker Desktop MSI installer also supports the standard [Windows Installer command line options](https://learn.microsoft.com/en-us/windows/win32/msi/standard-installer-command-line-options).

| Property                           | Description                                                                                                                                                                                                                                                                                   | Default                 |
| :--------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------- |
| `ENABLEDESKTOPSHORTCUT`            | Creates a desktop shortcut.                                                                                                                                                                                                                                                                   | 1                       |
| `INSTALLFOLDER`                    | Specifies a custom location where Docker Desktop will be installed.                                                                                                                                                                                                                           | C:\Program Files\Docker |
| `ADMINSETTINGS`                    | Automatically creates an `admin-settings.json` file which is used to [control certain Docker Desktop settings](../security/hardened-desktop/settings-management/index.md) on client machines within organizations. It must be used together with the `ALLOWEDORG` property. | None                    |
| `ALLOWEDORG`                       | Requires the user to sign in and be part of the specified Docker Hub organization when running the application. This creates a registry key called `allowedOrgs` in `HKLM\Software\Policies\Docker\Docker Desktop`.                                                                           | None                    |
| `ALWAYSRUNSERVICE`                 | Lets users switch to Windows containers without needing admin rights                                                                                                                                                                                                                          | 0                       |
| `DISABLEWINDOWSCONTAINERS`         | Disables the Windows containers integration                                                                                                                                                                                                                                                   | 0                       |
| `ENGINE`                           | Sets the Docker Engine that's used to run containers. This can be either `wsl` , `hyperv`, or `windows`                                                                                                                                                                                       | `wsl`                   |
| `PROXYENABLEKERBEROSNTLM`          | When set to 1, enables support for Kerberos and NTLM proxy authentication.                                                                                                                                                                                                                    | 0                       |
| `PROXYHTTPMODE`                    | Sets the HTTP Proxy mode. This can be either `system` or `manual`                                                                                                                                                                                                                             | `system`                |
| `OVERRIDEPROXYHTTP`                | Sets the URL of the HTTP proxy that must be used for outgoing HTTP requests.                                                                                                                                                                                                                  | None                    |
| `OVERRIDEPROXYHTTPS`               | Sets the URL of the HTTP proxy that must be used for outgoing HTTPS requests.                                                                                                                                                                                                                 | None                    |
| `OVERRIDEPROXYEXCLUDE`             | Bypasses proxy settings for the hosts and domains. Uses a comma-separated list.                                                                                                                                                                                                               | None                    |
| `OVERRIDEPROXYPAC`                 | Sets the PAC file URL. This setting takes effect only when using `manual` proxy mode.                                                                                                                                                                                                         | None                    |
| `OVERRIDEPROXYEMBEDDEDPAC`         | Specifies an embedded PAC (Proxy Auto-config) script. This setting takes effect only when using `manual` proxy mode and has precedence over the `OVERRIDEPROXYPAC` flag.                                                                                                                      | None                    |
| `HYPERVDEFAULTDATAROOT`            | Specifies the default location for the Hyper-V VM disk.                                                                                                                                                                                                                                       | None                    |
| `WINDOWSCONTAINERSDEFAULTDATAROOT` | Specifies the default location for Windows containers.                                                                                                                                                                                                                                        | None                    |
| `WSLDEFAULTDATAROOT`               | Specifies the default location for the WSL distribution disk.                                                                                                                                                                                                                                 | None                    |
| `DISABLEANALYTICS`                 | When set to 1, analytics collection will be disabled for the MSI. For more information, see [Analytics](#analytics).                                                                                                                                                                          | 0                       |
| `REMOVEEXISTINGINSTALL`            | When set to 1, any existing EXE installations are removed. Existing settings and content are preserved. Available with Docker Desktop version 4.61 and later.   | 1 |

Additionally, you can also use `/norestart` or `/forcerestart` to control reboot behaviour.

By default, the installer reboots the machine after a successful installation. When run silently, the reboot is automatic and the user is not prompted.

## Analytics

The MSI installer collects anonymous usage statistics relating to installation only. This is to better understand user behaviour and to improve the user experience by identifying and addressing issues or optimizing popular features.

### How to opt-out

{{< tabs >}}
{{< tab name="From the GUI" >}}

When you install Docker Desktop from the default installer GUI, select the **Disable analytics** checkbox located on the bottom-left corner of the **Welcome** dialog.

{{< /tab >}}
{{< tab name="From the command line" >}}

When you install Docker Desktop from the command line, use the `DISABLEANALYTICS` property.

```powershell
msiexec /i "win\msi\bin\en-US\DockerDesktop.msi" /L*V ".\msi.log" DISABLEANALYTICS=1
```

{{< /tab >}}
{{< /tabs >}}

### Persistence

If you decide to disable analytics for an installation, your choice is persisted in the registry and honoured across future upgrades and uninstalls.

However, the key is removed when Docker Desktop is uninstalled and must be configured again via one of the previous methods.

The registry key is as follows:

```powershell
SOFTWARE\Docker Inc.\Docker Desktop\DisableMsiAnalytics
```

When analytics is disabled, this key is set to `1`.

## Additional resources

- [Explore the FAQs](faq.md)


---

# PKG installer

*Sección: Enterprise*

{{< summary-bar feature_name="PKG installer" >}}

The PKG package supports various MDM (Mobile Device Management) solutions, making it ideal for bulk installations and eliminating the need for manual setups by individual users. With this package, IT administrators can ensure standardized, policy-driven installations of Docker Desktop, enhancing efficiency and software management across their organizations.

## Install interactively

1. In [Docker Home](http://app.docker.com), choose your organization.
2. Select **Docker Desktop**, then **Deploy**.
3. From the **macOS** tab, select the **Download PKG installer** button.
4. Once downloaded, double-click `Docker.pkg` to run the installer.
5. Follow the instructions on the installation wizard to authorize the installer and proceed with the installation.
   - **Introduction**: Select **Continue**.
   - **License**: Review the license agreement and select **Agree**.
   - **Destination Select**: This step is optional. It is recommended that you keep the default installation destination (usually `Macintosh HD`). Select **Continue**.
   - **Installation Type**: Select **Install**.
   - **Installation**: Authenticate using your administrator password or Touch ID.
   - **Summary**: When the installation completes, select **Close**.

> [!NOTE]
>
> When installing Docker Desktop with the PKG, in-app updates are automatically disabled. This ensures organizations can maintain version consistency and prevent unapproved updates. For Docker Desktop installed with the `.dmg` installer, in-app updates remain supported.
>
> Docker Desktop notifies you when an update is available. To update Docker Desktop, download the latest installer from the Docker Home. Navigate to the **Deploy** page.
>
> To keep up to date with new releases, check the [release notes](../../desktop/release-notes.md) page.

## Install from the command line

1. In [Docker Home](http://app.docker.com), choose your organization.
2. Select **Docker Desktop**, then **Deploy**.
3. From the **macOS** tab, select the **Download PKG installer** button.
4. From your terminal, run the following command:

   ```console
   $ sudo installer -pkg "/path/to/Docker.pkg" -target /Applications
   ```

## Additional resources

- See how you can deploy Docker Desktop for Mac using [Intune](use-intune.md) or [Jamf Pro](use-jamf-pro.md)
- Explore how to [Enforce sign-in](../security/enforce-sign-in/methods.md#plist-method-mac-only) for your users.


---

# Deploy with Intune

*Sección: Enterprise*

{{< summary-bar feature_name="Intune" >}}

Learn how to deploy Docker Desktop on Windows and macOS devices using Microsoft Intune. It covers app creation, installer configuration, and assignment to users or devices.

{{< tabs >}}
{{< tab name="Windows" >}}

1. Sign in to your Intune admin center.
2. Add a new app. Select **Apps**, then **Windows**, then **Add**.
3. For the app type, select **Windows app (Win32)**
4. Select the `intunewin` package. 
5. Fill in the required details, such as the description, publisher, or app version and then select **Next**. 
6. Optional: On the **Program** tab, you can update the **Install command** field to suit your needs. The field is pre-populated with `msiexec /i "DockerDesktop.msi" /qn`. See the [Common installation scenarios](msi-install-and-configure.md) for examples on the changes you can make. 

   > [!TIP]
   >
   > It's recommended you configure the Intune deployment to schedule a reboot of the machine on successful installs.
   >
   > This is because the Docker Desktop installer installs Windows features depending on your engine selection and also updates the membership of the `docker-users` local group.
   >
   > You may also want to set Intune to determine behaviour based on return codes and watch for a return code of `3010`. Return code 3010 means the installation succeeded but a reboot is required.

7. Complete the remaining tabs, then review and create the app. 

{{< /tab >}}
{{< tab name="Mac" >}}

First, upload the package:

1. Sign in to your Intune admin center.
2. Add a new app. Select **Apps**, then **macOS**, then **Add**.
3. Select **Line-of-business app** and then **Select**.
4. Upload the `Docker.pkg` file and fill in the required details.

Next, assign the app:

1. Once the app is added, navigate to **Assignments** in Intune.
2. Select **Add group** and choose the user or device groups you want to assign the app to.
3. Select **Save**.

{{< /tab >}}
{{< /tabs >}}

## Additional resources

- [Explore the FAQs](faq.md).
- Learn how to [enforce sign-in](../security/enforce-sign-in/index.md) for your users.


---

# Deploy with Jamf Pro

*Sección: Enterprise*

{{< summary-bar feature_name="Jamf Pro" >}}

Learn how to deploy Docker Desktop for Mac using Jamf Pro, including uploading the installer and creating a deployment policy.

First, upload the package:

1. From the Jamf Pro console, navigate to **Computers** > **Management Settings** > **Computer Management** > **Packages**.
2. Select **New** to add a new package.
3. Upload the `Docker.pkg` file.

Next, create a policy for deployment:

1. Navigate to **Computers** > **Policies**.
2. Select **New** to create a new policy.
3. Enter a name for the policy, for example "Deploy Docker Desktop".
4. Under the **Packages** tab, add the Docker package you uploaded.
5. Configure the scope to target the devices or device groups on which you want to install Docker.
6. Save the policy and deploy.

For more information, see [Jamf Pro's official documentation](https://learn.jamf.com/en-US/bundle/jamf-pro-documentation-current/page/Policies.html). 

## Additional resources

- Learn how to [enforce sign-in](../security/enforce-sign-in/index.md) for your users.


---

# Security for enterprises

*Sección: Enterprise*

[Hardened Docker Desktop](hardened-desktop/index.md)
provides security features that help organizations secure developer
environments, including Settings Management, Enhanced Container Isolation,
Registry Access Management, and related controls.

{{< grid >}}


---

# Enforce sign-in for Docker Desktop

*Sección: Enterprise*

{{< summary-bar feature_name="Enforce sign-in" >}}

By default, users can access Docker Desktop without signing in to your organization.
When users don't sign in as organization members, they miss out on subscription benefits and can bypass security features configured for your organization.

You can enforce sign-in using several methods, depending on your setup:

- [Registry key method (Windows only)](methods.md#registry-key-method-windows-only)
- [Configuration profiles method (Mac only)](methods.md#configuration-profiles-method-mac-only)
- [`.plist` method (Mac only)](methods.md#plist-method-mac-only)
- [`registry.json` method (All)](methods.md#registryjson-method-all)

This page provides an overview of how sign-in enforcement works.

## How sign-in enforcement works

When Docker Desktop detects a registry key, configuration profile, `.plist` file, or
`registry.json` file:

- A **Sign in required!** prompt appears, requiring users to sign
  in as organization members to use Docker Desktop.
- If users sign in with accounts that aren't organization members, they're
  automatically signed out and can't use Docker Desktop. They can select **Sign in**
  to try again with a different account.
- When users sign in with organization member accounts, they can use Docker
  Desktop normally.
- When users sign out, the **Sign in required!** prompt reappears and they can
  no longer use Docker Desktop unless they sign back in.

> [!NOTE]
>
> Enforcing sign-in for Docker Desktop doesn't affect Docker CLI access. CLI access is only restricted for organizations that enforce single sign-on (SSO).

### Impact on already-signed-in users

When enforcement is first deployed, users who are already running Docker Desktop are not immediately affected. Docker Desktop only re-evaluates enforcement on restart.

On the next Docker Desktop restart:

- Users signed in with an organization member account are automatically re-authenticated and continue working uninterrupted.
- Users signed in with a non-member account are immediately signed out on startup and see the **Sign in required!** prompt. 

## Enforcing sign-in versus enforcing single sign-on (SSO)

Enforcing Docker Desktop sign-in and [enforcing SSO](../../../security/authentication/single-sign-on/connect.md#enforce-sso) are different features that serve different purposes:

| Enforcement                       | Description                                                     | Benefits                                                                                                                                                                                                                                                   |
|:----------------------------------|:----------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Enforce sign-in only              | Users must sign in before using Docker Desktop                 | Ensures users receive the benefits of your subscription and ensures security features are applied. In addition, you gain insights into users’ activity.                                                                                                    |
| Enforce single sign-on (SSO) only | If users sign in, they must sign in using SSO                  | Centralizes authentication and enforces unified policies set by the identity provider.                                                                                                                                                                     |
| Enforce both                      | Users must sign in using SSO before using Docker Desktop       | Ensures users receive the benefits of your subscription and ensures security features are applied. In addition, you gain insights into users’ activity. It also centralizes authentication and enforces unified policies set by the identity provider. |
| Enforce neither                   | If users sign in, they can use SSO or their Docker credentials | Lets users access Docker Desktop without barriers, at the cost of reduced security and insights.                                                                                                                                                  |

## Next steps

- To set up sign-in enforcement, see [Configure sign-in enforcement](methods.md).
- To configure SSO enforcement, see [Enforce SSO](../../../security/authentication/single-sign-on/connect.md).


---

# Configure sign-in enforcement

*Sección: Enterprise*

{{< summary-bar feature_name="Enforce sign-in" >}}

You can enforce sign-in for Docker Desktop using several methods. Choose the method that best fits your organization's infrastructure and security requirements.

## Choose your method

| Method | Platform |
|:-------|:---------|
| Registry key | Windows only |
| Configuration profiles | Mac only |
| `plist` file | Mac only |
| `registry.json` | All platforms |

> [!TIP]
>
> For Mac, configuration profiles offer the highest security because they're
protected by Apple's System Integrity Protection (SIP).

## Windows: Registry key method

{{< tabs >}}
{{< tab name="Manual setup" >}}

To configure the registry key method manually:

1. Create the registry key:

   ```console
   $ HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Docker\Docker Desktop
   ```
1. Create a multi-string value name `allowedOrgs`.
1. Use your organization names as string data. You can add multiple organizations:
   - Use lowercase letters only
   - Add each organization on a separate line
   - Do not use spaces or commas as separators
1. Restart Docker Desktop.
1. Verify the **Sign in required!** prompt appears in Docker Desktop.

{{< /tab >}}
{{< tab name="Group Policy deployment" >}}

Deploy the registry key across your organization using Group Policy:

1. Create a registry script with the following structure:
   - Path: `HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Docker\Docker Desktop`
   - Value name: `allowedOrgs` (multi-string)
   - Value data: Your organization names, one per line, in lowercase only
1. In Group Policy Management, create or edit a GPO.
1. Navigate to **Computer Configuration** > **Preferences** > **Windows Settings** > **Registry**.
1. Right-click **Registry** > **New** > **Registry Item**.
1. Configure the registry item:
   - Action: **Update**
   - Path: `HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Docker\Docker Desktop`
   - Value name: `allowedOrgs`
   - Value data: Your organization names
1. Link the GPO to the target Organizational Unit.
1. Test on a small group using `gpupdate/force`.
1. Deploy organization-wide after verification.

{{< /tab >}}
{{< /tabs >}}

## Mac: Configuration profiles method (recommended)

Configuration profiles provide the most secure enforcement method for Mac, as they're protected by Apple's System Integrity Protection.

The payload is a dictionary of key-values. Docker Desktop supports the following keys:

- `allowedOrgs`: Sets a list of organizations in one single string, where each organization is in lowercase only and is separated by a semi-colon. 
- `overrideProxyHTTP`: Sets the URL of the HTTP proxy that must be used for outgoing HTTP requests.
- `overrideProxyHTTPS`: Sets the URL of the HTTP proxy that must be used for outgoing HTTPS requests.
- `overrideProxyExclude`: Bypasses proxy settings for the specified hosts and domains. Uses a comma-separated list.
- `overrideProxyPAC`: Sets the file path where the PAC file is located. It has precedence over the remote PAC file on the selected proxy.
- `overrideProxyEmbeddedPAC`: Sets the content of an in-memory PAC file. It has precedence over `overrideProxyPAC`.

Overriding at least one of the proxy settings via Configuration profiles will automatically lock the settings as they're managed by Mac.


1. Create a file named `docker.mobileconfig` and include the following content:
   ```xml
   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
   <plist version="1.0">
   <dict>
      <key>PayloadContent</key>
      <array>
         <dict>
            <key>PayloadType</key>
            <string>com.docker.config</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>PayloadIdentifier</key>
            <string>com.docker.config</string>
            <key>PayloadUUID</key>
            <string>eed295b0-a650-40b0-9dda-90efb12be3c7</string>
            <key>PayloadDisplayName</key>
            <string>Docker Desktop Configuration</string>
            <key>PayloadDescription</key>
            <string>Configuration profile to manage Docker Desktop settings.</string>
            <key>PayloadOrganization</key>
            <string>Your company name</string>
            <key>allowedOrgs</key>
            <string>first_org;second_org</string>
            <key>overrideProxyHTTP</key>
            <string>http://company.proxy:port</string>
            <key>overrideProxyHTTPS</key>
            <string>https://company.proxy:port</string>
         </dict>
      </array>
      <key>PayloadType</key>
      <string>Configuration</string>
      <key>PayloadVersion</key>
      <integer>1</integer>
      <key>PayloadIdentifier</key>
      <string>com.yourcompany.docker.config</string>
      <key>PayloadUUID</key>
      <string>0deedb64-7dc9-46e5-b6bf-69d64a9561ce</string>
      <key>PayloadDisplayName</key>
      <string>Docker Desktop Config Profile</string>
      <key>PayloadDescription</key>
      <string>Config profile to enforce Docker Desktop settings for allowed organizations.</string>
      <key>PayloadOrganization</key>
      <string>Your company name</string>
   </dict>
   </plist>
   ```
1. Replace placeholders:
   - Change `com.yourcompany.docker.config` to your company identifier
   - Replace `Your company name` with your organization name making sure it is all lowercase
   - Replace `PayloadUUID` with a randomly generated UUID
   - Update the `allowedOrgs` value with your organization names (separated by semicolons)
   - Replace `company.proxy:port` with http/https proxy server host(or IP address) and port
1. Deploy the profile using your MDM solution.
1. Verify the profile appears in **System Settings** > **General** > **Device Management** under **Device (Managed)**. Ensure the profile is listed with the correct name and settings.

Some MDM solutions let you specify the payload as a plain dictionary of key-value settings without the full `.mobileconfig` wrapper:

```xml
<dict>
   <key>allowedOrgs</key>
   <string>first_org;second_org</string>
   <key>overrideProxyHTTP</key>
   <string>http://company.proxy:port</string>
   <key>overrideProxyHTTPS</key>
   <string>https://company.proxy:port</string>
</dict>
```

## Mac: plist file method

{{< tabs >}}
{{< tab name="Manual creation" >}}

1. Create the file `/Library/Application Support/com.docker.docker/desktop.plist`.
1. Add this content, replacing `myorg1` and `myorg2` with your organization names and making sure they have lowercase letters only:
   ```xml
   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
   <plist version="1.0">
     <dict>
	     <key>allowedOrgs</key>
	     <array>
             <string>myorg1</string>
             <string>myorg2</string>
         </array>
     </dict>
   </plist>
   ```
1. Set file permissions to prevent editing by non-administrator users.
1. Restart Docker Desktop.
1. Verify the `Sign in required!` prompt appears in Docker Desktop.

{{< /tab >}}
{{< tab name="Shell script deployment" >}}

Create and deploy a script for organization-wide distribution:

```bash
#!/bin/bash

# Create directory if it doesn't exist
sudo mkdir -p "/Library/Application Support/com.docker.docker"

# Write the plist file
sudo defaults write "/Library/Application Support/com.docker.docker/desktop.plist" allowedOrgs -array "myorg1" "myorg2"

# Set appropriate permissions
sudo chmod 644 "/Library/Application Support/com.docker.docker/desktop.plist"
sudo chown root:admin "/Library/Application Support/com.docker.docker/desktop.plist"
```

Deploy this script using SSH, remote support tools, or your preferred deployment method.

{{< /tab >}}
{{< /tabs >}}

## All platforms: registry.json method

The registry.json method works across all platforms and offers flexible deployment options.

### File locations

Create the `registry.json` file (UTF-8 without BOM) at the appropriate location:

| Platform | Location |
| --- | --- |
| Windows | `/ProgramData/DockerDesktop/registry.json` |
| Mac | `/Library/Application Support/com.docker.docker/registry.json` |
| Linux | `/usr/share/docker-desktop/registry/registry.json` |

### Basic setup

{{< tabs >}}
{{< tab name="Manual creation" >}}

1. Ensure users are members of your Docker organization.
1. Create the `registry.json` file at the appropriate location for your platform.
1. Add this content, replacing organization names with your own and making sure they have lowercase letters only:
      ```json
      {
         "allowedOrgs": ["myorg1", "myorg2"]
      }
      ```
1. Set file permissions to prevent user editing.
1. Restart Docker Desktop.
1. Verify the `Sign in required!` prompt appears in Docker Desktop.

> [!TIP]
>
> If users have issues starting Docker Desktop after enforcing sign-in,
> they may need to update to the latest version.

{{< /tab >}}
{{< tab name="Command line setup" >}}

#### Windows (PowerShell as Administrator)

```shell
Set-Content /ProgramData/DockerDesktop/registry.json '{"allowedOrgs":["myorg1","myorg2"]}'
```

#### Mac

```console
sudo mkdir -p "/Library/Application Support/com.docker.docker"
echo '{"allowedOrgs":["myorg1","myorg2"]}' | sudo tee "/Library/Application Support/com.docker.docker/registry.json"
```

#### Linux

```console
sudo mkdir -p /usr/share/docker-desktop/registry
echo '{"allowedOrgs":["myorg1","myorg2"]}' | sudo tee /usr/share/docker-desktop/registry/registry.json
```

{{< /tab >}}
{{< tab name="Installation-time setup" >}}

Create the registry.json file during Docker Desktop installation:

#### Windows

```shell
# PowerShell
Start-Process '.\Docker Desktop Installer.exe' -Wait 'install --allowed-org=myorg'

# Command Prompt
"Docker Desktop Installer.exe" install --allowed-org=myorg1
```

> [!NOTE]
>
> The `--allowed-org` flag accepts only one organization. To enforce sign-in for multiple organizations on Mac, configure the `registry.json` file after installation.

#### Mac

```console
sudo hdiutil attach Docker.dmg
sudo /Volumes/Docker/Docker.app/Contents/MacOS/install --allowed-org=myorg
sudo hdiutil detach /Volumes/Docker
```
> [!NOTE]
>
> The `--allowed-org` flag accepts only one organization. To enforce sign-in for multiple organizations on Mac, configure the `registry.json` file after installation.

{{< /tab >}}
{{< /tabs >}}

## Method precedence

When multiple configuration methods exist on the same system, Docker Desktop uses this precedence order:

1. Registry key (Windows only)
1. Configuration profiles (Mac only)
1. plist file (Mac only)
1. registry.json file

## Troubleshoot sign-in enforcement

If sign-in enforcement doesn't work:

- Verify file locations and permissions
- Check that organization names use lowercase letters
- Restart Docker Desktop or reboot the system
- Confirm users are members of the specified organizations
- Update Docker Desktop to the latest version


---

# Hardened Docker Desktop

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

Hardened Docker Desktop provides a collection of security features designed to strengthen developer environments without compromising productivity or developer experience.

With Hardened Docker Desktop, you can enforce strict security policies that prevent developers and containers from bypassing organizational controls. You can also enhance container isolation to protect against security threats like malicious payloads that might breach the Docker Desktop Linux VM or underlying host system.

## Who should use Hardened Docker Desktop?

Hardened Docker Desktop is ideal for security-focused organizations that:

- Don't provide root or administrator access to developers' machines
- Want centralized control over Docker Desktop configurations
- Must meet specific compliance requirements

## How Hardened Docker Desktop works

Hardened Docker Desktop features work independently and together to create a defense-in-depth security strategy. They protect developer workstations against attacks across multiple layers, including Docker Desktop configuration, container image management, and container runtime security:

- Registry Access Management and Image Access Management prevent access to unauthorized container registries and image types, reducing exposure to malicious payloads
- Enhanced Container Isolation runs containers without root privileges inside a Linux user namespace, limiting the impact of malicious containers
- Air-gapped containers let you configure network restrictions for containers, preventing malicious containers from accessing your organization's internal network resources
- Namespace access controls whether organization members can push content to their personal Docker Hub namespaces, preventing accidental publication of images outside approved locations
- Settings Management locks down Docker Desktop configurations to enforce company policies and prevent developers from introducing insecure settings, whether intentionally or accidentally

## Next steps

Explore Hardened Docker Desktop features to understand how they can strengthen your organization's security posture:

{{< grid >}}


---

# Air-gapped containers

*Sección: Enterprise*

{{< summary-bar feature_name="Air-gapped containers" >}}

Air-gapped containers let you restrict container network access by controlling where containers can send and receive data. This feature applies custom proxy rules to container network traffic, helping secure environments where containers shouldn't have unrestricted internet access.

Docker Desktop can configure container network traffic to accept connections, reject connections, or tunnel through HTTP or SOCKS proxies. You control which TCP ports the policy applies to and whether to use a single proxy or per-destination policies via Proxy Auto-Configuration (PAC) files.

## Who should use air-gapped containers?

Use air-gapped containers if:

- Your organization requires containers to communicate only with approved internal services
- You need to meet compliance standards that mandate network isolation (such as SOC 2, ISO 27001, or PCI DSS)
- You want to prevent containers from leaking data or reaching unapproved external endpoints during builds or at runtime

## How air-gapped containers work

`containersProxy` governs two distinct traffic paths:

- Image pulls (always enforced): Docker Desktop hardwires `http.docker.internal:3128` as the daemon's proxy in `daemon.json` at VM startup, so all `docker pull` and Compose pull operations always go through `containersProxy`, including any PAC file rules.
- Running container outbound traffic (opt-in): Docker Desktop intercepts container TCP connections and applies proxy rules only for ports listed in `transparentPorts`. Without it, running container traffic bypasses `containersProxy` entirely.

> [!IMPORTANT]
>
> If you configure a PAC file under `containersProxy`, the PAC file must return an appropriate proxy server to connect to the registries where your images are hosted.

Other considerations:

- If PAC file download fails, containers block requests to target URLs
- Hostname is available for ports 80 and 443, but only IP addresses for other ports

## Prerequisites

Before configuring air-gapped containers, you must have:

- [Enforce sign-in](../enforce-sign-in/index.md) enabled to ensure users authenticate with your organization
- A Docker Business subscription
- Configured [Settings Management](settings-management/index.md) with the `admin-settings.json` file to manage organization policies

## Configure air-gapped containers

Add the container proxy to your [`admin-settings.json` file](settings-management/configure-json-file.md). For example:

```json
{
  "configurationFileVersion": 2,
  "containersProxy": {
    "locked": true,
    "mode": "manual",
    "http": "",
    "https": "",
    "exclude": [],
    "pac": "http://192.168.1.16:62039/proxy.pac",
    "transparentPorts": "*"
  }
}
```

### Configuration parameters

The `containersProxy` setting controls network policies applied to `docker image pull` and, when `transparentPorts` is configured, running container outbound traffic:

| Parameter | Description | Value |
|-----------|-------------|-------|
| `locked` | Prevents developers from overriding settings | `true` (locked), `false` (default) |
| `mode` | Proxy configuration method | `system` (use system proxy), `manual` (custom) |
| `http` | HTTP proxy server | URL (e.g., `"http://proxy.company.com:8080"`) |
| `https` | HTTPS proxy server | URL (e.g., `"https://proxy.company.com:8080"`) |
| `exclude` | Bypass proxy for these addresses | Array of hostnames/IPs |
| `pac` | Proxy Auto-Configuration file URL | URL to PAC file |
| `transparentPorts` | Ports subject to proxy rules | Comma-separated ports or wildcard (`"*"`) |

### Configuration examples

Block all external access:

```json
"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "",
  "https": "",
  "exclude": [],
  "transparentPorts": "*"
}
```

Allow specific internal services:

```json
"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "",
  "https": "",
  "exclude": ["internal.company.com", "10.0.0.0/8"],
  "transparentPorts": "80,443"
}
```

Route through corporate proxy:

```json
"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "http://corporate-proxy.company.com:8080",
  "https": "http://corporate-proxy.company.com:8080",
  "exclude": ["localhost", "*.company.local"],
  "transparentPorts": "*"
}
```

## Proxy Auto-Configuration (PAC) files

PAC files provide fine-grained control over container network access by defining rules for different destinations.

### Basic PAC file structure

```javascript
function FindProxyForURL(url, host) {
	if (localHostOrDomainIs(host, 'internal.corp')) {
		return "PROXY 10.0.0.1:3128";
	}
	if (isInNet(host, "192.168.0.0", "255.255.255.0")) {
	    return "DIRECT";
	}
    return "PROXY reject.docker.internal:1234";
}
```

### General considerations

 - `FindProxyForURL` function URL parameter format is `http://host_or_ip:port` or `https://host_or_ip:port`
 - If you have an internal container trying to access `https://docs.docker.com/enterprise/security/hardened-desktop/air-gapped-containers` the Docker proxy service will submit docs.docker.com for the host value and https://docs.docker.com:443 for the URL value to `FindProxyForURL`, if you are using `shExpMatch` function in your PAC file as follows:

   <!-- vale off -->
   ```console
   if(shExpMatch(url, "https://docs.docker.com:443/enterprise/security/hardened-desktop/*")) return "DIRECT";
   ```

   `shExpMatch` function will fail, instead use:

   ```console
   if (host == docs.docker.com && url.indexOf(":443") > 0) return "DIRECT";
   ```
   <!-- vale on -->

### PAC file return values

| Return value | Action |
|--------------|--------|
| `PROXY host:port` | Route through HTTP proxy at specified host and port |
| `SOCKS5 host:port` | Route through SOCKS5 proxy at specified host and port |
| `DIRECT` | Allow direct connection without proxy |
| `PROXY reject.docker.internal:any_port` | Block the request completely |

### Advanced PAC file example

```javascript
function FindProxyForURL(url, host) {
  // Allow access to Docker Hub for approved base images
  if (dnsDomainIs(host, ".docker.io") || host === "docker.io") {
    return "PROXY corporate-proxy.company.com:8080";
  }

  // Allow internal package repositories
  if (localHostOrDomainIs(host, 'nexus.company.com') ||
      localHostOrDomainIs(host, 'artifactory.company.com')) {
    return "DIRECT";
  }

  // Allow development tools on specific ports
  if (url.indexOf(":3000") > 0 || url.indexOf(":8080") > 0) {
    if (isInNet(host, "10.0.0.0", "255.0.0.0")) {
      return "DIRECT";
    }
  }

  // Block access to developer's localhost
  if (host === "host.docker.internal" || host === "localhost") {
    return "PROXY reject.docker.internal:1234";
  }

  // Block all other external access
  return "PROXY reject.docker.internal:1234";
}
```

## Verify air-gapped container configuration

After applying the configuration, test that container network restrictions work:

Test blocked access:

```console
$ docker run --rm alpine wget -O- https://www.google.com
# Should fail or timeout based on your proxy rules
```

Test allowed access:

```console
$ docker run --rm alpine wget -O- https://internal.company.com
# Should succeed if internal.company.com is in your exclude list or PAC rules
```

Test proxy routing:

```console
$ docker run --rm alpine wget -O- https://docker.io
# Should succeed if routed through approved proxy
```

## Security considerations

- Network policy enforcement: Air-gapped containers work at the Docker Desktop level. Advanced users might bypass restrictions through various means, so consider additional network-level controls for high-security environments.
- Development workflow impact: Overly restrictive policies can break legitimate development workflows. Test thoroughly and provide clear exceptions for necessary services.
- PAC file management: Host PAC files on reliable internal infrastructure. Failed PAC downloads result in blocked container network access.
- Performance considerations: Complex PAC files with many rules may impact container network performance. Keep rules simple and efficient.

## Next steps

- [Explore Enhanced Container Isolation](enhanced-container-isolation/index.md) to further restrict what containers can do at runtime
- [Understand how Docker Desktop handles host and container networking](../../../desktop/features/networking/index.md)


---

# Enhanced Container Isolation

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

Enhanced Container Isolation (ECI) prevents malicious containers from compromising Docker Desktop or the host system. It applies advanced security techniques automatically while maintaining full developer productivity and workflow compatibility.

- ECI strengthens container isolation and locks in security configurations created by administrators, such as [Registry Access Management policies](../registry-access-management.md) and [Settings Management](../settings-management/index.md) controls. 
- ECI works alongside other Docker security features like reduced Linux capabilities, seccomp, and AppArmor.

If you are using WSL2 backend, ensure you’re running WSL version 2.6 or later. This is required because ECI depends on a Linux kernel version of at least 6.3.0, and WSL 2.6+ includes kernel version 6.6.

## Who should use Enhanced Container Isolation?

ECI is designed for:

- Organizations that want to prevent container-based attacks and reduce security vulnerabilities in developer environments
- Security teams that need stronger container isolation without impacting developer workflows
- Enterprises that require additional protection when running untrusted or third-party container images

## How Enhanced Container Isolation works

Docker implements ECI using the [Sysbox container runtime](https://github.com/nestybox/sysbox), a
security-enhanced fork of the standard OCI runc runtime. When ECI is turned on, containers created through `docker run` or `docker create` automatically use Sysbox instead of runc without requiring any changes to developer workflows. Docker's default runtime remains runc, but all user containers
implicitly launch with Sysbox. 

When ECI is turned on, the Docker CLI `--runtime` flag is ignored. Even containers using the `--privileged` flag run securely with ECI, preventing them from breaching the Docker Desktop virtual machine or other containers.

## Key security features

### Linux user namespace isolation

With Enhanced Container Isolation, all containers leverage Linux user namespaces for stronger isolation. Container root users map to unprivileged users in the Docker Desktop VM:

```console
$ docker run -it --rm --name=first alpine
/ # cat /proc/self/uid_map
         0     100000      65536
```

This output shows that container root (0) maps to unprivileged user 100000 in the VM, with a range of 64K user IDs. Each container gets exclusive mappings:

```console
$ docker run -it --rm --name=second alpine
/ # cat /proc/self/uid_map
         0     165536      65536
```

Without Enhanced Container Isolation, containers run as true root:

```console
$ docker run -it --rm alpine
/ # cat /proc/self/uid_map
         0       0     4294967295
```

By using Linux user namespaces, ECI ensures container processes never run with valid user IDs in the Linux VM, constraining their capabilities to resources within the container only.

### Secured privileged containers

Privileged containers (`docker run --privileged`) normally pose significant security risks because they provide unrestricted access to the Linux kernel. Without ECI, privileged containers can:

- Run as true root with all capabilities
- Bypass seccomp and AppArmor restrictions
- Access all hardware devices
- Modify global kernel settings

Organizations securing developer environments face challenges with privileged containers because they can gain control of the Docker Desktop VM and alter security settings like registry access management and network proxies.

Enhanced Container Isolation transforms privileged containers by ensuring they can only access resources within their container boundary. For example, privileged containers can't access Docker Desktop's network configuration:

```console
$ docker run --privileged djs55/bpftool map show
Error: can't get next map: Operation not permitted
```

Without ECI, privileged containers can easily access and modify these settings:

```console
$ docker run --privileged djs55/bpftool map show
17: ringbuf  name blocked_packets  flags 0x0
        key 0B  value 0B  max_entries 16777216  memlock 0B
18: hash  name allowed_map  flags 0x0
        key 4B  value 4B  max_entries 10000  memlock 81920B
```

Advanced container workloads like Docker-in-Docker and Kubernetes-in-Docker still work with ECI but run much more securely.

> [!NOTE]
>
> ECI doesn't prevent users from running privileged containers, but makes them secure by containing their access. Privileged workloads that modify global kernel settings (loading kernel modules, changing Berkeley Packet Filter settings) receive "permission denied" errors.

### Namespace isolation enforcement

Enhanced Container Isolation prevents containers from sharing Linux namespaces with the Docker Desktop VM, maintaining isolation boundaries:

**PID namespace sharing blocked:**

```console
$ docker run -it --rm --pid=host alpine
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: error in the container spec: invalid or unsupported container spec: sysbox containers can't share namespaces [pid] with the host (because they use the linux user-namespace for isolation): unknown.
```

**Network namespace sharing blocked:**

```console
$ docker run -it --rm --network=host alpine
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: error in the container spec: invalid or unsupported container spec: sysbox containers can't share a network namespace with the host (because they use the linux user-namespace for isolation): unknown.
```

**User namespace override ignored:**

```console
$ docker run -it --rm --userns=host alpine
/ # cat /proc/self/uid_map
         0     100000      65536
```

Docker build operations using `--network-host` and Docker Buildx entitlements (`network.host`,
`security.insecure`) are also blocked.

### Protected bind mounts

Enhanced Container Isolation maintains support for standard file sharing while preventing access to sensitive VM directories:

Host directory mounts continue to work:

```console
$ docker run -it --rm -v $HOME:/mnt alpine
/ # ls /mnt
# Successfully lists home directory contents
```

VM configuration mounts are blocked:

```console
$ docker run -it --rm -v /etc/docker/daemon.json:/mnt/daemon.json alpine
docker: Error response from daemon: failed to create shim task: OCI runtime create failed: error in the container spec: can't mount /etc/docker/daemon.json because it's configured as a restricted host mount: unknown
```

This prevents containers from reading or modifying Docker Engine configurations, registry access management settings, proxy configurations, and other security-related VM files.

> [!NOTE]
>
> By default, ECI blocks bind mounting the Docker Engine socket (/var/run/docker.sock) as this would grant containers control over Docker Engine. Administrators can create exceptions for trusted container images.

### Advanced system call protection

Enhanced Container Isolation intercepts sensitive system calls to prevent containers from using legitimate capabilities maliciously:

```console
$ docker run -it --rm --cap-add SYS_ADMIN -v $HOME:/mnt:ro alpine
/ # mount -o remount,rw /mnt /mnt
mount: permission denied (are you root?)
```

Even with `CAP_SYS_ADMIN` capability, containers can't change read-only bind mounts to read-write, ensuring they can't breach container boundaries.

Containers can still create internal mounts within their filesystem:

```console
/ # mkdir /root/tmpfs
/ # mount -t tmpfs tmpfs /root/tmpfs
/ # mount -o remount,ro /root/tmpfs /root/tmpfs
/ # findmnt | grep tmpfs
├─/root/tmpfs    tmpfs      tmpfs    ro,relatime,uid=100000,gid=100000
```

ECI performs system call filtering efficiently by intercepting only control-path system calls (rarely used) while leaving data-path system calls unaffected, maintaining container performance.

### Automatic filesystem user ID mapping

Enhanced Container Isolation solves file sharing challenges between containers with different user ID ranges through automatic filesystem mapping.

Each container gets exclusive user ID mappings, but Sysbox uses filesystem user ID remapping via Linux kernel ID-mapped mounts (added in 2021) or alternative shiftsfs module. This maps filesystem accesses from containers' real user IDs to standard ranges, enabling:

- Volume sharing across containers with different user ID ranges
- Consistent file ownership regardless of container user ID mappings
- Transparent file access without user intervention

### Information hiding through filesystem emulation

ECI emulates portions of `/proc` and `/sys` filesystems within containers to hide sensitive host information and provide per-container views of kernel resources:

```console
$ docker run -it --rm alpine
/ # cat /proc/uptime
5.86 5.86
```

This shows container uptime instead of Docker Desktop VM uptime, preventing system information from leaking into containers.

Several `/proc/sys` resources that aren't namespaced by the Linux kernel are emulated per-container, with Sysbox coordinating values when programming kernel settings. This enables container workloads that normally require privileged access to run securely.

## Performance and compatibility

Enhanced Container Isolation maintains optimized performance and full compatibility:

- No performance impact: System call filtering targets only control-path calls, leaving data-path operations unaffected
- Full workflow compatibility: Existing development processes, tools, and container images work unchanged
- Advanced workload support: Docker-in-Docker, Kubernetes-in-Docker, and other complex scenarios work securely
- Automatic management: User ID mappings, filesystem access, and security policies are handled automatically
- Standard image support: No special container images or modifications required

> [!IMPORTANT]
>
> ECI protection varies by Docker Desktop version and doesn't yet protect extension containers. Docker builds and Kubernetes in Docker Desktop have varying protection levels depending on the version. For details, see [Enhanced Container Isolation limitations](limitations.md).


---

# Configure Docker socket exceptions and advanced settings

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

This page shows you how to configure Docker socket exceptions and other advanced settings for Enhanced Container Isolation (ECI). These configurations enable trusted tools like Testcontainers to work with ECI while maintaining security.

## Docker socket mount permissions

By default, Enhanced Container Isolation blocks containers from mounting the Docker socket to prevent malicious access to Docker Engine. However, some tools require Docker socket access.

Common scenarios requiring Docker socket access include:

- Testing frameworks: Testcontainers, which manages test containers
- Build tools: Paketo buildpacks that create ephemeral build containers
- CI/CD tools: Tools that manage containers as part of deployment pipelines
- Development utilities: Docker CLI containers for container management

## Configure socket exceptions

Configure Docker socket exceptions using Settings Management:

{{< tabs >}}
{{< tab name="Docker Home" >}}

1. Sign in to [Docker Home](https://app.docker.com) and select your organization from the top-left account drop-down.
1. Select **Docker Desktop**, then **Settings Management**.
1. [Create or edit a setting policy](../settings-management/configure-admin-console.md).
1. Find **Enhanced Container Isolation** settings.
1. Configure **Docker socket access control** with your trusted images and
command restrictions.

{{< /tab >}}
{{< tab name="JSON file" >}}

Create an [`admin-settings.json` file](../settings-management/configure-json-file.md) and add:

```json
{
  "configurationFileVersion": 2,
  "enhancedContainerIsolation": {
    "locked": true,
    "value": true,
    "dockerSocketMount": {
      "imageList": {
        "images": [
          "docker.io/localstack/localstack:*",
          "docker.io/testcontainers/ryuk:*",
          "docker:cli"
        ],
        "allowDerivedImages": true
      },
      "commandList": {
        "type": "deny",
        "commands": ["push", "build"]
      }
    }
  }
}
```

{{< /tab >}}
{{< /tabs >}}

## Image allowlist configuration

The `imageList` defines which container images can mount the Docker socket.

### Image reference formats

| Format  | Description |
| :---------------------- | :---------- |
| `<image_name>[:<tag>]`  | Name of the image, with optional tag. If the tag is omitted, the `:latest` tag is used. If the tag is the wildcard `*`, then it means "any tag for that image." |
| `<image_name>@<digest>` | Name of the image, with a specific repository digest (e.g., as reported by `docker buildx imagetools inspect <image>`). This means only the image that matches that name and digest is allowed. |

### Example configurations

Basic allowlist for testing tools:

```json
"imageList": {
  "images": [
    "docker.io/testcontainers/ryuk:*",
    "docker:cli",
    "alpine:latest"
  ]
}
```

Wildcard allowlist (Docker Desktop 4.36 and later):

```json
"imageList": {
  "images": ["*"]
}
```

> [!WARNING]
>
> Using `"*"` allows all containers to mount the Docker socket, which reduces security. Only use this when explicitly listing allowed images isn't feasible.

### Security validation

Docker Desktop validates allowed images by:

1. Downloading image digests from registries for allowed images
1. Comparing container image digests against the allowlist when containers start
1. Blocking containers whose digests don't match allowed images

This prevents bypassing restrictions by re-tagging unauthorized images:

```console
$ docker tag malicious-image docker:cli
$ docker run -v /var/run/docker.sock:/var/run/docker.sock docker:cli
# This fails because the digest doesn't match the real docker:cli image
```

## Derived images support

For tools like Paketo buildpacks that create ephemeral local images, you can
allow images derived from trusted base images.

### Enable derived images

```json
"imageList": {
  "images": [
    "paketobuildpacks/builder:base"
  ],
  "allowDerivedImages": true
}
```

When `allowDerivedImages` is true, local images built from allowed base images (using `FROM` in Dockerfile) also gain Docker socket access.

### Derived images requirements

- Local images only: Derived images must not exist in remote registries
- Base image available: The parent image must be pulled locally first
- Performance impact: Adds up to 1 second to container startup for validation
- Version compatibility: Full wildcard support requires Docker Desktop 4.36+

## Command restrictions

### Deny list (recommended)

Blocks specified commands while allowing all others:

```json
"commandList": {
  "type": "deny",
  "commands": ["push", "build", "image*"]
}
```

### Allow list

Only allows specified commands while blocking all others:

```json
"commandList": {
  "type": "allow",
  "commands": ["ps", "container*", "volume*"]
}
```

### Command wildcards

| Wildcard | Blocks/allows |
| :---------------- | :---------- |
| `"container\*"`     | All "docker container ..." commands |
| `"image\*"`         | All "docker image ..." commands |
| `"volume\*"`        | All "docker volume ..." commands |
| `"network\*"`       | All "docker network ..." commands |
| `"build\*"`         | All "docker build ..." commands |
| `"system\*"`        | All "docker system ..." commands |

### Command blocking example

When a blocked command is executed:

```console
/ # docker push myimage
Error response from daemon: enhanced container isolation: docker command "/v1.43/images/myimage/push?tag=latest" is blocked; if you wish to allow it, configure the docker socket command list in the Docker Desktop settings.
```

## Common configuration examples

### Testcontainers setup

For Java/Python testing with Testcontainers:

```json
"dockerSocketMount": {
  "imageList": {
    "images": [
      "docker.io/testcontainers/ryuk:*",
      "testcontainers/*:*"
    ]
  },
  "commandList": {
    "type": "deny",
    "commands": ["push", "build"]
  }
}
```

### CI/CD pipeline tools

For controlled CI/CD container management:

```json
"dockerSocketMount": {
  "imageList": {
    "images": [
      "docker:cli",
      "your-registry.com/ci-tools/*:*"
    ]
  },
  "commandList": {
    "type": "allow",
    "commands": ["ps", "container*", "image*"]
  }
}
```

### Development environments

For local development with Docker-in-Docker:

```json
"dockerSocketMount": {
  "imageList": {
    "images": [
      "docker:dind",
      "docker:cli"
    ]
  },
  "commandList": {
    "type": "deny",
    "commands": ["system*"]
  }
}
```

## Security recommendations

### Image allowlist best practices

- Be restrictive: Only allow images you absolutely trust and need
- Use wildcards carefully: Tag wildcards (`*`) are convenient but less secure than specific tags
- Regular reviews: Periodically review and update your allowlist
- Digest pinning: Use digest references for maximum security in critical environments

### Command restrictions

- Default to deny: Start with a deny list blocking dangerous commands like `push` and `build`
- Principle of least privilege: Only allow commands your tools actually need
- Monitor usage: Track which commands are being blocked to refine your configuration

### Monitoring and maintenance

- Regular validation: Test your configuration after Docker Desktop updates, as image digests may change.
- Handle digest mismatches: If allowed images are unexpectedly blocked:
    ```console
    $ docker image rm <image>
    $ docker pull <image>
    ```

This resolves digest mismatches when upstream images are updated.

## Next steps

- Review [Enhanced Container Isolation limitations](limitations.md).
- Review [Enhanced Container Isolation FAQs](faq.md).


---

# Enable Enhanced Container Isolation

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

ECI prevents malicious containers from compromising Docker Desktop while maintaining full developer productivity.

This page shows you how to turn on Enhanced Container Isolation (ECI) and verify it's working correctly.

## Prerequisites

Before you begin, you must have:

- A Docker Business subscription
- [Enforced sign-in](../../enforce-sign-in/index.md) (for administrators managing organization-wide settings only)

## Enable Enhanced Container Isolation

### For developers

Turn on ECI in your Docker Desktop settings:

1. Sign in to your organization in Docker Desktop. Your organization must have
a Docker Business subscription.
1. Stop and remove all existing containers:

    ```console
    $ docker stop $(docker ps -q)
    $ docker rm $(docker ps -aq)
    ```

1. In Docker Desktop, go to **Settings** > **General**.
1. Select the **Use Enhanced Container Isolation** checkbox.
1. Select **Apply and restart**.

> [!IMPORTANT]
>
> ECI doesn't protect containers created before turning on the feature. Remove existing containers before turning on ECI.

### For administrators

Configure Enhanced Container Isolation organization-wide using Settings Management:

{{< tabs >}}
{{< tab name="Docker Home" >}}

1. Sign in to [Docker Home](https://app.docker.com) and select your organization from the top-left account drop-down.
1. Select **Docker Desktop**, then **Settings Management**.
1. [Create or edit a setting policy](../settings-management/configure-admin-console.md).
1. Set **Enhanced Container Isolation** to **Always enabled**.

{{< /tab >}}
{{< tab name="JSON file" >}}

1. Create an [`admin-settings.json` file](../settings-management/configure-json-file.md) and add:

      ```json
      {
        "configurationFileVersion": 2,
        "enhancedContainerIsolation": {
          "value": true,
          "locked": true
        }
      }
      ```

1. Configure the following as needed:
    - `"value": true`: Turns on ECI by default (required)
    - `"locked": true`: Prevents developers from turning off ECI
    - `"locked": false`: Allows developers to control the setting

{{< /tab >}}
{{< /tabs >}}

### Apply the configuration

For ECI settings to take effect:

- New installations: Users launch Docker Desktop and sign in
- Existing installations: Users must fully quit Docker Desktop and relaunch

> [!IMPORTANT]
>
> Restarting from the Docker Desktop menu isn't sufficient. Users must completely quit and reopen Docker Desktop.

You can also configure [Docker socket mount permissions](config.md) for trusted images that need Docker API access.

## Verify Enhanced Container Isolation is active

After turning on ECI, verify it's working correctly using these methods.

### Check user namespace mapping

Run a container and examine the user namespace mapping:

```console
$ docker run --rm alpine cat /proc/self/uid_map
```

With ECI turned on:

```text
0     100000      65536
```

This shows the container's root user (0) maps to an unprivileged user (100000) in the Docker Desktop VM, with a range of 64K user IDs. Each container gets an exclusive user ID range for isolation.

With ECI turned off:

```text
0          0 4294967295
```

This shows the container root user (0) maps directly to the VM root user (0), providing less isolation.

### Check container runtime

Verify the container runtime being used:

```console
$ docker inspect --format='{{.HostConfig.Runtime}}' <container_name>
```

With ECI turned on, it turns `sysbox-runc`. With ECI turned off, it returns
`runc`.

### Test security restrictions

Verify that ECI security restrictions are active.

Test namespace sharing:

```console
$ docker run -it --rm --pid=host alpine
```

With ECI turned on, this command fails with an error about Sysbox containers
not being able to share namespaces with the host.

Test Docker socket access:

```console
$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock alpine
```

With ECI turned on, this command fails unless you've configured Docker socket exceptions for trusted images.

## What users see with enforced ECI

When administrators enforce Enhanced Container Isolation through
Settings Management:

- The **Use Enhanced Container Isolation** setting appears turned on in
Docker Desktop settings.
- If set to `"locked": true`, the setting is locked and greyed out.
- All new containers automatically use Linux user namespaces.
- Existing development workflows continue to work without modification.
- Users see `sysbox-runc` as the container runtime in `docker inspect` output.

## Next steps

- Review [Configure Docker socket exceptions and advanced settings](config.md).
- Review [Enhanced Container Isolation limitations](limitations.md).


---

# Enhanced Container Isolation FAQs

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

This page answers common questions about Enhanced Container Isolation (ECI) that aren't covered in the main documentation.

## Do I need to change the way I use Docker when ECI is switched on?

No. ECI works automatically in the background by creating more secure containers. You can continue using all your existing Docker commands, workflows, and development tools without any changes.

## Do all container workloads work well with ECI?

Most container workloads run without issues when ECI is turned on. However, some advanced workloads that require specific kernel-level access may not work. For details about which workloads are affected, see [ECI limitations](limitations.md).

## Why not just restrict usage of the `--privileged` flag?

Privileged containers serve legitimate purposes like Docker-in-Docker, Kubernetes-in-Docker, and accessing hardware devices. ECI provides a better solution by allowing these advanced workloads to run securely while preventing them from compromising the Docker Desktop VM.

## Does ECI affect container performance?

ECI has minimal impact on container performance. The only exception is containers that perform many `mount` and `umount` system calls, as these are inspected by the Sysbox runtime for security. Most development workloads see no noticeable performance difference.

## Can I override the container runtime with ECI turned on?


No. When ECI is turned on, all containers use the Sysbox runtime regardless of any `--runtime` flags:

```console
$ docker run --runtime=runc alpine echo "test"
# This still uses sysbox-runc, not runc
```

The `--runtime` flag is ignored to prevent users from bypassing ECI security by running containers as true root in the Docker Desktop VM.

## Does ECI protect containers created before turning it on?

No. ECI only protects containers created after it's turned on. Remove existing containers before turning on ECI:

```console
$ docker stop $(docker ps -q)
$ docker rm $(docker ps -aq)
```

For more details, see [Enable Enhanced Container Isolation](enable-eci.md).

## Which containers does ECI protect?

ECI protection varies by container type and Docker Desktop version:

### Always protected

- Containers created with `docker run` and `docker create`
- Containers using the `docker-container` build driver
- Kubernetes with the `kind` provisioner

### Platform dependent

- Docker Build: Protected in Docker Desktop for Mac, Linux, and Windows with Hyper-V backend

### Not protected

- Docker Extensions
- Docker Debug containers
- Kubernetes with `kubeadm` provisioner

For complete details, see [ECI limitations](limitations.md).

## Can I mount the Docker socket with ECI turned on?

By default, no. ECI blocks Docker socket bind mounts for security. However, you can configure exceptions for trusted images like Testcontainers.

For configuration details, see [Configure Docker socket exceptions](config.md).

## What bind mounts does ECI restrict?

ECI restricts bind mounts of Docker Desktop VM directories but allows host directory mounts configured in Docker Desktop Settings.


---

# Enhanced Container Isolation limitations

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

Enhanced Container Isolation has some platform-specific limitations and feature constraints. Understanding these limitations helps you plan your security strategy and set appropriate expectations.

## WSL 2 security considerations

> [!NOTE]
>
> Docker Desktop requires WSL 2 version 2.1.5 or later. ECI on the WSL 2 backend
> requires WSL version 2.6 or later because ECI depends on a Linux kernel version
> of at least 6.3.0. Check your version with `wsl --version` and update with
> `wsl --update` if needed.

Enhanced Container Isolation provides different security levels depending on your Windows backend configuration.

The following table compares ECI on WSL 2 and ECI on Hyper-V:

| Security feature                                   | ECI on WSL   | ECI on Hyper-V   | Comment               |
| -------------------------------------------------- | ------------ | ---------------- | --------------------- |
| Strongly secure containers                         | Yes          | Yes              | Makes it harder for malicious container workloads to breach the Docker Desktop Linux VM and host. |
| Docker Desktop Linux VM protected from user access | No           | Yes              | On WSL, users can access Docker Engine directly or bypass Docker Desktop security settings. |
| Docker Desktop Linux VM has a dedicated kernel     | No           | Yes              | On WSL, Docker Desktop can't guarantee the integrity of kernel level configs. |

WSL 2 security gaps include:

- Direct VM access: Users can bypass Docker Desktop security by accessing the VM directly: `wsl -d docker-desktop`. This gives users root access to modify Docker Engine settings and bypass
Settings Management configurations.
- Shared kernel vulnerability: All WSL 2 distributions share the same Linux kernel instance. Other WSL distributions can modify kernel settings that affect Docker Desktop's security.

### Recommendation

Use Hyper-V backend for maximum security. WSL 2 offers better performance and resource
utilization, but provides reduced security isolation.

## Windows containers not supported

ECI only works with Linux containers (Docker Desktop's default mode). Native Windows
containers mode isn't supported.

## Docker Build protection varies

Docker Build protection depends on the driver and Docker Desktop version:

| Build drive | Protection | Version requirements |
|:------------|:-----------|:---------------------|
| `docker` (default) | Protected | Docker Desktop 4.30 and later (except WSL 2) |
| `docker` (legacy) | Not protected | Docker Desktop versions before 4.30 |
| `docker-container` | Always protected | All Docker Desktop versions |

The following Docker Build features don't work with ECI:

- `docker build --network=host`
- Docker Buildx entitlements: `network.host`, `security.insecure`

### Recommendation

Use `docker-container` build driver for builds requiring these features:

```console
$ docker buildx create --driver docker-container --use
$ docker buildx build --network=host .
```

## Docker Desktop Kubernetes not protected in Kubeadm mode

The integrated Kubernetes feature, when used with the legacy Kubeadm provisioner, doesn't benefit from ECI protection. Malicious or privileged pods can compromise the Docker Desktop VM and bypass security controls.

### Recommendation

Use the Docker Desktop Kubernetes `kind` provisioner (see [Cluster provisioning method](../../../../desktop/use-desktop/kubernetes.md#cluster-provisioning-method)). In this mode, and with ECI turned on, each Kubernetes node runs in an ECI-protected container, providing stronger isolation from the Docker Desktop VM. The `kind` provisioner is also faster and allows for multi-node Kubernetes clusters.

## Unprotected container types

These container types currently don't benefit from ECI protection:

- Docker Extensions: Extension containers run without ECI protection
- Kubernetes pods: When using Docker Desktop's integrated Kubernetes with the old Kubeadm provisioner.

### Recommendation

Only use extensions from trusted sources in security-sensitive environments.

## Global command restrictions

Command lists apply to all containers allowed to mount the Docker socket. You can't configure different command restrictions per container image.

## Local-only images not supported

You can't allow arbitrary local-only images (images not in a registry) to mount the Docker socket, unless they're:

- Derived from an allowed base image (with `allowDerivedImages: true`)
- Using the wildcard allowlist (`"*"`, Docker Desktop 4.36 and later)

## Unsupported Docker commands

These Docker commands aren't yet supported in command list restrictions:

- `compose`: Docker Compose commands
- `dev`: Development environment commands
- `extension`: Docker Extensions management
- `feedback`: Docker feedback submission
- `init`: Docker initialization commands
- `manifest`: Image manifest management
- `plugin`: Plugin management
- `sbom`: Software Bill of Materials
- `scout`: Docker Scout commands
- `trust`: Image trust management

## Performance considerations

### Derived images impact

Enabling `allowDerivedImages: true` adds approximately 1 second to container startup time for image validation.

### Registry dependencies

- Docker Desktop periodically fetches image digests from registries for validation
- Initial container starts require registry access to validate allowed images
- Network connectivity issues may cause delays in container startup

### Image digest validation

When allowed images are updated in registries, local containers may be unexpectedly blocked until you refresh the local image:

```console
$ docker image rm <image>
$ docker pull <image>
```

## Production compatibility

### Container behavior differences

Most containers run identically with and without ECI. However, some advanced workloads may behave differently:

- Containers requiring kernel module loading
- Workloads modifying global kernel settings (BPF, sysctl)
- Applications expecting specific privilege escalation behavior
- Tools requiring direct hardware device access

Test advanced workloads with ECI in development environments before production deployment to ensure compatibility.

### Runtime considerations

Containers using the Sysbox runtime (with ECI) may have subtle differences compared to standard OCI runc runtime in production. These differences typically only affect privileged or system-level operations.


---

# Image Access Management

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

Image Access Management lets administrators control which types of images developers can pull from Docker Hub. This prevents developers from accidentally using untrusted community images that could pose security risks to your organization.

With Image Access Management, you can restrict access to:

- Docker Official Images: Curated images maintained by Docker
- Docker Verified Publisher Images: Images from trusted commercial publishers
- Organization images: Your organization's private repositories
- Community images: Public images from individual developers

You can also use a repository allowlist to approve specific repositories that bypass all other access controls.

## Who should use Image Access Management?

Image Access Management helps prevent supply chain attacks by ensuring developers only use trusted container images. For example, a developer building a new application might accidentally use a malicious community image as a component. Image Access Management prevents this by restricting access to only approved image types.

Common security scenarios include:

- Prevent use of unmaintained or malicious community images
- Ensure developers use only vetted, official base images
- Control access to commercial third-party images
- Maintain consistent security standards across development teams

Use the repository allowlist when you need to:

- Grant access to specific vetted community images
- Allow essential third-party tools that don't fall under official categories
- Provide exceptions to general image access policies for specific business requirements

## Prerequisites

Before configuring Image Access Management, you must:

- [Enforce sign-in](../enforce-sign-in/index.md). Image Access Management only takes effect when users are signed in to Docker Desktop with organization credentials.
- Use [personal access tokens (PATs)](../../../security/access-tokens/personal-access-tokens.md) for authentication (Organization access tokens aren't supported)
- Have a Docker Business subscription

## Configure image access

> [!NOTE]
>
> Image Access Management is turned off by default for organization members. Organization owners always have access to all images regardless of policy settings.

To configure Image Access Management:

1. Sign in to [Docker Home](https://app.docker.com) and select your organization from the top-left account drop-down.
1. Select **Docker Desktop**, then **Image Access**.
1. Use the **toggle** to enable image access.
1. Select which image types to allow:
    - **Organization images**: Images from your organization (always allowed by default). These can be public or private images created by members within your organization.
    - **Community images**: Images contributed by various users that may pose security risks. This category includes Docker-Sponsored Open Source images and is turned off by default.
    - **Docker Verified Publisher Images**: Images from Docker partners in the Verified Publisher program, qualified for secure supply chains.
    - **Docker Official Images**: Curated Docker repositories that provide OS repositories, best practices for Dockerfiles, drop-in solutions, and timely security updates.
    - **Repository allowlist**: A list of specific repositories that should be
      allowed. Configure in the next step.
1. If **Repository allowlist** is enabled in the previous step,
   you can add or remove specific repositories in the allow list:
    - To add repositories, in the **Repository allowlist** section, select
      **Add repositories to allowlist** and follow the on-screen instructions.
    - To remove a repository, in the **Repository allowlist** section, select
      the trashcan icon next to it.

    Repositories in the allow list are accessible to all organization members regardless of the image type restrictions configured in the previous steps.

After restrictions are applied, organization members can view the permissions page in read-only format.

## Verify access restrictions

After configuring Image Access Management, test that restrictions work correctly.

When developers pull allowed image types:

```console
$ docker pull nginx  # Docker Official Image
# Pull succeeds if Docker Official Images are allowed
```

When developers pull blocked image types:

```console
$ docker pull someuser/custom-image  # Community image
Error response from daemon: image access denied: community images not allowed
```

Image access restrictions apply to all Docker Hub operations including pulls, builds using `FROM` instructions, and Docker Compose services.

## Best practices

- Start with the most restrictive policy and gradually expand based on legitimate business needs:
   1. Start with Docker Official Images and Organization images
   2. If needed, add Docker Verified Publisher Images for commercial tools
   3. Carefully evaluate community images only for specific, vetted use cases
   4. Use the repository allowlist sparingly. Only add repositories that have been thoroughly vetted and approved through your organization's security review process
- Monitor usage patterns: Review which images developers are attempting to pull, identify legitimate requests for additional image types, regularly audit approved image categories for continued relevance, and use Docker Desktop analytics to monitor usage patterns.
- Regularly review the repository allow list: Periodically audit the repositories in your allowlist to ensure they remain necessary and trustworthy, and remove any that are no longer needed or maintained.

## Scope and bypass considerations

- Image Access Management only controls access to Docker Hub images. Images from other registries aren't affected by these policies. Use [Registry Access Management](registry-access-management.md) to control access to other registries.
- Users can potentially bypass Image Access Management by signing out of Docker Desktop (unless sign-in is enforced), using images from other registries that aren't restricted, or using registry mirrors or proxies. Enforce sign-in and combine with Registry Access Management for comprehensive control.
- Image restrictions apply to Dockerfile `FROM` instructions, Docker Compose services using restricted images will fail, multi-stage builds may be affected if intermediate images are restricted, and CI/CD pipelines using diverse image types may be impacted.

## Next steps

- Layer security controls: Image Access Management works best with [Registry Access Management](registry-access-management.md) to control which registries developers can access, [Enhanced Container Isolation](enhanced-container-isolation/index.md) to secure containers at runtime, and [Settings Management](settings-management/index.md) to control Docker Desktop configuration.


---

# Namespace access control

*Sección: Enterprise*

{{< summary-bar feature_name="Namespace access" >}}

Namespace access control lets organization administrators control whether all
members of an organization can push content to their personal namespaces on
Docker Hub. This prevents organizations from accidentally publishing images
outside of approved, governed locations.

When namespace access control is enabled, organization members can still view and pull images
from their personal namespaces and continue accessing all existing repositories
and content. However, they're unable to create new repositories or
push new images to their personal namespace.

> [!IMPORTANT]
>
> For users in multiple organizations, if namespace access control is enabled in
> any organization, that user cannot push to their personal namespace and cannot
> create new repositories in their personal namespace.

### Configure namespace access control

To configure namespace access control:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization from the top-left account drop-down.
2. Select **Docker Desktop**, then **Namespace access**.
3. Use the toggle to enable or disable namespace access control.
4. Select **Save changes**.

Once namespace access control is enabled, organization members can still view their
personal namespace and existing repositories but they are not able to create
any new repositories or push any new images to existing repositories.

### Verify access restrictions

After configuring namespace access control, test that restrictions work correctly.

After any attempt to push to an existing repository in your personal namespace,
you'll see an error message like the following:

```console
$ docker push <personal-namespace>/<image>:<tag>
Unavailable
authentication required - namespace access restriction from an organization you belong to prevents pushing new content in your personal namespace. Restriction applied by: <organizations>. Please contact your organization administrator
```


---

# Registry Access Management

*Sección: Enterprise*

{{< summary-bar feature_name="Registry access management" >}}

Registry Access Management (RAM) lets administrators control which container
registries developers can access through Docker Desktop. This DNS-level
filtering limits pulls and pushes to approved registries.

RAM works with cloud registries, on-premises registries, and registry mirrors.
You can allow any hostname or domain, but you must also include redirect
domains (for example, `s3.amazonaws.com` for some registries) in your
allowlist.

## Supported registries

Registry Access Management works with any container registry, including:

- Docker Hub (allowed by default)
- Cloud registries: Amazon ECR, Google Artifact Registry, Azure Container
  Registry
- Git-based registries: GitHub Container Registry, GitLab Container Registry
- On-premises solutions: Nexus, Artifactory, Harbor
- Registry mirrors: Including Docker Hub mirrors

## Prerequisites

Before configuring Registry Access Management, you must:

- [Enforce sign-in](../enforce-sign-in/index.md).
  Registry Access Management only takes effect when users are signed in to
  Docker Desktop with organization credentials.
- Use
  [Organization access tokens (OATs)](../../../security/access-tokens/organization-access-tokens.md)
  for authentication
- Have a Docker Business subscription

## Configure registry permissions

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization from the top-left account drop-down.
1. Select **Docker Desktop**, then **Registry Access**.
1. Use the toggle to turn on registry access. By default, Docker Hub is
   enabled in the registry list.
1. To add registries, select **Add registry** and provide a **Registry
   address** and **Registry nickname**.
1. Select **Create**. You can add up to 100 registries.
1. Verify your registry appears in the registry list and select **Save
   changes**.

> [!NOTE]
>
> Policy changes can take up to 24 hours to propagate. To apply changes
> immediately, ask developers to sign out and back in to Docker Desktop.

If a developer belongs to multiple organizations with different RAM policies,
only the policy for the first organization in the configuration file is
enforced.

> [!TIP]
>
> RAM restrictions also apply to Dockerfile `ADD` instructions that fetch
> content by URL. Include trusted registry domains in your allowlist when
> using `ADD` with URLs.
>
> RAM is designed for container registries, not general-purpose URLs such as
> package mirrors or storage services. Adding too many domains may cause
> errors or hit system limits.

## Verify restrictions are working

After users sign in to Docker Desktop with their organization credentials,
Registry Access Management takes effect immediately.

When users try to pull from a blocked registry:

```console
$ docker pull blocked-registry.com/image:tag
Error response from daemon: registry access to blocked-registry.com is not allowed
```

Allowed registry access works normally:

```console
$ docker pull allowed-registry.com/image:tag
# Pull succeeds
```

Registry restrictions apply to all Docker operations including pulls, pushes,
and builds that reference external registries.

## Registry limits and platform constraints

Registry Access Management has these limits and platform-specific behaviors:

- Maximum allowlist size: 100 registries or domains per organization
- DNS-based filtering: Restrictions work at the hostname level, not IP
  addresses
- Redirect domains required: Include all domains a registry redirects to (CDN
  endpoints, storage services)
- Windows containers: Windows image operations aren't restricted by default.
  Turn on **Use proxy for Windows Docker daemon** in Docker Desktop settings
  to apply restrictions
- WSL 2 requirements: Requires Linux kernel 5.4 or later. Restrictions apply
  to all WSL 2 distributions

## Build and deployment restrictions

These scenarios aren't restricted by Registry Access Management:

- Docker Buildx with the Kubernetes driver
- Docker Buildx with a custom Docker-container driver
- Some Docker Debug and Kubernetes image pulls (even if Docker Hub is blocked)
- Images previously cached by registry mirrors may still be blocked if the
  source registry is restricted

## Security bypass considerations

Users can potentially bypass Registry Access Management through:

- Local proxies or DNS manipulation
- Signing out of Docker Desktop (unless sign-in is enforced)
- Network-level modifications outside Docker Desktop's control

To maximize security effectiveness:

- [Enforce sign-in](../enforce-sign-in/index.md) to
  prevent bypass through sign-out
- Implement additional network-level controls for complete protection
- Use Registry Access Management as part of a broader security strategy

## Registry allowlist best practices

- Include all registry domains. Some registries redirect to multiple domains.
  For AWS ECR, include:

  ```text
  your-account.dkr.ecr.us-west-2.amazonaws.com
  amazonaws.com
  s3.amazonaws.com
  ```

- Maintain the allowlist regularly:
  - Remove unused registries periodically
  - Add newly approved registries as needed
  - Update domain names that may have changed
  - Monitor registry usage through Docker Desktop analytics
- Test configuration changes:
  - Verify registry access after allowlist updates
  - Confirm all necessary redirect domains are included
  - Ensure development workflows aren't disrupted
- Combine with
  [Enhanced Container Isolation](enhanced-container-isolation/index.md)
  for broader Desktop security


---

# Settings Management

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

Settings Management lets administrators configure and enforce Docker Desktop settings across end-user machines. It helps maintain consistent configurations and enhances security within your organization.

## Who should use Settings Management?

Settings Management is designed for organizations that:

- Need centralized control over Docker Desktop configurations
- Want to standardize Docker Desktop environments across teams
- Operate in regulated environments and must enforce compliance policies

## How Settings Management works

Administrators can define settings using one of these methods:

- [Docker Home](configure-admin-console.md): Create and assign settings policies via Docker Home. This provides a web-based interface for managing settings
  across your organization.
- [`admin-settings.json` file](configure-json-file.md): Place a configuration file on the
  user's machine to enforce settings. This method works well for automated
  deployments and scripted installations.

Enforced settings override user-defined configurations and can't be modified by developers.

## Configurable settings

Settings Management supports a wide range of Docker Desktop features, including:

- Proxy configurations
- Network settings
- Container isolation options
- Registry access controls
- Resource limits
- Security policies
- Cloud policies

For a complete list of settings you can enforce, see the [Settings reference](settings-reference.md).

## Policy precedence

When multiple policies exist, Docker Desktop applies them in this order:

1. User-specific policies: Highest priority
1. Organization default policy: Applied when no user-specific policy exists
1. Local `admin-settings.json` file: Lowest priority, overridden by Docker Home policies
1. [Configuration profiles](../../enforce-sign-in/methods.md#configuration-profiles-method-mac-only) when used to control proxy settings

## Set up Settings Management

You can create settings management policies at any time, but your organization needs to verify a domain before the policies take effect.

1. Check that you have [added and verified](../../../../security/provisioning/domain-management.md#add-and-verify-a-domain) your organization's domain.
2. [Enforce sign-in](../../enforce-sign-in/index.md) to
   ensure all developers authenticate with your organization.
3. Choose a configuration method:
   - Use the `--admin-settings` installer flag on [macOS](../../../../desktop/setup/install/mac-install.md#install-from-the-command-line) or [Windows](../../../../desktop/setup/install/windows-install.md#install-from-the-command-line) to automatically create the `admin-settings.json`.
   - Manually create and configure the [`admin-settings.json` file](configure-json-file.md).
   - Create a settings policy in the [Docker Home](configure-admin-console.md).

After configuration, developers receive the enforced settings when they:

- Quit and relaunch Docker Desktop, then sign in
- Launch and sign in to Docker Desktop for the first time

> [!NOTE]
>
> Docker Desktop doesn't automatically prompt users to restart or re-authenticate after a settings change. You may need to communicate these requirements to your developers.

## Developer experience

When settings are enforced:

- Settings options appear grayed out in Docker Desktop and can't be modified through the Dashboard, CLI, or configuration files
- If Enhanced Container Isolation is enabled, developers can't use privileged containers or similar methods to alter enforced settings within the Docker Desktop Linux VM

This ensures consistent environments while maintaining a clear visual indication of which settings are managed by administrators.

## View applied settings

When administrators apply Settings Management policies, Docker Desktop greys out most enforced settings in the GUI.

The Docker Desktop GUI doesn't currently display all centralized settings,
particularly Enhanced Container Isolation (ECI) settings that administrators
apply via Docker Home.

As a workaround, you can check the `settings-store.json` file to view all
applied settings:

- Mac: `~/Library/Application Support/Docker/settings-store.json`
- Windows: `%APPDATA%\Docker\settings-store.json`
- Linux: `~/.docker/desktop/settings-store.json`

The `settings-store.json` file contains all settings, including those that
may not appear in the Docker Desktop GUI.

## Limitations

Settings Management has the following limitations:

- Doesn't work in air-gapped or offline environments
- Not compatible with environments that restrict authentication with Docker Hub

## Next steps

Get started with Settings Management:

- [Configure Settings Management with the `admin-settings.json` file](configure-json-file.md)
- [Configure Settings Management with Docker Home](configure-admin-console.md)


---

# Desktop settings reporting

*Sección: Enterprise*

{{< summary-bar feature_name="Compliance reporting" >}}

Desktop settings reporting tracks user compliance with Docker Desktop settings policies. Use this feature to monitor policy application across your organization and identify users who need assistance with compliance.

## Prerequisites

Before you can use Docker Desktop settings reporting, make sure you have:

- [Docker Desktop](../../../../desktop/release-notes.md) installed across your organization
- [A verified domain](../../../../security/authentication/single-sign-on/connect.md)
- [Enforced sign-in](../../enforce-sign-in/index.md) for your organization
- A Docker Business subscription
- At least one settings policy configured

## Access the reporting dashboard

To view compliance reporting:

1. Sign in to [Docker Home](https://app.docker.com) and select
your organization.
1. Select **Docker Desktop**, then **Settings Reporting**.

The reporting dashboard provides these tools:

- A search field to find users by username or email address
- Filter options to show users assigned to specific policies
- Toggles to hide or un-hide compliant users
- Compliance status indicators
- CSV export option to download compliance data

## User compliance statuses

Docker Desktop evaluates three types of status to determine overall compliance:

### Compliance status

This is the primary status shown in the dashboard:

| Compliance status | What it means |
|-------------------|---------------|
| Compliant | The user fetched and applied the latest assigned policy. |
| Non-compliant | The user fetched the correct policy, but hasn't applied it. |
| Outdated | The user fetched a previous version of the policy. |
| No policy assigned | The user does not have any policy assigned to them. |
| Uncontrolled domain | The user's email domain is not verified. |

### Domain status

Shows how the user's email domain relates to your organization:

| Domain status | What it means |
|---------------|---------------|
| Verified | The user’s email domain is verified. |
| Guest user | The user's email domain is not verified. |
| Domainless | Your organization has no verified domains, and the user's domain is unknown. |

### Settings status

Indicates the user's policy assignment:

| Settings status | What it means |
|-----------------|---------------|
| Global policy | The user is assigned your organization's default policy. |
| User policy | The user is assigned a specific custom policy. |
| No policy assigned | The user is not assigned to any policy. |

## Monitor compliance

From the **Desktop settings reporting** dashboard, you can:

- Review organization-wide compliance at a glance
- Turn on **Hide compliant users** to focus on issues
- Filter by specific policies to check targeted compliance
- Export compliance data
- Select any user's name for detailed status and resolution steps

When you select a user's name, you'll see their detailed compliance information including current status, domain verification, assigned policy, last policy fetch time, and Docker Desktop version.

## Resolve compliance issues

You can select a non-compliant user's name in the dashboard for recommended status resolution steps. The following sections are general resolution steps for non-compliant statuses:

### Non-compliant or outdated users

- Ask the user to fully quit and relaunch Docker Desktop
- Verify the user is signed in to Docker Desktop
- Confirm the user has Docker Desktop 4.40 or later

### Uncontrolled domain users

- Verify the user's email domain in your organization settings
- If the domain should be controlled, add and verify it, then wait for verification
- If the user is a guest and shouldn't be controlled, no action is needed

### No policy assigned users

- Assign the user to an existing policy
- Create a new user-specific policy for them
- Verify they're included in your organization's default policy scope

After users take corrective action, refresh the reporting dashboard to verify status changes.

## Policy update timing

Docker Desktop checks for policy updates:

- At startup
- Every 60 minutes while Docker Desktop is running
- When users restart Docker Desktop

Changes to policies in Docker Home are available immediately, but users must restart Docker Desktop to apply them.


---

# Configure Settings Management in Docker Home

*Sección: Enterprise*

{{< summary-bar feature_name="Admin Console" >}}

Use Docker Home to create and manage settings policies for Docker Desktop across your organization. Settings policies let you standardize configurations, enforce security requirements, and maintain consistent Docker Desktop environments.

## Prerequisites

Before you begin, make sure you have:

- [Docker Desktop](../../../../desktop/release-notes.md) installed
- [A verified domain](/security/authentication/single-sign-on/connect/#step-1-add-a-domain)
- [Enforced sign-in](../../enforce-sign-in/index.md) for your organization
- A Docker Business subscription

> [!IMPORTANT]
>
> You can create settings management policies at any time, but your organization needs to verify a domain before the policies take effect.

## Create a settings policy

To create a new settings policy:

1. Sign in to [Docker Home](https://app.docker.com/) and select
   your organization.
1. Select **Docker Desktop**, then **Settings Management**.
1. Select **Create a settings policy**.
1. Provide a name and optional description.

   > [!TIP]
   >
   > You can upload an existing `admin-settings.json` file to pre-fill the form.
   > Docker Home policies override local `admin-settings.json` files.

1. Choose who the policy applies to:
   - All users
   - Specific users

     > [!NOTE]
     >
     > User-specific policies override global default policies. Test your policy with a small group before applying it organization-wide.

1. Configure each setting using a state:

     | Docker Home state | Description                        | `admin-settings.json` equivalent   |
     | :------------------ | :--------------------------------- |:---------------------------------- |
     | **User-defined**    | Users can change the setting       | Omit the setting                   |
     | **Always enabled**  | Setting is on and locked           | `"value": true`, `"locked": true`  |
     | **Enabled**         | Setting is on but can be changed   | `"value": true`, `"locked": false` |
     | **Always disabled** | Setting is off and locked          | `"value": false`, `"locked": true` |
     | **Disabled**        | Setting is off but can be changed  | `"value": false`, `"locked": false`|

     > [!TIP]
     >
     > For a complete list of configurable settings, supported platforms, and configuration methods, see the [Settings reference](settings-reference.md).

1. Select **Create** to save your policy.

## Apply the policy

Settings policies take effect after Docker Desktop restarts and users sign in.

For new installations:

1. Launch Docker Desktop.
1. Sign in with your Docker account.

For existing installations:

1. Quit Docker Desktop completely.
1. Relaunch Docker Desktop.

> [!IMPORTANT]
>
> Users must fully quit and reopen Docker Desktop. Restarting from the Docker Desktop menu isn't sufficient.

Docker Desktop checks for policy updates when it launches and every 60 minutes while running.

## Verify applied settings

After you apply policies:

- Docker Desktop displays most settings as greyed out
- Some settings, particularly Enhanced Container Isolation configurations,
  may not appear in the GUI
- You can verify all applied settings by checking the [`settings-store.json`
  file](../../../../desktop/settings-and-maintenance/settings.md) on your system

## Manage existing policies

From the **Desktop Settings Management** page in Docker Home, use the **Actions** menu to:

- Edit or delete an existing settings policy
- Export a settings policy as an `admin-settings.json` file
- Promote a user-specific policy to be the new global default

## Roll back policies

To roll back a settings policy:

- Complete rollback: Delete the entire policy.
- Partial rollback: Set specific settings to **User-defined**.

When you roll back settings, users regain control over those settings configurations.


---

# Configure Settings Management with a JSON file

*Sección: Enterprise*

{{< summary-bar feature_name="Hardened Docker Desktop" >}}

Settings Management lets you configure and enforce Docker Desktop settings across your organization using an `admin-settings.json` file. This standardizes Docker Desktop environments and ensures consistent configurations for all users.

## Prerequisites

Before you begin, make sure you have:

- [Enforce sign-in](../../enforce-sign-in/index.md) for
  your organization
- A Docker Business subscription

The presence of the `admin-settings.json` file enforces sign-in on Docker Desktop. This is intended for business features that require authentication.

Users must be signed in and part of a Docker Business organization. If either condition isn't met, the settings file is ignored.

## Step one: Create the settings file

You can create the `admin-settings.json` file in two ways:

- Use the `--admin-settings` installer flag to auto-generate the file:
  - [Mac](../../../../desktop/setup/install/mac-install.md#install-from-the-command-line) installation guide
  - [Windows](../../../../desktop/setup/install/windows-install.md#install-from-the-command-line) installation guide
- Create it manually (UTF-8 without BOM) and place it in the following locations:
  - Mac: `/Library/Application Support/com.docker.docker/admin-settings.json`
  - Windows: `C:\ProgramData\DockerDesktop\admin-settings.json`
  - Linux: `/usr/share/docker-desktop/admin-settings.json`

> [!IMPORTANT]
>
> Place the file in a protected directory to prevent unauthorized changes. Use Mobile Device Management (MDM) tools like Jamf to distribute the file at scale across your organization.

## Step two: Configure settings

> [!TIP]
>
> For a complete list of available settings, their supported platforms, and which configuration methods they work with, see the [Settings reference](settings-reference.md).

The `admin-settings.json` file uses structured keys to define configurable settings and whether values are enforced.

Each setting supports a `locked` field that controls user permissions:

- When `locked` is set to `true`, users can't change that value in Docker Desktop, the CLI, or config files.
- When `locked` is set to `false`, the value acts like a default suggestion and users
  can still update it.

Settings where `locked` is set to `false` are ignored on existing installs if
a user has already customized that value in `settings-store.json`,
`settings.json`, or `daemon.json`.

### Grouped settings

Docker Desktop groups some settings together with a single toggle that controls
the entire section. These include:

- Enhanced Container Isolation (ECI): Uses a main toggle (`enhancedContainerIsolation`) that enables/disables the entire feature, with sub-settings for specific configurations
- Kubernetes: Uses a main toggle (`kubernetes.enabled`) with sub-settings for cluster configuration
- Docker Scout: Groups settings under the `scout` object

When configuring grouped settings:

1. Set the main toggle to enable the feature
1. Configure sub-settings within that group
1. When you lock the main toggle, users cannot modify any settings in that group

Example for `enhancedContainerIsolation`:

```json
"enhancedContainerIsolation": {
  "locked": true,  // This locks the entire ECI section
  "value": true,   // This enables ECI
  "dockerSocketMount": {  // These are sub-settings
    "imageList": {
      "images": ["docker.io/testcontainers/ryuk:*"]
    }
  }
}
```

### Example `admin-settings.json` file

The following sample is an `admin-settings.json` file with common enterprise settings configured. You can use this example as a template with the [`admin-settings.json` configurations](#admin-settingsjson-configurations):

```json {collapse=true}
{
  "configurationFileVersion": 2,
  "exposeDockerAPIOnTCP2375": {
    "locked": true,
    "value": false
  },
  "proxy": {
    "locked": true,
    "mode": "system",
    "http": "",
    "https": "",
    "exclude": [],
    "windowsDockerdPort": 65000,
    "enableKerberosNtlm": false,
    "pac": "",
    "embeddedPac": ""
  },
  "containersProxy": {
    "locked": true,
    "mode": "manual",
    "http": "",
    "https": "",
    "exclude": [],
    "pac": "",
    "embeddedPac": "",
    "transparentPorts": ""
  },
  "enhancedContainerIsolation": {
    "locked": true,
    "value": true,
    "dockerSocketMount": {
      "imageList": {
        "images": [
          "docker.io/localstack/localstack:*",
          "docker.io/testcontainers/ryuk:*"
        ]
      },
      "commandList": {
        "type": "deny",
        "commands": ["push"]
      }
    }
  },
  "linuxVM": {
    "wslEngineEnabled": {
      "locked": false,
      "value": false
    },
    "dockerDaemonOptions": {
      "locked": false,
      "value": "{\"debug\": false}"
    },
    "vpnkitCIDR": {
      "locked": false,
      "value": "192.168.65.0/24"
    }
  },
  "kubernetes": {
    "locked": false,
    "enabled": false,
    "showSystemContainers": false,
    "imagesRepository": ""
  },
  "windowsContainers": {
    "dockerDaemonOptions": {
      "locked": false,
      "value": "{\"debug\": false}"
    }
  },
  "disableUpdate": {
    "locked": false,
    "value": false
  },
  "analyticsEnabled": {
    "locked": false,
    "value": true
  },
  "extensionsEnabled": {
    "locked": true,
    "value": false
  },
  "scout": {
    "locked": false,
    "sbomIndexing": true,
    "useBackgroundIndexing": true
  },
  "allowBetaFeatures": {
    "locked": false,
    "value": false
  },
  "blockDockerLoad": {
    "locked": false,
    "value": true
  },
  "filesharingAllowedDirectories": [
    {
      "path": "$HOME",
      "sharedByDefault": true
    },
    {
      "path": "$TMP",
      "sharedByDefault": false
    }
  ],
  "useVirtualizationFrameworkVirtioFS": {
    "locked": true,
    "value": true
  },
  "useVirtualizationFrameworkRosetta": {
    "locked": true,
    "value": true
  },
  "useGrpcfuse": {
    "locked": true,
    "value": true
  },
  "displayedOnboarding": {
    "locked": true,
    "value": true
  },
  "desktopTerminalEnabled": {
    "locked": false,
    "value": false
  },
  "enableInference": {
    "locked": false,
    "value": true
  },
  "enableInferenceTCP": {
    "locked": false,
    "value": true
  },
  "enableInferenceTCPPort": {
    "locked": true,
    "value": 12434
  },
  "enableInferenceCORS": {
    "locked": true,
    "value": ""
  },
  "enableInferenceGPUVariant": {
    "locked": true,
    "value": true
  },
  "portBindingBehavior": {
    "locked": true,
    "value": "default-port-binding"
  }
}
```

## Step three: Apply the settings

Settings take effect after Docker Desktop restarts and the user signs in.

For new installations:

1. Launch Docker Desktop.
1. Sign in with your Docker account.

For existing installations:

1. Quit Docker Desktop completely.
1. Relaunch Docker Desktop.

> [!IMPORTANT]
>
> You must fully quit and reopen Docker Desktop. Restarting from the menu isn't sufficient.

## `admin-settings.json` configurations

The following tables describe all available settings in the `admin-settings.json` file.

> [!NOTE]
>
> Some settings are platform-specific or require minimum Docker Desktop versions. Check the Version column for requirements.

### General settings

| Parameter                  | OS           | Description                                                                                                                                                                                                      | Version                                |
| :------------------------- | ------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `configurationFileVersion` |              | Specifies the version of the configuration file format.                                                                                                                                                          |                                        |
| `analyticsEnabled`         |              | If `value` is set to false, Docker Desktop doesn't send usage statistics to Docker.                                                                                                                              |                                        |
| `disableUpdate`            |              | If `value` is set to true, checking for and notifications about Docker Desktop updates is disabled.                                                                                                              |                                        |
| `blockDockerLoad`          |              | If `value` is set to `true`, users are no longer able to run [`docker load`](/reference/cli/docker/image/load/) and receive an error if they try to.                                                             |                                        |
| `displayedOnboarding`      |              | If `value` is set to `true`, the onboarding survey will not be displayed to new users. Setting `value` to `false` has no effect.                                                                                 |  |
| `desktopTerminalEnabled`   |              | If `value` is set to `false`, developers cannot use the Docker terminal to interact with the host machine and execute commands directly from Docker Desktop.                                                     |                                        |
| `exposeDockerAPIOnTCP2375` | Windows only | Exposes the Docker API on a specified port. If `value` is set to true, the Docker API is exposed on port 2375. Note: This is unauthenticated and should only be enabled if protected by suitable firewall rules. |                                        |
| `silentModulesUpdate`      |              | If `value` is set to `true`, Docker Desktop automatically updates components that don't require a restart. For example, the Docker CLI or Docker Scout components.                                               | |

### Extensions

| Parameter                                     | OS  | Description                                                                                                                                                                                                    | Version |
| :-------------------------------------------- | --- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `extensionsEnabled`                           |     | If `value` is set to false, Docker Extensions are disabled.                                                                                                                                                    |         |
| `onlyMarketplaceExtensions`                   |     | If `value` is set to true, developers are blocked from installing other extensions via the command line.                                                                                                       |         |
| `extensionsPrivateMarketplace`                |     | If `value` is set to true, activates the private marketplace is enabled which ensures Docker Desktop connects to content defined and controlled by the administrator instead of the public Docker marketplace. |         |
| `extensionsPrivateMarketplaceAdminContactURL` |     | Defines a contact link for developers to request new extensions in the private marketplace.                                                                                                                    |         |

### File sharing and emulation

| Parameter                            | OS         | Description                                                                                                                                                                                                                                                                                                                                               | Version                                |
| :----------------------------------- | ---------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `filesharingAllowedDirectories`      |            | Specify which paths your developers can add file shares to. Also accepts `$HOME`, `$TMP`, or `$TEMP` as `path` variables. When a path is added, its subdirectories are allowed. If `sharedByDefault` is set to `true`, that path will be added upon factory reset or when Docker Desktop first starts.                                                    |                                        |
| `useVirtualizationFrameworkVirtioFS` | macOS only | If `value` is set to `true`, VirtioFS is set as the file sharing mechanism. Note: If both `useVirtualizationFrameworkVirtioFS` and `useGrpcfuse` have `value` set to `true`, VirtioFS takes precedence. If both are set to `false`, Docker Desktop fails to start with an error, as at least one file sharing mechanism must be enabled. |                                        |
| `useGrpcfuse`                        | macOS only | If `value` is set to `true`, gRPC Fuse is set as the file sharing mechanism.                                                                                                                                                                                                                                                                              |                                        |
| `useVirtualizationFrameworkRosetta`  | macOS only | If `value` is set to `true`, Docker Desktop turns on Rosetta to accelerate x86_64/amd64 binary emulation on Apple Silicon. Note: This also automatically enables `Use Virtualization framework`.                                                                                                                                                          |  |

### Docker Scout

| Parameter | OS  | Description                                                                                                                                                                                                                                                            | Version |
| :-------- | --- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `scout`   |     | Setting `useBackgroundIndexing` to `false` disables automatic indexing of images loaded to the image store. Setting `sbomIndexing` to `false` prevents users from being able to index image by inspecting them in Docker Desktop or using `docker scout` CLI commands. |         |

### Proxy settings

Docker Desktop has two distinct proxy settings with different scopes:

- `proxy` (App Proxy): Governs Docker Desktop host-level traffic — the Desktop application, Docker CLI, and extensions. It also serves as a fallback for the daemon when `containersProxy` is not explicitly configured. Once `containersProxy` is set, `proxy` plays no role in daemon or container traffic.
- [`containersProxy`](#container-proxy): Always governs `docker image pull`. All `docker image pull` and Compose pull operations go through `containersProxy`, including any PAC file rules. It also governs running container outbound traffic when `transparentPorts` is configured.

| Parameter            | OS           | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Version                                |
| :------------------- | ------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `proxy`              |              | If `mode` is set to `system` instead of `manual`, Docker Desktop gets the proxy values from the system and ignores any values set for `http`, `https` and `exclude`. Change `mode` to `manual` to manually configure proxy servers. If the proxy port is custom, specify it in the `http` or `https` property, for example `"https": "http://myotherproxy.com:4321"`. The `exclude` property specifies a comma-separated list of hosts and domains to bypass the proxy. |                                        |
| `windowsDockerdPort` | Windows only | Exposes Docker Desktop's internal proxy locally on this port for the Windows Docker daemon to connect to. If it is set to 0, a random free port is chosen. If the value is greater than 0, use that exact value for the port. The default value is -1 which disables the option.                                                                                                                                                                                        |                                        |
| `enableKerberosNtlm` |              | When set to `true`, Kerberos and NTLM authentication is enabled. Default is `false`. For more information, see the settings documentation.                                                                                                                                                                                                                                                                                                                              | |
| `pac`                |              | Specifies a PAC file URL. For example, `"pac": "http://proxy/proxy.pac"`.                                                                                                                                                                                                                                                                                                                                                                                               |                                        |
| `embeddedPac`        |              | Specifies an embedded PAC (Proxy Auto-config) script. For example, `"embeddedPac": "function FindProxyForURL(url, host) { return \"DIRECT\"; }"`. This setting takes precedence over HTTP, HTTPS, Proxy bypass and PAC server URL.                                                                                                                                                                                                                                      |  |

> [!NOTE]
>
> Proxy configuration is a special case because it must be configured in two places:
>
> 1. In Docker Home for your organization.
> 2. On the user's system where Docker Desktop is installed.
>
> On the user's machine, configure the proxy either through the `admin-settings.json` file or by using installer flags during Docker Desktop installation. For detailed instructions, refer to the [installation guide](../../../../desktop/setup/install/windows-install.md#proxy-configuration).
> 
> This additional configuration is required because Docker Desktop must know which proxy server to use before it can complete user sign-in and retrieve organization settings from Docker Home.

### Container proxy

| Parameter         | OS  | Description                                                                                                                                                                                                                                         | Version                                |
| :---------------- | --- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `containersProxy` |     | Configures the proxy for `docker image pull` (always enforced) and running container outbound traffic (enforced when `transparentPorts` is set). For more information see [Air-Gapped Containers](../air-gapped-containers.md). |  |
| `pac`             |     | Specifies a PAC file URL. For example, `"pac": "http://containerproxy/proxy.pac"`.                                                                                                                                                                  |                                        |
| `embeddedPac`     |     | Specifies an embedded PAC (Proxy Auto-config) script. For example, `"embeddedPac": "function FindProxyForURL(url, host) { return \"PROXY 192.168.92.1:2003\"; }"`. This setting takes precedence over HTTP, HTTPS, Proxy bypass and PAC server URL. |  |

### Linux VM settings

| Parameter                                        | OS           | Description                                                                                                                                                                                                                                                                                                | Version |
| :----------------------------------------------- | ------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `linuxVM`                                        |              | Parameters and settings related to Linux VM options - grouped together here for convenience.                                                                                                                                                                                                               |         |
| &nbsp; &nbsp; &nbsp; &nbsp;`wslEngineEnabled`    | Windows only | If `value` is set to true, Docker Desktop uses the WSL 2 based engine. This overrides anything that may have been set at installation using the `--backend=<backend name>` flag.                                                                                                                           |         |
| &nbsp; &nbsp; &nbsp; &nbsp;`dockerDaemonOptions` |              | If `value` is set to true, it overrides the options in the Docker Engine config file. See the [Docker Engine reference](/reference/cli/dockerd.md#daemon-configuration-file). Note that for added security, a few of the config attributes may be overridden when Enhanced Container Isolation is enabled. |         |
| &nbsp; &nbsp; &nbsp; &nbsp;`vpnkitCIDR`          |              | Overrides the network range used for vpnkit DHCP/DNS for `*.docker.internal`                                                                                                                                                                                                                               |         |

### Windows containers

| Parameter                                        | OS  | Description                                                                                                                                    | Version |
| :----------------------------------------------- | --- | :--------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `windowsContainers`                              |     | Parameters and settings related to `windowsContainers` options - grouped together here for convenience.                                        |         |
| &nbsp; &nbsp; &nbsp; &nbsp;`dockerDaemonOptions` |     | Overrides the options in the Linux daemon config file. See the [Docker Engine reference](/reference/cli/dockerd.md#daemon-configuration-file). |         |

> [!NOTE]
>
> This setting is not available to configure via Docker Home.

### Kubernetes settings

| Parameter    | OS  | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      | Version |
| :----------- | --- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `kubernetes` |     | If `enabled` is set to true, a Kubernetes single-node cluster is started when Docker Desktop starts. If `showSystemContainers` is set to true, Kubernetes containers are displayed in the Docker Desktop Dashboard and when you run `docker ps`. The [imagesRepository](../../../../desktop/use-desktop/kubernetes.md#configuring-a-custom-image-registry-for-kubernetes-control-plane-images) setting lets you specify which repository Docker Desktop pulls control-plane Kubernetes images from. |         |

> [!NOTE]
>
> When using `imagesRepository` with Enhanced Container Isolation (ECI), add these images to the [ECI Docker socket mount image list](#enhanced-container-isolation):
>
> `[imagesRepository]/desktop-cloud-provider-kind:`
> `[imagesRepository]/desktop-containerd-registry-mirror:`
>
> These containers mount the Docker socket, so you must add them to the ECI images list. Otherwise, ECI blocks the mount and Kubernetes won't start.

### Networking settings

| Parameter               | OS                          | Description                                                                                                                                                                                                                 | Version                                |
| :---------------------- | --------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| `defaultNetworkingMode` | Windows and Mac only        | Defines the default IP protocol for new Docker networks: `dual-stack` (IPv4 + IPv6, default), `ipv4only`, or `ipv6only`.                                                                                                    | |
| `dnsInhibition`         | Windows and Mac only        | Controls DNS record filtering returned to containers. Options: `auto` (recommended), `ipv4`, `ipv6`, `none`                                                                                                                 | |
| `portBindingBehavior`   | Linux-based containers only | Defines port binding restrictions and default behavior, allowing admins to control how a user exposes ports from their containers. Options: `default-port-binding`, `default-local-port-binding`, `local-only-port-binding` | Docker Desktop version 4.52 and later. |

For more information, see [Networking](/manuals/desktop/features/networking.md#networking-mode-and-dns-behaviour-for-mac-and-windows).

### AI settings

| Parameter                   | OS           | Description                                                                                                                                                                                                                        | Version |
| :-------------------------- | ------------ | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `enableInference`           |              | Setting `enableInference` to `true` enables [Docker Model Runner](../../../../ai/model-runner/index.md).                                                                                                                             |         |
| `enableInferenceTCP`        |              | Enable host-side TCP support. This setting requires the Docker Model Runner setting to be enabled first.                                                                                                                           |         |
| `enableInferenceTCPPort`    |              | Specifies the exposed TCP port. This setting requires the Docker Model Runner and Enable host-side TCP support settings to be enabled first.                                                                                       |         |
| `enableInferenceCORS`       |              | Specifies the allowed CORS origins. Empty string to deny all,`*` to accept all, or a list of comma-separated values. This setting requires the Docker Model Runner and Enable host-side TCP support settings to be enabled first.  |         |
| `enableInferenceGPUVariant` | Windows only | Setting `enableInferenceGPUVariant` to `true` enables GPU-backed inference. The additional components required for this don't come by default with Docker Desktop, therefore they will be downloaded to `~/.docker/bin/inference`. |         |

### Beta features

> [!IMPORTANT]
>
> For Docker Desktop versions 4.41 and earlier, some of these settings lived under the **Experimental features** tab on the **Features in development** page.

| Parameter                   | OS  | Description                                                                                                                                                                                                                                               | Version                                 |
| :-------------------------- | --- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
| `allowBetaFeatures`         |     | If `value` is set to `true`, beta features are enabled.                                                                                                                                                                                                   |                                         |
| `enableDockerAI`            |     | If `allowBetaFeatures` is true, setting `enableDockerAI` to `true` enables [Gordon](../../../../ai/gordon/index.md) by default. You can independently control this setting from the `allowBetaFeatures` setting.                                            |                                         |
| `enableDockerMCPToolkit`    |     | If `allowBetaFeatures` is true, setting `enableDockerMCPToolkit` to `true` enables the [MCP Toolkit feature](../../../../ai/mcp-catalog-and-toolkit/toolkit.md) by default. You can independently control this setting from the `allowBetaFeatures` setting. |                                         |
| `allowExperimentalFeatures` |     | If `value` is set to `true`, experimental features are enabled.                                                                                                                                                                                           |  |

### Enhanced Container Isolation

| Parameter                                                      | OS  | Description                                                                                                                                                                                                                                                                                                                                               | Version |
| :------------------------------------------------------------- | --- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `enhancedContainerIsolation`                                   |     | If `value` is set to true, Docker Desktop runs all containers as unprivileged, via the Linux user-namespace, prevents them from modifying sensitive configurations inside the Docker Desktop VM, and uses other advanced techniques to isolate them. For more information, see [Enhanced Container Isolation](../enhanced-container-isolation/index.md). |         |
| &nbsp; &nbsp; &nbsp; &nbsp;`dockerSocketMount`                 |     | By default, enhanced container isolation blocks bind-mounting the Docker Engine socket into containers (e.g., `docker run -v /var/run/docker.sock:/var/run/docker.sock ...`). This lets you relax this in a controlled way. See [ECI Configuration](../enhanced-container-isolation/config.md) for more info.                                             |         |
| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; `imageList`   |     | Indicates which container images are allowed to bind-mount the Docker Engine socket.                                                                                                                                                                                                                                                                      |         |
| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; `commandList` |     | Restricts the commands that containers can issue via the bind-mounted Docker Engine socket.                                                                                                                                                                                                                                                               |         |


---

# Settings reference

*Sección: Enterprise*

This reference documents Docker Desktop settings that administrators can configure using [Settings Management](index.md). Use this page to understand which settings are available, their accepted values, platform compatibility, and which configuration methods apply.
 
> [!NOTE]
>
> This page only covers configurable settings for administrators who are deploying Docker Desktop to their organization. For the full list of Docker Desktop user-facing settings, see [Change settings](../../../../desktop/settings-and-maintenance/settings.md).

## General

### Send usage statistics

Controls whether Docker Desktop collects and sends local usage statistics and crash reports to Docker. Does not affect server-side telemetry collected via Docker Hub or other backend services such
as sign in timestamps, pulls, or builds.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `analyticsEnabled` |
| Docker Home | **Send usage statistics** |

> [!NOTE]
>
> Organizations using the Insights Dashboard may need this setting enabled to
ensure that developer activity is fully visible. If users opt out and the
setting is not locked, their activity may be excluded from analytics
views.

### Automatically check for updates

Controls whether Docker Desktop checks for and notifies users about available updates. When set to `true`, update checks and notifications are disabled.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `disableUpdate` |
| Docker Home | **Disable update** |

> [!NOTE]
>
> In hardened environments, enable this setting and lock it. This guarantees that
only internally vetted versions are installed.

### Automatically update components

Allows Docker Desktop to automatically update components that do not require a restart, such as Docker Compose, Docker Scout, and the Docker CLI.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `silentModulesUpdate` |
| Docker Home | **Automatically update components** |

### Enable Gordon

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values (individuals) | `true`, `false` |
| Accepted values (Business tier) | `"Disabled"`, `"Enabled"`, `"Always Enabled"` |
| JSON key | `enableDockerAI` |
| Docker Home | **Enable Gordon** |

> [!IMPORTANT]
>
> Docker Business customers must set this to `"Enabled"` or `"Always Enabled"` in Docker Home. Setting to `"User Defined"` alone will not activate Gordon.

### Block `docker load`

Prevents users from loading local Docker images using the `docker load` command, enforcing image provenance by requiring all images to come from registries.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `blockDockerLoad` |
| Docker Home | **Block Docker Load** |

> [!NOTE]
>
> In hardened environments, enable and lock this setting. This forces all images
to come from your secure, scanned registry.

### Hide onboarding survey

Prevents the onboarding survey from being shown to new users.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `displayedOnboarding` |
| Docker Home | **Hide onboarding survey** |

### Enable Docker terminal

Allows or restricts access to the built-in terminal for host system interaction. When set to `false`, users cannot use the Docker terminal to interact with the host machine or execute commands directly from Docker Desktop.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| Docker Desktop GUI | **General** tab |
| JSON key | `desktopTerminalEnabled` |
| Docker Home | Not available |

### Expose Docker API on TCP 2375 {{< badge color=blue text="Windows only" >}}

Exposes the Docker API over an unauthenticated TCP socket on port 2375. Only recommended for isolated and protected environments. Supports legacy integrations that require TCP API access.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `exposeDockerAPIOnTCP2375` |
| Docker Home | **Expose Docker API** |

> [!NOTE]
>
> In hardened environments, disable and lock this setting. This ensures the
Docker API is only reachable via the secure internal socket.

## Extensions 

### Enable Docker extensions

Controls whether users can install and run Docker Extensions.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `extensionsEnabled` |
| Docker Home | **Allow Extensions** |

> [!NOTE]
>
> In hardened environments, disable and lock this setting. This prevents
third-party or unverified plugins from being installed.

### Allow only extensions distributed through the Docker Marketplace

Prevents installation of third-party or locally developed extensions.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `onlyMarketplaceExtensions` |
| Docker Home | **Only marketplace extensions** |

### Enable a private marketplace

Ensures Docker Desktop connects to content defined and controlled by the administrator instead of the public Docker Marketplace.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `extensionsPrivateMarketplace` |
| Docker Home | **Extensions private marketplace** |

## AI

### Enable Docker Model Runner

Enables Docker Model Runner functionality for running AI models in containers.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `enableInference` |
| Docker Home | **Enable Docker Model Runner** |

#### Enable host-side TCP support

Enables TCP connectivity for Docker Model Runner services, allowing external applications to connect to Model Runner via TCP.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `enableInferenceTCP` |
| Docker Home | **Host-side TCP support** |
| Requires | Docker Model Runner enabled |

##### Port

Specifies the port used for Model Runner TCP connections.

| Property | Value |
|---|---|
| Default | `12434` |
| Accepted values | Integer |
| Format | Integer |
| JSON key | `enableInferenceTCPPort` |
| Docker Home | **Host-side TCP port** |
| Requires | Docker Model Runner and host-side TCP support enabled |

##### CORS Allowed Origins 

Controls cross-origin resource sharing for Model Runner web integration.

| Property | Value |
|---|---|
| Default | Empty string |
| Accepted values | Empty string (deny all), `*` (accept all), or comma-separated list of origins |
| Format | String |
| JSON key | `enableInferenceCORS` |
| Docker Home | **CORS Allowed Origins** |
| Requires | Docker Model Runner and host-side TCP support enabled |

### Enable GPU-backed inference {{< badge color=blue text="Windows only" >}}

Enables GPU-backed inference. Additional components will be downloaded to `~/.docker/bin/inference`.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `enableInferenceGPUVariant` |
| Docker Home | **Enable GPU-backed inference** |

## File sharing and emulation 

### File sharing directories 

Defines which host directories containers can access for development workflows.

| Property | Value |
|---|---|
| Default | Varies by OS |
| Accepted values | List of file paths |
| Format | Array of strings |
| JSON key | `filesharingAllowedDirectories` |
| Docker Home | Yes — **Allowed file sharing directories** |

### VirtioFS {{< badge color=blue text="Mac only" >}}

Uses VirtioFS for fast, native file sharing between host and containers. If both VirtioFS and gRPC FUSE are set to `true`, VirtioFS takes precedence.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `useVirtualizationFrameworkVirtioFS` |
| Docker Home | **Use VirtioFS for file sharing** tab |

### gRPC FUSE {{< badge color=blue text="Mac only" >}}

Enables gRPC FUSE for macOS file sharing.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `useGrpcfuse` |
| Docker Home | **Use gRPC FUSE for file sharing** |

### Rosetta {{< badge color=blue text="Mac only" >}}

Uses Rosetta for x86_64/amd64 emulation on Apple Silicon.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `useVirtualizationFrameworkRosetta` |
| Docker Home | **Use Rosetta for x86_64/amd64 emulation on Apple Silicon** |

## Scout

### Enable Scout image analysis

Turns on vulnerability scanning and software bill of materials (SBOM) analysis for container images.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `sbomIndexing` |
| Docker Home | **SBOM indexing** |

### Enable background Scout SBOM indexing 

Keeps image metadata current by indexing during idle time or after image operations.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `useBackgroundIndexing` |
| Docker Home | **Background indexing** |

## Proxy

> [!NOTE]
>
> Proxy configuration is a special case because it must be configured in two places:
>
> 1. In the Docker Home for your organization.
> 2. On the user's system where Docker Desktop is installed.
>
> On the user's machine, configure the proxy either through the `admin-settings.json` file or by using installer flags during Docker Desktop installation. For detailed instructions, refer to the [installation guide](../../../../desktop/setup/install/windows-install.md#proxy-configuration).
> 
> This additional configuration is required because Docker Desktop must know which proxy server to use before it can complete user sign-in and retrieve organization settings from the Docker Home.

### Embedded PAC script 

Specifies an embedded Proxy Auto-Config (PAC) script. For example: `"embeddedPac": "function FindProxyForURL(url, host) { return \"DIRECT\"; }"`.

| Property | Value |
|---|---|
| Default | `""` |
| Accepted values | Embedded PAC script content |
| Format | String |
| JSON key | `embeddedPac` |
| Docker Home | Yes **Embedded PAC script** |

### PAC file URL 

Specifies a PAC file URL for Docker Desktop to use when routing network traffic. For example: `"pac": "http://proxy/proxy.pac"`.

| Property | Value |
|---|---|
| Default | `""` |
| Accepted values | PAC file URL |
| Format | String |
| JSON key | `pac` |
| Docker Home | **PAC file** |

### Override Windows "dockerd" port {{< badge color=blue text="Windows only" >}}

Exposes Docker Desktop's internal proxy locally on this port for the Windows Docker daemon to connect to. If it is set to 0, a random free port is chosen. If the value is greater than 0, use that exact value for the port.

| Property | Value |
|---|---|
| Default | `-1` |
| Accepted values | `-1` `0` |
| Format | String |
| JSON key | `windowsDockerdPort` |
| Docker Home | **Override Windows “dockerd” port** |

### Enable Kerberos and NTLM authentication 

Enables enterprise proxy authentication support for Kerberos and NTLM protocols.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `proxy.enableKerberosNtlm` |
| Docker Home | **Kerberos NTLM** |

### Proxy bypass

Defines network addresses that containers should bypass when using proxy settings.

| Property | Value |
|---|---|
| Default | `""` |
| Accepted values | List of addresses |
| Format | String |
| Docker Desktop GUI | **Proxies** tab |
| JSON key | `proxy` (with `manual` and `exclude` modes) |
| Docker Home | Yes — **Proxy** section |

## Containers proxy

### Air-gapped container proxy

Configures an HTTP/HTTPS proxy that governs two distinct traffic paths:

- Daemon image pulls (always enforced): Docker Desktop always injects `http.docker.internal:3128` as the daemon's proxy in `daemon.json` at VM startup. All `docker pull` and Compose pull operations are routed through `containersProxy`, including any PAC file rules. This applies regardless of whether `transparentPorts` is configured.
- Running container outbound traffic (opt-in): Container TCP traffic is only subject to `containersProxy` rules when `transparentPorts` is configured. Without it, running containers connect directly and PAC file rules do not apply to their outbound traffic.

> [!IMPORTANT]
>
> If you configure a PAC file under `containersProxy`, the PAC file must return an appropriate proxy server to connect to the registries where your images are hosted.

The [`proxy`](#proxy) setting governs Docker Desktop host-level traffic: the Desktop application, Docker CLI, and extensions. It serves as a fallback for the daemon only when `containersProxy` is not explicitly configured. Once `containersProxy` is set, `proxy` plays no role in daemon or container traffic.

| Property | Value |
|---|---|
| Default | See example below |
| Accepted values | JSON object |
| Format | JSON object |
| JSON key | `containersProxy` |
| Docker Home | **Containers proxy** section |

```json
"containersProxy": {
  "locked": true,
  "mode": "manual",
  "http": "",
  "https": "",
  "exclude": [],
  "pac": "",
  "transparentPorts": ""
}
```

For more information, see [Air-gapped containers](../air-gapped-containers.md).

## LinuxVM

### Enable WSL engine {{< badge color=blue text="Windows only" >}}

When set to `true`, Docker Desktop uses the WSL 2 based engine. Overrides any backend flag set at installation using `--backend=<backend name>`.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `wslEngineEnabled` |
| Docker Home | **Windows Subsystem for Linux (WSL) Engine** |

### Docker daemon options 

Overrides the Docker daemon configuration used in containers, without modifying local configuration files.

| Property | Value |
|---|---|
| Default | `{}` |
| Accepted values | JSON object |
| Format | Stringified JSON |
| JSON key | `linuxVM.dockerDaemonOptions` |
| Docker Home | **Docker Daemon options** in the LinuxVM dropdown |

### VPNKit CIDR {{< badge color=blue text="Mac only" >}}

Sets the network subnet used for Docker Desktop's internal VPNKit DHCP/DNS services. Prevents IP address conflicts in environments with overlapping network subnets.

| Property | Value |
|---|---|
| Default | `192.168.65.0/24` |
| Accepted values | CIDR notation |
| Format | String |
| JSON key | `vpnkitCIDR` |
| Docker Home | **VPNKit CIDR** |

## Windows containers

### Docker daemon options 

Overrides the Docker daemon configuration used in Windows containers, without modifying local configuration files.

| Property | Value |
|---|---|
| Default | `{}` |
| Accepted values | JSON object |
| Format | Stringified JSON |
| JSON key | `windowsContainers.dockerDaemonOptions` |
| Docker Home | **Docker Daemon options** in the **Windows containers dropdown** |

## Kubernetes

### Enable Kubernetes

Enables the local Kubernetes cluster integration with Docker Desktop.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `kubernetes` |
| Docker Home | **Enable Kubernetes** |

### Show system containers

Controls visibility of Kubernetes system containers in the Docker Desktop Dashboard.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| Docker Home | **Show system containers** |

### Kubernetes image repository 

Specifies a registry used for Kubernetes control plane images instead of Docker Hub. Overrides the `[registry[:port]/][namespace]` portion of image names. Images must be mirrored from Docker Hub with matching tags.

| Property | Value |
|---|---|
| Default | `""` |
| Accepted values | Registry URL |
| Format | String |
| JSON key | `KubernetesImagesRepository` |
| Docker Home | **Kubernetes Images Repository** |

> [!NOTE]
>
> Images must be mirrored from Docker Hub with matching tags. Required images depend on the cluster provisioning method.

> [!IMPORTANT]
>
> When using custom image repositories with Enhanced Container Isolation, add these images to the ECI allowlist: `[imagesRepository]/desktop-cloud-provider-kind:*` and `[imagesRepository]/desktop-containerd-registry-mirror:*`.

### Cluster provisioning method 

Controls Kubernetes cluster topology and node configuration.

| Property | Value |
|---|---|
| Default | `kubeadm` |
| Accepted values | `kubeadm`, `kind` |
| Format | String |
| Docker Home | **Kubernetes mode** |

### Node version

Pins the Kubernetes version used for cluster nodes.

| Property | Value |
|---|---|
| Default | `1.31.1` |
| Accepted values | Semantic version (e.g. `1.29.1`) |
| Format | String |
| Docker Home | **Node version** tab |

### Nodes count

Sets the number of nodes in multi-node Kubernetes clusters.

| Property | Value |
|---|---|
| Default | `1` |
| Accepted values | Integer |
| Format | Integer |
| Docker Home | **Nodes count** |

## Features in development

### Access beta features

Controls whether users can access all Docker Desktop features that are in public beta.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `allowBetaFeatures` |
| Docker Home | **Access beta features** |

### Enable Docker MCP Toolkit (Beta)

Enables [Docker MCP Toolkit](../../../../ai/mcp-catalog-and-toolkit/index.md) in Docker Desktop for AI model development workflows.

| Property | Value |
|---|---|
| Default | `true` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `enableDockerMCPToolkit` |
| Docker Home | Not available |

## Enhance container isolation

### Enable Enhanced Container Isolation 

Prevents containers from modifying Docker Desktop VM configuration or accessing sensitive host areas.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `enhancedContainerIsolation` |
| Docker Home | **Enable enhanced container isolation** |

### Docker socket access control (ECI exceptions)

Defines specific images and commands allowed to use the Docker socket when Enhanced Container Isolation is active. Supports tools like Testcontainers, LocalStack, or CI systems that need Docker socket access while maintaining security.

| Property | Value |
|---|---|
| Accepted values | JSON object |
| Format | JSON object |
| JSON key | ``dockerSocketMount` |
| Docker Home | **Image list**, **Command list** |

```json
"enhancedContainerIsolation": {
  "locked": true,
  "value": true,
  "dockerSocketMount": {
    "imageList": {
      "images": [
        "docker.io/localstack/localstack:*",
        "docker.io/testcontainers/ryuk:*"
      ]
    },
    "commandList": {
      "type": "deny",
      "commands": ["push"]
    }
  }
}
```

## Network

### Networking mode 

Sets the default IP protocol used when Docker creates new networks.

| Property | Value |
|---|---|
| Default | `dual-stack` |
| Accepted values | `ipv4only`, `ipv6only` |
| Format | String |
| JSON key | `defaultNetworkingMode` |
| Docker Home | **Default network IP mode** |

For more information, see [Networking](/manuals/desktop/features/networking.md#networking-mode-and-dns-behaviour-for-mac-and-windows).

### Inhibit DNS resolution for IPv4/IPv6 

Filters unsupported DNS record types to improve reliability in environments where only IPv4 or IPv6 is supported. Requires Docker Desktop 4.43 and later.

| Property | Value |
|---|---|
| Default | `auto` |
| Accepted values | `ipv4`, `ipv6`, `none` |
| Format | String |
| JSON key | `dnsInhibition` |
| Docker Home | **DNS filtering behavior** |

For more information, see [Networking](/manuals/desktop/features/networking.md#networking-mode-and-dns-behaviour-for-mac-and-windows).

### Port binding behavior

Specify how port bindings are handled for new containers.

| Property | Value |
|---|---|
| Default | `default-port-binding` |
| Accepted values | `default-local-port-binding`, `local-only-port-binding`, `default-port-binding` |
| Format | String |
| JSON key | `portBindingBehavior` |
| Docker Home | **Port binding behavior** |

## Other

### Enable Docker Offload 

Controls Docker Offload availability. When enabled, users see the Docker Offload toggle in the Docker Desktop header.

| Property | Value |
|---|---|
| Default | `false` |
| Accepted values | `true`, `false` |
| Format | Boolean |
| JSON key | `enableCloud` |
| Docker Home | **Enable Docker Offload** |

> [!NOTE]
>
> This setting is only available when Docker Offload capability is enabled for
> the organization.


---

# Docker Extensions

*Sección: Extensions*

Docker Extensions let you use third-party tools within Docker Desktop to extend its functionality.

You can seamlessly connect your favorite development tools to your application development and deployment workflows. Augment Docker Desktop with debugging, testing, security, and networking functionalities, and create custom add-ons using the Extensions [SDK](extensions-sdk/index.md).

Anyone can use Docker Extensions and there is no limit to the number of extensions you can install.

![Extensions Marketplace](/assets/images/extensions.webp)

## What extensions are available?

There is a mix of partner and community-built extensions and Docker-built extensions.
You can explore the list of available extensions in [Docker Hub](https://hub.docker.com/search?q=&type=extension) or in the Extensions Marketplace within Docker Desktop.

## Security and trust

Docker Extensions run with elevated privileges on your host machine. They have direct access to the Docker Engine, can read and write files on your filesystem, and can install and run native binaries. 

Docker reviews extensions submitted to the Marketplace, but does not guarantee the security of any extension. Extensions installed outside the Marketplace have not been reviewed at all. Only install extensions from publishers you trust. 

If you're an organization admin, see [Configure a private marketplace](private-marketplace.md) to control which extensions your team can install.


---

# Overview of the Extensions SDK

*Sección: Extensions*

> [!IMPORTANT]
>
> New submissions to the Docker Extensions Marketplace are paused while Docker reviews Marketplace security. You can still update existing extensions, and private Marketplace extensions are unaffected. Contact extensions@docker.com if you have additional questions.

The resources in this section help you create your own Docker extension.

The Docker CLI tool provides a set of commands to help you build and publish your extension, packaged as a 
specially formatted Docker image.

At the root of the image filesystem is a `metadata.json` file which describes the content of the extension. 
It's a fundamental element of a Docker extension.

An extension can contain a UI part and backend parts that run either on the host or in the Desktop virtual machine.
For further information, see [Architecture](architecture/index.md).

You distribute extensions through Docker Hub. However, you can develop them locally without the need to push 
the extension to Docker Hub. See [Extensions distribution](extensions/distribution.md) for further details.

{{% include "extensions-form.md" %}}

{{< grid >}}


---

# Extension architecture

*Sección: Extensions*

Extensions are applications that run inside the Docker Desktop. They're packaged as Docker images, distributed
through Docker Hub, and installed by users either through the Marketplace within the Docker Desktop Dashboard or the
Docker Extensions CLI.

Extensions can be composed of three (optional) components:
- A frontend (or User Interface): A web application displayed in a tab of the dashboard in Docker Desktop
- A backend: One or many containerized services running in the Docker Desktop VM
- Executables: Shell scripts or binaries that Docker Desktop copies on the host when installing the extension

![Overview of the three components of an extension](images/extensions-architecture.png?w=600h=400)

An extension doesn't necessarily need to have all these components, but at least one of them depending on the extension features. 
To configure and run those components, Docker Desktop uses a `metadata.json` file. See the
[metadata](metadata) section for more details.

## The frontend

The frontend is basically a web application made from HTML, Javascript, and CSS. It can be built with a simple HTML
file, some vanilla Javascript or any frontend framework, such as React or Vue.js.

When Docker Desktop installs the extension, it extracts the UI folder from the extension image, as defined by the 
`ui` section in the `metadata.json`. See the [ui metadata section](metadata.md#ui-section) for more details.

Every time users click on the **Extensions** tab, Docker Desktop initializes the extension's UI as if it was the first time. When they navigate away from the tab, both the UI itself and all the sub-processes started by it (if any) are terminated.

The frontend can invoke `docker` commands, communicate with the extension backend, or invoke extension executables
deployed on the host, through the [Extensions SDK](https://www.npmjs.com/package/@docker/extension-api-client).

> [!TIP]
>
> The `docker extension init` generates a React based extension. But you can still use it as a starting point for
> your own extension and use any other frontend framework, like Vue, Angular, Svelte, etc. or event stay with
> vanilla Javascript.

Learn more about [building a frontend](../build/frontend-extension-tutorial.md) for your extension.

## The backend

Alongside a frontend application, extensions can also contain one or many backend services. In most cases, the Extension does not need a backend, and features can be implemented just by invoking docker commands through the SDK. However, there are some cases when an extension requires a backend
	service, for example:
- To run long-running processes that must outlive the frontend
- To store data in a local database and serve them back with a REST API
- To store the extension state, like when a button starts a long-running process, so that if you navigate away
  from the extension and come back, the frontend can pick up where it left off
- To access specific resources in the Docker Desktop VM, for example by mounting folders in the compose
file

> [!TIP]
>
> The `docker extension init` generates a Go backend. But you can still use it as a starting point for
> your own extension and use any other language like Node.js, Python, Java, .Net, or any other language and framework.

Usually, the backend is made of one container that runs within the Docker Desktop VM. Internally, Docker Desktop creates
a Docker Compose project, creates the container from the `image` option of the `vm` section of the `metadata.json`, and
attaches it to the Compose project. See the [`vm` metadata section](metadata.md#vm-section) for more details.

In some cases, a `compose.yaml` file can be used instead of an `image`. This is useful when the backend container
needs more specific options, such as mounting volumes or requesting [capabilities](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities)
that can't be expressed just with a Docker image. The `compose.yaml` file can also be used to add multiple containers
needed by the extension, like a database or a message broker. 
Note that, if the Compose file defines many services, the SDK can only contact the first of them.

> [!NOTE]
>
> In some cases, it is useful to also interact with Docker Engine from the backend.
> See [How to use the Docker socket](../guides/use-docker-socket-from-backend.md) from the backend.

To communicate with the backend, the Extension SDK provides [functions](../dev/api/backend.md#get) to make `GET`,
`POST`, `PUT`, `HEAD`, and `DELETE` requests from the frontend. Under the hood, the communication is done through a socket
or named pipe, depending on the operating system. If the backend was listening to a port, it would be difficult to
prevent collision with other applications running on the host or in a container already. Also, some users are
running Docker Desktop in constrained environments where they can't open ports on their machines.

![Backend and frontend communication](images/extensions-arch-2.png?w=500h=300)

Finally, the backend can be built with any technology, as long as it can run in a container and listen on a socket.

Learn more about [adding a backend](../build/backend-extension-tutorial.md) to your extension.

## Executables

In addition to the frontend and the backend, extensions can also contain executables. Executables are binaries or shell scripts
that are installed on the host when the extension is installed. The frontend can invoke them with [the extension SDK](../dev/api/backend.md#invoke-an-extension-binary-on-the-host).

These executables are useful when the extension needs to interact with a third-party CLI tool, like AWS, `kubectl`, etc.
Shipping those executables with the extension ensure that the CLI tool is always available, at the right version, on
the users' machine.

When Docker Desktop installs the extension, it copies the executables on the host as defined by the `host` section in
the `metadata.json`. See the [`host` metadata section](metadata.md#host-section) for more details.

![Executable and frontend communication](images/extensions-arch-3.png?w=250h=300)

However, since they're executed on the users' machine, they have to be available to the platform they're running on.
For example, if you want to ship the `kubectl` executable, you need to provide a different version for Windows, Mac,
and Linux. Multi arch images will also need to include binaries built for the right arch (AMD / ARM)


See the [host metadata section](metadata.md#host-section) for more details.

Learn how to [invoke host binaries](../guides/invoke-host-binaries.md).


---

# Extension metadata

*Sección: Extensions*

## The metadata.json file

The `metadata.json` file is the entry point for your extension. It contains the metadata for your extension, such as the
name, version, and description. It also contains the information needed to build and run your extension. The image for
a Docker extension must include a `metadata.json` file at the root of its filesystem.

The format of the `metadata.json` file must be:

```json
{
    "icon": "extension-icon.svg",
    "ui": ...
    "vm": ...
    "host": ...
}
```

The `ui`, `vm`, and `host` sections are optional and depend on what a given extension provides. They describe the extension content to be installed.

### UI section

The `ui` section defines a new tab that's added to the dashboard in Docker Desktop. It follows the form:

```json
"ui":{
    "dashboard-tab":
    {
        "title":"MyTitle",
        "root":"/ui",
        "src":"index.html"
    }
}
```

`root` specifies the folder where the UI code is within the extension image filesystem.
`src` specifies the entrypoint that should be loaded in the extension tab.

Other UI extension points will be available in the future.

### VM section

The `vm` section defines a backend service that runs inside the Desktop VM. It must define either an `image` or a
`compose.yaml` file that specifies what service to run in the Desktop VM.

```json
"vm": {
    "image":"${DESKTOP_PLUGIN_IMAGE}"
},
```

When you use `image`, a default compose file is generated for the extension.

> `${DESKTOP_PLUGIN_IMAGE}` is a specific keyword that allows an easy way to refer to the image packaging the extension.
> It is also possible to specify any other full image name here. However, in many cases using the same image makes
> things easier for extension development.

```json
"vm": {
    "composefile": "compose.yaml"
},
```

The Compose file, with a volume definition for example, would look like:

```yaml
services:
  myExtension:
    image: ${DESKTOP_PLUGIN_IMAGE}
    volumes:
      - /host/path:/container/path
```

### Host section

The `host` section defines executables that Docker Desktop copies on the host.

```json
  "host": {
    "binaries": [
      {
        "darwin": [
          {
            "path": "/darwin/myBinary"
          },
        ],
        "windows": [
          {
            "path": "/windows/myBinary.exe"
          },
        ],
        "linux": [
          {
            "path": "/linux/myBinary"
          },
        ]
      }
    ]
  }
```

`binaries` defines a list of binaries Docker Desktop copies from the extension image to the host.

`path` specifies the binary path in the image filesystem. Docker Desktop is responsible for copying these files in its own location, and the JavaScript API allows invokes these binaries.

Learn how to [invoke executables](../guides/invoke-host-binaries.md).


---

# Extension security

*Sección: Extensions*

## Extension capabilities

An extension can have the following optional parts: 
* A user interface in HTML or JavaScript, displayed in Docker Desktop Dashboard
* A backend part that runs as a container
* Executables deployed on the host machine.

Extensions are executed with the same permissions as the Docker Desktop user. Extension capabilities include running any Docker commands (including running containers and mounting folders), running extension binaries, and accessing files on your machine that are accessible by the user running Docker Desktop.
Note that extensions are not restricted to execute binaries that they list in the [host section](metadata.md#host-section) of the extension metadata: since these binaries can contain any code running as user, they can in turn execute any other commands as long as the user has rights to execute them.

The Extensions SDK provides a set of JavaScript APIs to invoke commands or invoke these binaries from the extension UI code. Extensions can also provide a backend part that starts a long-lived running container in the background.

> [!IMPORTANT]
>
> Make sure you trust the publisher or author of the extension when you install it, as the extension has the same access rights as the user running Docker Desktop.


---

# Part one: Build

*Sección: Extensions*




---

# Add a backend to your extension

*Sección: Extensions*

Your extension can ship a backend part with which the frontend can interact with. This page provides information on why and how to add a backend.

Before you start, make sure you have installed the latest version of [Docker Desktop](https://www.docker.com/products/docker-desktop/).

> Tip
>
> Check the [Quickstart guide](../quickstart.md) and `docker extension init <my-extension>`. They provide a better base for your extension as it's more up-to-date and related to your install of Docker Desktop.

## Why add a backend?

Thanks to the Docker Extensions SDK, most of the time you should be able to do what you need from the Docker CLI
directly from [the frontend](frontend-extension-tutorial.md#use-the-extension-apis-client).

Nonetheless, there are some cases where you might need to add a backend to your extension. So far, extension
builders have used the backend to:
- Store data in a local database and serve them back with a REST API.
- Store the extension state, for example when a button starts a long-running process, so that if you navigate away from the extension user interface and comes back, the frontend can pick up where it left off.

For more information about extension backends, see [Architecture](../architecture/index.md#the-backend).

## Add a backend to the extension

If you created your extension using the `docker extension init` command, you already have a backend setup. Otherwise, you have to first create a `vm` directory that contains the code and updates the Dockerfile to
containerize it.

Here is the extension folder structure with a backend:

```bash
.
├── Dockerfile # (1)
├── Makefile
├── metadata.json
├── ui
    └── index.html
└── vm # (2)
    ├── go.mod
    └── main.go
```

1. Contains everything required to build the backend and copy it in the extension's container filesystem.
2. The source folder that contains the backend code of the extension.

Although you can start from an empty directory or from the `vm-ui extension` [sample](https://github.com/docker/extensions-sdk/tree/main/samples),
it is highly recommended that you start from the `docker extension init` command and change it to suit your needs.

> [!TIP]
>
> The `docker extension init` generates a Go backend. But you can still use it as a starting point for
> your own extension and use any other language like Node.js, Python, Java, .Net, or any other language and framework.

In this tutorial, the backend service simply exposes one route that returns a JSON payload that says "Hello".

```json
{ "Message": "Hello" }
```

> [!IMPORTANT]
>
> We recommend that, the frontend and the backend communicate through sockets, and named pipes on Windows, instead of
> HTTP. This prevents port collision with any other running application or container running
> on the host. Also, some Docker Desktop users are running in constrained environments where they
> can't open ports on their machines. When choosing the language and framework for your backend, make sure it
> supports sockets connection.

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"flag"
	"log"
	"net"
	"net/http"
	"os"

	"github.com/labstack/echo"
	"github.com/sirupsen/logrus"
)

func main() {
	var socketPath string
	flag.StringVar(&socketPath, "socket", "/run/guest/volumes-service.sock", "Unix domain socket to listen on")
	flag.Parse()

	os.RemoveAll(socketPath)

	logrus.New().Infof("Starting listening on %s\n", socketPath)
	router := echo.New()
	router.HideBanner = true

	startURL := ""

	ln, err := listen(socketPath)
	if err != nil {
		log.Fatal(err)
	}
	router.Listener = ln

	router.GET("/hello", hello)

	log.Fatal(router.Start(startURL))
}

func listen(path string) (net.Listener, error) {
	return net.Listen("unix", path)
}

func hello(ctx echo.Context) error {
	return ctx.JSON(http.StatusOK, HTTPMessageBody{Message: "hello world"})
}

type HTTPMessageBody struct {
	Message string
}
```

{{< /tab >}}
{{< tab name="Node" >}}

> [!IMPORTANT]
>
> We don't have a working example for Node yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=Node)
> and let us know if you'd like a sample for Node.

{{< /tab >}}
{{< tab name="Python" >}}

> [!IMPORTANT]
>
> We don't have a working example for Python yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=Python)
> and let us know if you'd like a sample for Python.

{{< /tab >}}
{{< tab name="Java" >}}

> [!IMPORTANT]
>
> We don't have a working example for Java yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=Java)
> and let us know if you'd like a sample for Java.

{{< /tab >}}
{{< tab name=".NET" >}}

> [!IMPORTANT]
>
> We don't have a working example for .NET. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=.Net)
> and let us know if you'd like a sample for .NET.

{{< /tab >}}
{{< /tabs >}}

## Adapt the Dockerfile

> [!NOTE]
>
> When using the `docker extension init`, it creates a `Dockerfile` that already contains what is needed for a Go backend.

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

To deploy your Go backend when installing the extension, you need first to configure the `Dockerfile`, so that it:
- Builds the backend application
- Copies the binary in the extension's container filesystem
- Starts the binary when the container starts listening on the extension socket

> [!TIP]
> 
> To ease version management, you can reuse the same image to build the frontend, build the
backend service, and package the extension.

```dockerfile
# syntax=docker/dockerfile:1
FROM node:17.7-alpine3.14 AS client-builder
# ... build frontend application

# Build the Go backend
FROM golang:1.17-alpine AS builder
ENV CGO_ENABLED=0
WORKDIR /backend
RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    --mount=type=bind,source=vm/.,target=. \
    go build -trimpath -ldflags="-s -w" -o bin/service

FROM alpine:3.15
# ... add labels and copy the frontend application

COPY --from=builder /backend/bin/service /
CMD /service -socket /run/guest-services/extension-allthethings-extension.sock
```

{{< /tab >}}
{{< tab name="Node" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for Node yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=Node)
> and let us know if you'd like a Dockerfile for Node.

{{< /tab >}}
{{< tab name="Python" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for Python yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=Python)
> and let us know if you'd like a Dockerfile for Python.

{{< /tab >}}
{{< tab name="Java" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for Java yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=Java)
> and let us know if you'd like a Dockerfile for Java.

{{< /tab >}}
{{< tab name=".NET" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for .Net. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.25798127=.Net)
> and let us know if you'd like a Dockerfile for .Net.

{{< /tab >}}
{{< /tabs >}}

## Configure the metadata file

To start the backend service of your extension inside the VM of Docker Desktop, you have to configure the image name
in the `vm` section of the `metadata.json` file.

```json
{
  "vm": {
    "image": "${DESKTOP_PLUGIN_IMAGE}"
  },
  "icon": "docker.svg",
  "ui": {
    ...
  }
}
```

For more information on the `vm` section of the `metadata.json`, see [Metadata](../architecture/metadata.md).

> [!WARNING]
>
> Do not replace the `${DESKTOP_PLUGIN_IMAGE}` placeholder in the `metadata.json` file. The placeholder is replaced automatically with the correct image name when the extension is installed.

## Invoke the extension backend from your frontend

Using the [advanced frontend extension example](frontend-extension-tutorial.md), we can invoke our extension backend.

Use the Docker Desktop Client object and then invoke the `/hello` route from the backend service with `ddClient.
extension.vm.service.get` that returns the body of the response.

{{< tabs group="framework" >}}
{{< tab name="React" >}}

Replace the `ui/src/App.tsx` file with the following code:

```tsx

// ui/src/App.tsx
import React, { useEffect, useState } from 'react';
import { createDockerDesktopClient } from "@docker/extension-api-client";

//obtain docker desktop extension client
const ddClient = createDockerDesktopClient();

export function App() {
  const [hello, setHello] = useState<string>();

  useEffect(() => {
    const getHello = async () => {
      const result = await ddClient.extension.vm?.service?.get('/hello');
      setHello(JSON.stringify(result));
    }
    getHello()
  }, []);

  return (
    <Typography>{hello}</Typography>
  );
}

```

{{< /tab >}}
{{< tab name="Vue" >}}

> [!IMPORTANT]
>
> We don't have an example for Vue yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Vue)
> and let us know if you'd like a sample with Vue.

{{< /tab >}}
{{< tab name="Angular" >}}

> [!IMPORTANT]
>
> We don't have an example for Angular yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Angular)
> and let us know if you'd like a sample with Angular.

{{< /tab >}}
{{< tab name="Svelte" >}}

> [!IMPORTANT]
>
> We don't have an example for Svelte yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Svelte)
> and let us know if you'd like a sample with Svelte.

{{< /tab >}}
{{< /tabs >}}

## Re-build the extension and update it

Since you have modified the configuration of the extension and added a stage in the Dockerfile, you must re-build the extension.

```bash
docker build --tag=awesome-inc/my-extension:latest .
```

Once built, you need to update it, or install it if you haven't already done so.

```bash
docker extension update awesome-inc/my-extension:latest
```

Now you can see the backend service running in the **Containers** view of the Docker Desktop Dashboard and watch the logs when you need to debug it.

> [!TIP]
>
> You may need to turn on the **Show system containers** option in **Settings** to see the backend container running.
> See [Show extension containers](../dev/test-debug.md#show-the-extension-containers) for more information.

Open the Docker Desktop Dashboard and select the **Containers** tab. You should see the response from the backend service
call displayed.

## What's next?

- Learn how to [share and publish your extension](../extensions/index.md).
- Learn more about extensions [architecture](../architecture/index.md).


---

# Create an advanced frontend extension

*Sección: Extensions*

To start creating your extension, you first need a directory with files which range from the extension’s source code to the required extension-specific files. This page provides information on how to set up an extension with a more advanced frontend.

Before you start, make sure you have installed the latest version of [Docker Desktop](../../../desktop/release-notes.md).

## Extension folder structure

The quickest way to create a new extension is to run `docker extension init my-extension` as in the
[Quickstart](../quickstart.md). This creates a new directory `my-extension` that contains a fully functional extension.

> [!TIP]
>
> The `docker extension init` generates a React based extension. But you can still use it as a starting point for
> your own extension and use any other frontend framework, like Vue, Angular, Svelte, etc. or even stay with
> vanilla Javascript.

Although you can start from an empty directory or from the `react-extension` [sample folder](https://github.com/docker/extensions-sdk/tree/main/samples),
it's highly recommended that you start from the `docker extension init` command and change it to suit your needs.

```bash
.
├── Dockerfile # (1)
├── ui # (2)
│   ├── public # (3)
│   │   └── index.html
│   ├── src # (4)
│   │   ├── App.tsx
│   │   ├── index.tsx
│   ├── package.json
│   └── package-lock.lock
│   ├── tsconfig.json
├── docker.svg # (5)
└── metadata.json # (6)
```

1. Contains everything required to build the extension and run it in Docker Desktop.
2. High-level folder containing your front-end app source code.
3. Assets that aren’t compiled or dynamically generated are stored here. These can be static assets like logos or the robots.txt file.
4. The src, or source folder contains all the React components, external CSS files, and dynamic assets that are brought into the component files.
5. The icon that is displayed in the left-menu of the Docker Desktop Dashboard.
6. A file that provides information about the extension such as the name, description, and version.

## Adapting the Dockerfile

> [!NOTE]
>
> When using the `docker extension init`, it creates a `Dockerfile` that already contains what is needed for a React
> extension.

Once the extension is created, you need to configure the `Dockerfile` to build the extension and configure the labels
that are used to populate the extension's card in the Marketplace. Here is an example of a `Dockerfile` for a React
extension:

{{< tabs group="framework" >}}
{{< tab name="React" >}}

```Dockerfile
# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM node:18.9-alpine3.15 AS client-builder
WORKDIR /ui
# cache packages in layer
COPY ui/package.json /ui/package.json
COPY ui/package-lock.json /ui/package-lock.json
RUN --mount=type=cache,target=/usr/src/app/.npm \
    npm set cache /usr/src/app/.npm && \
    npm ci
# install
COPY ui /ui
RUN npm run build

FROM alpine
LABEL org.opencontainers.image.title="My extension" \
    org.opencontainers.image.description="Your Desktop Extension Description" \
    org.opencontainers.image.vendor="Awesome Inc." \
    com.docker.desktop.extension.api.version="0.3.3" \
    com.docker.desktop.extension.icon="https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png" \
    com.docker.extension.screenshots="" \
    com.docker.extension.detailed-description="" \
    com.docker.extension.publisher-url="" \
    com.docker.extension.additional-urls="" \
    com.docker.extension.changelog=""

COPY metadata.json .
COPY docker.svg .
COPY --from=client-builder /ui/build ui

```
> Note
>
> In the example Dockerfile, you can see that the image label `com.docker.desktop.extension.icon` is set to an icon URL. The Extensions Marketplace displays this icon without installing the extension. The Dockerfile also includes `COPY docker.svg .` to copy an icon file inside the image. This second icon file is used to display the extension UI in the Dashboard, once the extension is installed.

{{< /tab >}}
{{< tab name="Vue" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for Vue yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Vue)
> and let us know if you'd like a Dockerfile for Vue.

{{< /tab >}}
{{< tab name="Angular" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for Angular yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Angular)
> and let us know if you'd like a Dockerfile for Angular.

{{< /tab >}}
{{< tab name="Svelte" >}}

> [!IMPORTANT]
>
> We don't have a working Dockerfile for Svelte yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Svelte)
> and let us know if you'd like a Dockerfile for Svelte.

{{< /tab >}}
{{< /tabs >}}

## Configure the metadata file

In order to add a tab in Docker Desktop for your extension, you have to configure it in the `metadata.json`
file the root of your extension directory.

```json
{
  "icon": "docker.svg",
  "ui": {
    "dashboard-tab": {
      "title": "UI Extension",
      "root": "/ui",
      "src": "index.html"
    }
  }
}
```

The `title` property is the name of the extension that is displayed in the left-menu of the Docker Desktop Dashboard.
The `root` property is the path to the frontend application in the extension's container filesystem used by the
system to deploy it on the host.
The `src` property is the path to the HTML entry point of the frontend application within the `root` folder.

For more information on the `ui` section of the `metadata.json`, see [Metadata](../architecture/metadata.md#ui-section).

## Build the extension and install it

Now that you have configured the extension, you need to build the extension image that Docker Desktop will use to
install it.

```bash
docker build --tag=awesome-inc/my-extension:latest .
```

This built an image tagged `awesome-inc/my-extension:latest`, you can run `docker inspect
awesome-inc/my-extension:latest` to see more details about it.

Finally, you can install the extension and see it appearing in the Docker Desktop Dashboard.

```bash
docker extension install awesome-inc/my-extension:latest
```

## Use the Extension APIs client

To use the Extension APIs and perform actions with Docker Desktop, the extension must first import the
`@docker/extension-api-client` library. To install it, run the command below:

```bash
npm install @docker/extension-api-client
```

Then call the `createDockerDesktopClient` function to create a client object to call the extension APIs.

```js
import { createDockerDesktopClient } from '@docker/extension-api-client';

const ddClient = createDockerDesktopClient();
```

When using Typescript, you can also install `@docker/extension-api-client-types` as a dev dependency. This will
provide you with type definitions for the extension APIs and auto-completion in your IDE.

```bash
npm install @docker/extension-api-client-types --save-dev
```

![Auto completion in an IDE](images/types-autocomplete.png)

For example, you can use the `docker.cli.exec` function to get the list of all the containers via the `docker ps --all`
command and display the result in a table.

{{< tabs group="framework" >}}
{{< tab name="React" >}}

Replace the `ui/src/App.tsx` file with the following code:

```tsx

// ui/src/App.tsx
import React, { useEffect } from 'react';
import {
  Paper,
  Stack,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
  Typography
} from "@mui/material";
import { createDockerDesktopClient } from "@docker/extension-api-client";

//obtain docker desktop extension client
const ddClient = createDockerDesktopClient();

export function App() {
  const [containers, setContainers] = React.useState<any[]>([]);

  useEffect(() => {
    // List all containers
    ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"']).then((result) => {
      // result.parseJsonLines() parses the output of the command into an array of objects
      setContainers(result.parseJsonLines());
    });
  }, []);

  return (
    <Stack>
      <Typography data-testid="heading" variant="h3" role="title">
        Container list
      </Typography>
      <Typography
      data-testid="subheading"
      variant="body1"
      color="text.secondary"
      sx={{ mt: 2 }}
    >
      Simple list of containers using Docker Extensions SDK.
      </Typography>
      <TableContainer sx={{mt:2}}>
        <Table>
          <TableHead>
            <TableRow>
              <TableCell>Container id</TableCell>
              <TableCell>Image</TableCell>
              <TableCell>Command</TableCell>
              <TableCell>Created</TableCell>
              <TableCell>Status</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {containers.map((container) => (
              <TableRow
                key={container.ID}
                sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
              >
                <TableCell>{container.ID}</TableCell>
                <TableCell>{container.Image}</TableCell>
                <TableCell>{container.Command}</TableCell>
                <TableCell>{container.CreatedAt}</TableCell>
                <TableCell>{container.Status}</TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableContainer>
    </Stack>
  );
}

```

![Screenshot of the container list.](images/react-extension.png)

{{< /tab >}}
{{< tab name="Vue" >}}

> [!IMPORTANT]
>
> We don't have an example for Vue yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Vue)
> and let us know if you'd like a sample with Vue.

{{< /tab >}}
{{< tab name="Angular" >}}

> [!IMPORTANT]
>
> We don't have an example for Angular yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Angular)
> and let us know if you'd like a sample with Angular.

{{< /tab >}}
{{< tab name="Svelte" >}}

> [!IMPORTANT]
>
> We don't have an example for Svelte yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Svelte)
> and let us know if you'd like a sample with Svelte.

{{< /tab >}}
{{< /tabs >}}

## Policies enforced for the front-end code

Extension UI code is rendered in a separate electron session and doesn't have a node.js environment initialized, nor direct access to the electron APIs. 

This is to limit the possible unexpected side effects to the overall Docker Dashboard.

The extension UI code can't perform privileged tasks, such as making changes to the system, or spawning sub-processes, except by using the SDK APIs provided with the extension framework.
The Extension UI code can also perform interactions with Docker Desktop, such as navigating to various places in the Dashboard, only through the extension SDK APIs.

Extensions UI parts are isolated from each other and extension UI code is running in its own session for each extension. Extensions can't access other extensions’ session data.

`localStorage` is one of the mechanisms of a browser’s web storage. It allows users to save data as key-value pairs in the browser for later use. `localStorage` doesn't clear data when the browser (the extension pane) closes. This makes it ideal for persisting data when navigating out of the extension to other parts of Docker Desktop.

If your extension uses `localStorage` to store data, other extensions running in Docker Desktop can't access the local storage of your extension. The extension’s local storage is persisted even after Docker Desktop is stopped or restarted. When an extension is upgraded, its local storage is persisted, whereas when it is uninstalled, its local storage is completely removed.

## Re-build the extension and update it

Since you have modified the code of the extension, you must build again the extension.

```console
$ docker build --tag=awesome-inc/my-extension:latest .
```

Once built, you need to update it.

```console
$ docker extension update awesome-inc/my-extension:latest
```

Now you can see the backend service running in the containers tab of the Docker Desktop Dashboard and watch the logs
when you need to debug it.

> [!TIP]
>
> You can turn on [hot reloading](../dev/test-debug.md#hot-reloading-whilst-developing-the-ui) to avoid the need to
> rebuild the extension every time you make a change.

## What's next?

- Add a [backend](backend-extension-tutorial.md) to your extension.
- Learn how to [test and debug](../dev/test-debug.md) your extension.
- Learn how to [setup CI for your extension](../dev/continuous-integration.md).
- Learn more about extensions [architecture](../architecture/index.md).
- For more information and guidelines on building the UI, see the [Design and UI styling section](../design/design-guidelines.md).
- If you want to set up user authentication for the extension, see [Authentication](../guides/oauth2-flow.md).


---

# Create a simple extension

*Sección: Extensions*

To start creating your extension, you first need a directory with files which range from the extension’s source code to the required extension-specific files. This page provides information on how to set up a minimal frontend extension based on plain HTML.

Before you start, make sure you have installed the latest version of [Docker Desktop](../../../desktop/release-notes.md).

> Tip
>
> If you want to start a codebase for your new extension, our [Quickstart guide](../quickstart.md) and `docker extension init <my-extension>` provides a better base for your extension.

## Extension folder structure

In the `minimal-frontend` [sample folder](https://github.com/docker/extensions-sdk/tree/main/samples), you can find a ready-to-go example that represents a UI Extension built on HTML. We will go through this code example in this tutorial.

Although you can start from an empty directory, it is highly recommended that you start from the template below and change it accordingly to suit your needs.

```bash
.
├── Dockerfile # (1)
├── metadata.json # (2)
└── ui # (3)
    └── index.html
```

1. Contains everything required to build the extension and run it in Docker Desktop.
2. A file that provides information about the extension such as the name, description, and version.
3. The source folder that contains all your HTML, CSS and JS files. There can also be other static assets such as logos
   and icons. For more information and guidelines on building the UI, see the [Design and UI styling section](../design/design-guidelines.md).

## Create a Dockerfile

At a minimum, your Dockerfile needs:

- [Labels](../extensions/labels.md) which provide extra information about the extension, icon and screenshots.
- The source code which in this case is an `index.html` that sits within the `ui` folder.
- The `metadata.json` file.

```Dockerfile
# syntax=docker/dockerfile:1
FROM scratch

LABEL org.opencontainers.image.title="Minimal frontend" \
    org.opencontainers.image.description="A sample extension to show how easy it's to get started with Desktop Extensions." \
    org.opencontainers.image.vendor="Awesome Inc." \
    com.docker.desktop.extension.api.version="0.3.3" \
    com.docker.desktop.extension.icon="https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png"

COPY ui ./ui
COPY metadata.json .
```

## Configure the metadata file

A `metadata.json` file is required at the root of the image filesystem.

```json
{
  "ui": {
    "dashboard-tab": {
      "title": "Minimal frontend",
      "root": "/ui",
      "src": "index.html"
    }
  }
}
```

For more information on the `metadata.json`, see [Metadata](../architecture/metadata.md).

## Build the extension and install it

Now that you have configured the extension, you need to build the extension image that Docker Desktop will use to
install it.

```console
$ docker build --tag=awesome-inc/my-extension:latest .
```

This built an image tagged `awesome-inc/my-extension:latest`, you can run `docker inspect awesome-inc/my-extension:latest` to see more details about it.

Finally, you can install the extension and see it appearing in the Docker Desktop Dashboard.

```console
$ docker extension install awesome-inc/my-extension:latest
```

## Preview the extension

To preview the extension in Docker Desktop, close and open the Docker Desktop Dashboard once the installation is complete.

The left-hand menu displays a new tab with the name of your extension.

![Minimal frontend extension](images/ui-minimal-extension.png)

## What's next?

- Build a more [advanced frontend](frontend-extension-tutorial.md) extension.
- Learn how to [test and debug](../dev/test-debug.md) your extension.
- Learn how to [setup CI for your extension](../dev/continuous-integration.md).
- Learn more about extensions [architecture](../architecture/index.md).


---

# UI styling overview for Docker extensions

*Sección: Extensions*

Our Design System is a constantly evolving set of specifications that aim to ensure visual consistency across Docker products, and meet [level AA accessibility standards](https://www.w3.org/WAI/WCAG2AA-Conformance). We've opened parts of it to extension authors, documenting basic styles (color, typography) and components. See: [Docker Extensions Styleguide](https://www.figma.com/file/U7pLWfEf6IQKUHLhdateBI/Docker-Design-Guidelines?node-id=1%3A28771).

We require extensions to match the wider Docker Desktop UI to a certain degree, and reserve the right to make this stricter in the future.

To get started on your UI, follow the steps below.

## Step one: Choose your framework

### Recommended: React+MUI, using our theme

Docker Desktop's UI is written in React and [MUI](https://mui.com/) (using Material UI specifically). This is the only officially supported framework for building extensions, and the one that the `init` command automatically configures for you. Using it brings significant benefits to authors:

- You can use our [Material UI theme](https://www.npmjs.com/package/@docker/docker-mui-theme) to automatically replicate Docker Desktop's look and feel.
- In future, we'll release utilities and components specifically targeting this combination (e.g. custom MUI components, or React hooks for interacting with Docker).

Read our [MUI best practices](mui-best-practices.md) guide to learn future-proof ways to use MUI with Docker Desktop.

### Not recommended: Some other framework

You may prefer to use another framework, perhaps because you or your team are more familiar with it or because you have existing assets you want to reuse. This is possible, but highly discouraged. It means that:

- You'll need to manually replicate the look and feel of Docker Desktop. This takes a lot of effort, and if you don't match our theme closely enough, users will find your extension jarring and we may ask you to make changes during a review process.
- You'll have a higher maintenance burden. Whenever Docker Desktop's theme changes (which could happen in any release), you'll need to manually change your extension to match it.
- If your extension is open-source, deliberately avoiding common conventions will make it harder for the community to contribute to it.

## Step two: Follow the below recommendations

### Follow our MUI best practices (if applicable)

See our [MUI best practices](mui-best-practices.md) article.

### Only use colors from our palette

With minor exceptions, displaying your logo for example, you should only use colors from our palette. These can be found in our [style guide document](https://www.figma.com/file/U7pLWfEf6IQKUHLhdateBI/Docker-Design-Guidelines?node-id=1%3A28771), and will also soon be available in our MUI theme and via CSS variables.

### Use counterpart colors in light/dark mode

Our colors have been chosen so that the counterpart colors in each variant of the palette should have the same essential characteristics. Anywhere you use `red-300` in light mode, you should use `red-300` in dark mode too.

## What's next?

- Take a look at our [MUI best practices](mui-best-practices.md).
- Learn how to [publish your extension](../extensions/index.md).


---

# Design guidelines for Docker extensions

*Sección: Extensions*

At Docker, we aim to build tools that integrate into a user's existing workflows rather than requiring them to adopt new ones. We strongly recommend that you follow these guidelines when creating extensions. We review and approve your Marketplace publication based on these requirements.

Here is a simple checklist to go through when creating your extension:
- Is it easy to get started?
- Is it easy to use?
- Is it easy to get help when needed?


## Create a consistent experience with Docker Desktop

Use the [Docker Material UI Theme](https://www.npmjs.com/package/@docker/docker-mui-theme) and the [Docker Extensions Styleguide](https://www.figma.com/file/U7pLWfEf6IQKUHLhdateBI/Docker-Design-Guidelines?node-id=1%3A28771) to ensure that your extension feels like it is part of Docker Desktop to create a seamless experience for users.

- Ensure the extension has both a light and dark theme. Using the components and styles as per the Docker style guide ensures that your extension meets the [level AA accessibility standard.](https://www.w3.org/WAI/WCAG2AA-Conformance).

  ![Light and dark mode](images/light_dark_mode.webp)

- Ensure that your extension icon is visible both in light and dark mode.

  ![Icon colors in light and dark mode](images/icon_colors.webp)

- Ensure that the navigational behavior is consistent with the rest of Docker Desktop. Add a header to set the context for the extension.

  ![Header that sets the context](images/header.webp)

- Avoid embedding terminal windows. The advantage we have with Docker Desktop over the CLI is that we have the opportunity to provide rich information to users. Make use of this interface as much as possible. 

  ![Terminal window used incorrectly](images/terminal_window_dont.webp)

  ![Terminal window used correctly](images/terminal_window_do.webp)

## Build features natively

- In order not to disrupt the flow of users, avoid scenarios where the user has to navigate outside Docker Desktop, to the CLI or a webpage for example, in order to carry out certain functionalities. Instead, build features that are native to Docker Desktop.

  ![Incorrect way to switch context](images/switch_context_dont.webp)

  ![Correct way to switch context](images/switch_context_do.webp)

## Break down complicated user flows

- If a flow is too complicated or the concept is abstract, break down the flow into multiple steps with one simple call-to-action in each step. This helps when onboarding novice users to your extension

  ![A complicated flow](images/complicated_flows.webp)

- Where there are multiple call-to-actions, ensure you use the primary (filled button style) and secondary buttons (outline button style) to convey the importance of each action.

  ![Call to action](images/cta.webp)

## Onboarding new users

When creating your extension, ensure that first time users of the extension and your product can understand its value-add and adopt it easily. Ensure you include contextual help within the extension.

- Ensure that all necessary information is added to the extensions Marketplace as well as the extensions detail page. This should include:
  - Screenshots of the extension. Note that the recommended size for screenshots is 2400x1600 pixels. 
  - A detailed description that covers what the purpose of the extension is, who would find it useful and how it works.
  - Link to necessary resources such as documentation.
- If your extension has particularly complex functionality, add a demo or video to the start page. This helps onboard a first time user quickly.

  ![start page](images/start_page.webp)

## What's next?

- Explore our [design principles](design-principles.md).
- Take a look at our [UI styling guidelines](../../../reference/api/ai-governance/index.md).
- Learn how to [publish your extension](../extensions/index.md).


---

# Docker design principles

*Sección: Extensions*

## Provide actionable guidance

We anticipate needs and provide simple explanations with clear actions so people are never lost and always know what to do next. Recommendations lead users to functionality that enhances the experience and extends their knowledge.

## Create value through confidence

People from all levels of experience should feel they know how to use our product. Experiences are familiar, unified, and easy to use so all users feel like experts.

## Infuse productivity with delight

We seek out moments of purposeful delight that elevate rather than distract, making work easier and more gratifying. Simple tasks are automated and users are left with more time for innovation.

## Build trust through transparency

We always provide clarity on what is happening and why. No amount of detail is withheld; the right information is shown at the right time and is always accessible.

## Scale with intention

Our products focus on inclusive growth and are continuously useful and adapt to match changing individual needs. We support all levels of expertise by meeting users where they are with conscious personalization.

## What's next?

- Take a look at our [UI styling guidelines](../../../reference/api/ai-governance/index.md).
- Learn how to [publish your extension](../extensions/index.md).


---

# MUI best practices

*Sección: Extensions*

This article assumes you're following our recommended practice by using our [Material UI theme](https://www.npmjs.com/package/@docker/docker-mui-theme).
Following the steps below maximizes compatibility with Docker Desktop and minimizes the work you need to do as an
extension author. They should be considered supplementary to the non-MUI-specific guidelines found in the
[UI Styling overview](../../../reference/api/ai-governance/index.md).

## Assume the theme can change at any time

Resist the temptation to fine-tune your UI with precise colors, offsets and font sizings to make it look as attractive as possible. Any specializations you make today will be relative to the current MUI theme, and may look worse when the theme changes. Any part of the theme might change without warning, including (but not limited to):

-  The font, or font sizes
-  Border thicknesses or styles
-  Colors:
   -  Our palette members (e.g. `red-100`) could change their RGB values
   -  The semantic colors (e.g. `error`, `primary`, `textPrimary`, etc) could be changed to use a different member of our palette
   -  Background colors (e.g. those of the page, or of dialogs) could change
-  Spacings:
   -  The size of the basic unit of spacing,(exposed via `theme.spacing`. For instance, we may allow users to customize the density of the UI
   -  The default spacing between paragraphs or grid items

The best way to build your UI, so that it’s robust against future theming changes, is to:

-  Override the default styling as little as possible.
-  Use semantic typography. e.g. use `Typography`s or `Link`s with appropriate `variant`s instead of using typographical HTML elements (`<a>`, `<p>`, `<h1>`, etc) directly.
-  Use canned sizes. e.g. use `size="small"` on buttons, or `fontSize="small"` on icons, instead of specifying sizes in pixels.
-  Prefer semantic colors. e.g. use `error` or `primary` over explicit color codes.
-  Write as little CSS as possible. Write semantic markup instead. For example, if you want to space out paragraphs of text, use the `paragraph` prop on your `Typography` instances. If you want to space out something else, use a `Stack` or `Grid` with the default spacing.
-  Use visual idioms you’ve seen in the Docker Desktop UI, since these are the main ones we’ll test any theme changes against.

## When you go custom, centralize it

Sometimes you’ll need a piece of UI that doesn’t exist in our design system. If so, we recommend that you first reach out to us. We may already have something in our internal design system, or we may be able to expand our design system to accommodate your use case.

If you still decide to build it yourself after contacting us, try and define the new UI in a reusable fashion. If you define your custom UI in just one place, it’ll make it easier to change in the future if our core theme changes. You could use:

-  A new `variant` of an existing component - see [MUI docs](https://mui.com/material-ui/customization/theme-components/#creating-new-component-variants)
-  A MUI mixin (a freeform bundle of reusable styling rules defined inside a theme)
-  A new [reusable component](https://mui.com/material-ui/customization/how-to-customize/#2-reusable-component)

Some of the above options require you to extend our MUI theme. See the MUI documentation on [theme composition](https://mui.com/material-ui/customization/theming/#nesting-the-theme).

## What's next?

- Take a look at our [UI styling guide](../../../reference/api/ai-governance/index.md).
- Learn how to [publish your extension](../extensions/index.md).


---

# Developer SDK tools

*Sección: Extensions*




---

# Extension APIs

*Sección: Extensions*




---

# Extension Backend

*Sección: Extensions*

The `ddClient.extension.vm` object can be used to communicate with the backend defined in the [vm section](../../architecture/metadata.md#vm-section) of the extension metadata.

## get

▸ **get**(`url`): `Promise`<`unknown`\>

Performs an HTTP GET request to a backend service.

```typescript
ddClient.extension.vm.service
 .get("/some/service")
 .then((value: any) => console.log(value)
```

See [Service API Reference](../../../../reference/api/extensions-sdk/httpservice.md) for other HTTP methods.

> Deprecated extension backend communication
>
> The methods below that use `window.ddClient.backend` are deprecated and will be removed in a future version. Use the methods specified above.

The `window.ddClient.backend` object can be used to communicate with the backend
defined in the [vm section](../../architecture/metadata.md#vm-section) of the
extension metadata. The client is already connected to the backend.

Example usages:

```typescript
window.ddClient.backend
  .get("/some/service")
  .then((value: any) => console.log(value));

window.ddClient.backend
  .post("/some/service", { ... })
  .then((value: any) => console.log(value));

window.ddClient.backend
  .put("/some/service", { ... })
  .then((value: any) => console.log(value));

window.ddClient.backend
  .patch("/some/service", { ... })
  .then((value: any) => console.log(value));

window.ddClient.backend
  .delete("/some/service")
  .then((value: any) => console.log(value));

window.ddClient.backend
  .head("/some/service")
  .then((value: any) => console.log(value));

window.ddClient.backend
  .request({ url: "/url", method: "GET", headers: { 'header-key': 'header-value' }, data: { ... }})
  .then((value: any) => console.log(value));
```

## Run a command in the extension backend container

For example, execute the command `ls -l` inside the backend container:

```typescript
await ddClient.extension.vm.cli.exec("ls", ["-l"]);
```

Stream the output of the command executed in the backend container. For example, spawn the command `ls -l` inside the backend container:

```typescript
await ddClient.extension.vm.cli.exec("ls", ["-l"], {
  stream: {
    onOutput(data) {
      if (data.stdout) {
        console.error(data.stdout);
      } else {
        console.log(data.stderr);
      }
    },
    onError(error) {
      console.error(error);
    },
    onClose(exitCode) {
      console.log("onClose with exit code " + exitCode);
    },
  },
});
```

For more details, refer to the [Extension VM API Reference](../../../../reference/api/extensions-sdk/extensionvm.md)

> Deprecated extension backend command execution
>
> This method is deprecated and will be removed in a future version. Use the specified method above.

If your extension ships with additional binaries that should be run inside the
backend container, you can use the `execInVMExtension` function:

```typescript
const output = await window.ddClient.backend.execInVMExtension(
  `cliShippedInTheVm xxx`
);
console.log(output);
```

## Invoke an extension binary on the host

Invoke a binary on the host. The binary is typically shipped with your extension using the [host section](../../architecture/metadata.md#host-section) in the extension metadata. Note that extensions run with user access rights, this API is not restricted to binaries listed in the [host section](../../architecture/metadata.md#host-section) of the extension metadata (some extensions might install software during user interaction, and invoke newly installed binaries even if not listed in the extension metadata).

For example, execute the shipped binary `kubectl -h` command in the host:

```typescript
await ddClient.extension.host.cli.exec("kubectl", ["-h"]);
```

As long as the `kubectl` binary is shipped as part of your extension, you can spawn the `kubectl -h` command in the host and get the output stream:

```typescript
await ddClient.extension.host.cli.exec("kubectl", ["-h"], {
  stream: {
    onOutput(data: { stdout: string } | { stderr: string }): void {
      if (data.stdout) {
        console.error(data.stdout);
      } else {
        console.log(data.stderr);
      }
    },
    onError(error: any): void {
      console.error(error);
    },
    onClose(exitCode: number): void {
      console.log("onClose with exit code " + exitCode);
    },
  },
});
```

You can stream the output of the command executed in the backend container or in the host.

For more details, refer to the [Extension Host API Reference](../../../../reference/api/extensions-sdk/extensionhost.md)

> Deprecated invocation of extension binary
>
> This method is deprecated and will be removed in a future version. Use the method specified above.

To execute a command in the host:

```typescript
window.ddClient.execHostCmd(`cliShippedOnHost xxx`).then((cmdResult: any) => {
  console.log(cmdResult);
});
```

To stream the output of the command executed in the backend container or in the host:

```typescript
window.ddClient.spawnHostCmd(
  `cliShippedOnHost`,
  [`arg1`, `arg2`],
  (data: any, err: any) => {
    console.log(data.stdout, data.stderr);
    // Once the command exits we get the status code
    if (data.code) {
      console.log(data.code);
    }
  }
);
```

> [!NOTE]
> 
>You cannot use this to chain commands in a single `exec()` invocation (like `cmd1 $(cmd2)` or using pipe between commands).
>
> You need to invoke `exec()` for each command and parse results to pass parameters to the next command if needed.


---

# Navigation

*Sección: Extensions*

`ddClient.desktopUI.navigate` enables navigation to specific screens of Docker Desktop such as the containers tab, the images tab, or a specific container's logs.

For example, navigate to a given container logs:

```typescript
const id = '8c7881e6a107';
try {
  await ddClient.desktopUI.navigate.viewContainerLogs(id);
} catch (e) {
  console.error(e);
  ddClient.desktopUI.toast.error(
    `Failed to navigate to logs for container "${id}".`
  );
}
```

#### Parameters

| Name | Type     | Description                                                                                                                                                                                            |
| :--- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`void`\>

A promise that fails if the container doesn't exist.

For more details about all navigation methods, see the [Navigation API reference](../../../../reference/api/extensions-sdk/navigationintents.md).

> Deprecated navigation methods
>
> These methods are deprecated and will be removed in a future version. Use the methods specified above.

```typescript
window.ddClient.navigateToContainers();
// id - the full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`
window.ddClient.navigateToContainer(id);
window.ddClient.navigateToContainerLogs(id);
window.ddClient.navigateToContainerInspect(id);
window.ddClient.navigateToContainerStats(id);

window.ddClient.navigateToImages();
window.ddClient.navigateToImage(id, tag);

window.ddClient.navigateToVolumes();
window.ddClient.navigateToVolume(volume);

window.ddClient.navigateToDevEnvironments();
```


---

# Dashboard

*Sección: Extensions*

## User notifications

Toasts provide a brief notification to the user. They appear temporarily and
shouldn't interrupt the user experience. They also don't require user input to disappear.

### success

▸ **success**(`msg`): `void`

Use to display a toast message of type success.

```typescript
ddClient.desktopUI.toast.success("message");
```

### warning

▸ **warning**(`msg`): `void`

Use to display a toast message of type warning.

```typescript
ddClient.desktopUI.toast.warning("message");
```

### error

▸ **error**(`msg`): `void`

Use to display a toast message of type error.

```typescript
ddClient.desktopUI.toast.error("message");
```

For more details about method parameters and the return types available, see [Toast API reference](../../../../reference/api/extensions-sdk/toast.md).

> Deprecated user notifications
>
> These methods are deprecated and will be removed in a future version. Use the methods specified above.

```typescript
window.ddClient.toastSuccess("message");
window.ddClient.toastWarning("message");
window.ddClient.toastError("message");
```

## Open a file selection dialog

This function opens a file selector dialog that asks the user to select a file or folder.

▸ **showOpenDialog**(`dialogProperties`): `Promise`<[`OpenDialogResult`](../../../../reference/api/extensions-sdk/opendialogresult.md)\>:

The `dialogProperties` parameter is a list of flags passed to Electron to customize the dialog's behaviour. For example, you can pass `multiSelections` to allow a user to select multiple files. See [Electron's documentation](https://www.electronjs.org/docs/latest/api/dialog) for a full list.

```typescript
const result = await ddClient.desktopUI.dialog.showOpenDialog({
  properties: ["openDirectory"],
});
if (!result.canceled) {
  console.log(result.paths);
}
```

## Open a URL

This function opens an external URL with the system default browser.

▸ **openExternal**(`url`): `void`

```typescript
ddClient.host.openExternal("https://docker.com");
```

> The URL must have the protocol `http` or `https`.

For more details about method parameters and the return types available, see [Desktop host API reference](../../../../reference/api/extensions-sdk/host.md).

> Deprecated external URL opening
>
> This method is deprecated and will be removed in a future version. Use the methods specified above.

```typescript
window.ddClient.openExternal("https://docker.com");
```

## Navigation to Dashboard routes

From your extension, you can also [navigate](dashboard-routes-navigation.md) to other parts of the Docker Desktop Dashboard.


---

# Docker

*Sección: Extensions*

## Docker objects

▸ **listContainers**(`options?`): `Promise`<`unknown`\>

To get the list of containers:

```typescript
const containers = await ddClient.docker.listContainers();
```

▸ **listImages**(`options?`): `Promise`<`unknown`\>

To get the list of local container images:

```typescript
const images = await ddClient.docker.listImages();
```

See the [Docker API reference](../../../../reference/api/extensions-sdk/docker.md) for details about these methods.

> Deprecated access to Docker objects
>
> The methods below are deprecated and will be removed in a future version. Use the methods specified above.

```typescript
const containers = await window.ddClient.listContainers();

const images = await window.ddClient.listImages();
```

## Docker commands

Extensions can also directly execute the `docker` command line.

▸ **exec**(`cmd`, `args`): `Promise`<[`ExecResult`](../../../../reference/api/extensions-sdk/execresult.md)\>

```typescript
const result = await ddClient.docker.cli.exec("info", [
  "--format",
  '"{{ json . }}"',
]);
```

The result contains both the standard output and the standard error of the executed command:

```json
{
  "stderr": "...",
  "stdout": "..."
}
```

In this example, the command output is JSON.
For convenience, the command result object also has methods to easily parse it:

- `result.lines(): string[]` splits output lines.
- `result.parseJsonObject(): any` parses a well-formed json output.
- `result.parseJsonLines(): any[]` parses each output line as a json object.

▸ **exec**(`cmd`, `args`, `options`): `void`

The command above streams the output as a result of the execution of a Docker command.
This is useful if you need to get the output as a stream or the output of the command is too long.

```typescript
await ddClient.docker.cli.exec("logs", ["-f", "..."], {
  stream: {
    onOutput(data) {
      if (data.stdout) {
        console.error(data.stdout);
      } else {
        console.log(data.stderr);
      }
    },
    onError(error) {
      console.error(error);
    },
    onClose(exitCode) {
      console.log("onClose with exit code " + exitCode);
    },
    splitOutputLines: true,
  },
});
```

The child process created by the extension is killed (`SIGTERM`) automatically when you close the dashboard in Docker Desktop or when you exit the extension UI.
If needed, you can also use the result of the `exec(streamOptions)` call in order to kill (`SIGTERM`) the process.

```typescript
const logListener = await ddClient.docker.cli.exec("logs", ["-f", "..."], {
  stream: {
    // ...
  },
});

// when done listening to logs or before starting a new one, kill the process
logListener.close();
```

This `exec(streamOptions)` API can also be used to listen to docker events:

```typescript
await ddClient.docker.cli.exec(
  "events",
  ["--format", "{{ json . }}", "--filter", "container=my-container"],
  {
    stream: {
      onOutput(data) {
        if (data.stdout) {
          const event = JSON.parse(data.stdout);
          console.log(event);
        } else {
          console.log(data.stderr);
        }
      },
      onClose(exitCode) {
        console.log("onClose with exit code " + exitCode);
      },
      splitOutputLines: true,
    },
  }
);
```

> [!NOTE]
>
>You cannot use this to chain commands in a single `exec()` invocation (like `docker kill $(docker ps -q)` or using pipe between commands).
>
> You need to invoke `exec()` for each command and parse results to pass parameters to the next command if needed.

See the [Exec API reference](../../../../reference/api/extensions-sdk/exec.md) for details about these methods.

> Deprecated execution of Docker commands
>
> This method is deprecated and will be removed in a future version. Use the one specified just below.

```typescript
const output = await window.ddClient.execDockerCmd(
  "info",
  "--format",
  '"{{ json . }}"'
);

window.ddClient.spawnDockerCmd("logs", ["-f", "..."], (data, error) => {
  console.log(data.stdout);
});
```


---

# Extension UI API

*Sección: Extensions*

The extensions UI runs in a sandboxed environment and doesn't have access to any
electron or nodejs APIs.

The extension UI API provides a way for the frontend to perform different actions
and communicate with the Docker Desktop dashboard or the underlying system.

JavaScript API libraries, with Typescript support, are available in order to get all the API definitions in to your extension code.

- [@docker/extension-api-client](https://www.npmjs.com/package/@docker/extension-api-client) gives access to the extension API entrypoint `DockerDesktopClient`.
- [@docker/extension-api-client-types](https://www.npmjs.com/package/@docker/extension-api-client-types) can be added as a dev dependency in order to get types auto-completion in your IDE.

```Typescript
import { createDockerDesktopClient } from '@docker/extension-api-client';

export function App() {
  // obtain Docker Desktop client
  const ddClient = createDockerDesktopClient();
  // use ddClient to perform extension actions
}
```

The `ddClient` object gives access to various APIs:

- [Extension Backend](backend.md)
- [Docker](docker.md)
- [Dashboard](dashboard.md)
- [Navigation](dashboard-routes-navigation.md)

See also the [Extensions API reference](../../../../reference/api/extensions-sdk/index.md).


---

# Continuous Integration (CI)

*Sección: Extensions*

In order to help validate your extension and ensure it's functional, the Extension SDK provides tools to help you setup continuous integration for your extension.

> [!IMPORTANT]
>
> The [Docker Desktop Action](https://github.com/docker/desktop-action) and the [extension-test-helper library](https://www.npmjs.com/package/@docker/extension-test-helper) are both [experimental](https://docs.docker.com/release-lifecycle/#experimental).

## Setup CI environment with GitHub Actions

You need Docker Desktop to be able to install and validate your extension.
You can start Docker Desktop in GitHub Actions using the [Docker Desktop Action](https://github.com/docker/desktop-action), by adding the following to a workflow file:

```yaml
steps:
  - id: start_desktop
    uses: docker/desktop-action/start@v0.1.0
```

> [!NOTE]
>
> This action supports only GitHub Actions macOS runners at the moment. You need to specify `runs-on: macOS-latest` for your end to end tests.

Once the step has executed, the next steps use Docker Desktop and the Docker CLI to install and test the extension.

## Validating your extension with Puppeteer

Once Docker Desktop starts in CI, you can build, install, and validate your extension with Jest and Puppeteer.

First, build and install the extension from your test:

```ts
import { DesktopUI } from "@docker/extension-test-helper";
import { exec as originalExec } from "child_process";
import * as util from "util";

export const exec = util.promisify(originalExec);

// keep a handle on the app to stop it at the end of tests
let dashboard: DesktopUI;

beforeAll(async () => {
  await exec(`docker build -t my/extension:latest .`, {
    cwd: "my-extension-src-root",
  });

  await exec(`docker extension install -f my/extension:latest`);
});
```

Then open the Docker Desktop Dashboard and run some tests in your extension's UI:

```ts
describe("Test my extension", () => {
  test("should be functional", async () => {
    dashboard = await DesktopUI.start();

    const eFrame = await dashboard.navigateToExtension("my/extension");

    // use puppeteer APIs to manipulate the UI, click on buttons, expect visual display and validate your extension
    await eFrame.waitForSelector("#someElementId");
  });
});
```

Finally, close the Docker Desktop Dashboard and uninstall your extension:

```ts
afterAll(async () => {
  dashboard?.stop();
  await exec(`docker extension uninstall my/extension`);
});
```

## What's next

- Build an [advanced frontend](../build/frontend-extension-tutorial.md) extension.
- Learn more about extensions [architecture](../architecture/index.md).
- Learn how to [publish your extension](../extensions/index.md).


---

# Test and debug

*Sección: Extensions*

In order to improve the developer experience, Docker Desktop provides a set of tools to help you test and debug your extension.

### Open Chrome DevTools

In order to open the Chrome DevTools for your extension when you select the **Extensions** tab, run:

```console
$ docker extension dev debug <name-of-your-extensions>
```

Each subsequent click on the extension tab also opens Chrome DevTools. To stop this behaviour, run:

```console
$ docker extension dev reset <name-of-your-extensions>
```

After an extension is deployed, it is also possible to open Chrome DevTools from the UI extension part using a variation of the [Konami Code](https://en.wikipedia.org/wiki/Konami_Code). Select the **Extensions** tab, and then hit the key sequence `up, up, down, down, left, right, left, right, p, d, t`.

### Hot reloading whilst developing the UI

During UI development, it’s helpful to use hot reloading to test your changes without rebuilding your entire
extension. To do this, you can configure Docker Desktop to load your UI from a development server, such as the one
[Vite](https://vitejs.dev/) starts when invoked with `npm start`.

Assuming your app runs on the default port, start your UI app and then run:

```console
$ cd ui
$ npm run dev
```

This starts a development server that listens on port 3000.

You can now tell Docker Desktop to use this as the frontend source. In another terminal run:

```console
$ docker extension dev ui-source <name-of-your-extensions> http://localhost:3000
```

Close and reopen the Docker Desktop dashboard and go to your extension. All the changes to the frontend code are immediately visible.

Once finished, you can reset the extension configuration to the original settings. This will also reset opening Chrome DevTools if you used `docker extension dev debug <name-of-your-extensions>`:

```console
$ docker extension dev reset <name-of-your-extensions>
```

## Show the extension containers

If your extension is composed of one or more services running as containers in the Docker Desktop VM, you can access them easily from the dashboard in Docker Desktop.

1. In Docker Desktop, navigate to **Settings**.
2. Under the **Extensions** tab, select the **Show Docker Desktop Extensions system containers** option. You can now view your extension containers and their logs.

## Clean up

To remove the extension, run:

```console
$ docker extension rm <name-of-your-extension>
```

## What's next

- Build an [advanced frontend](../build/frontend-extension-tutorial.md) extension.
- Learn more about extensions [architecture](../architecture/index.md).
- Explore our [design principles](../design/design-principles.md).
- Take a look at our [UI styling guidelines](../design/index.md).
- Learn how to [setup CI for your extension](continuous-integration.md).


---

# CLI reference

*Sección: Extensions*

The Extensions CLI is an extension development tool that is used to manage Docker extensions. Actions include install, list, remove, and validate extensions.

- `docker extension enable` turns on Docker extensions.
- `docker extension dev` commands for extension development.
- `docker extension disable` turns off Docker extensions.
- `docker extension init` creates a new Docker extension.
- `docker extension install` installs a Docker extension with the specified image.
- `docker extension ls` list installed Docker extensions.
- `docker extension rm` removes a Docker extension.
- `docker extension update` removes and re-installs a Docker extension.
- `docker extension validate` validates the extension metadata file against the JSON schema.


---

# Package and release your extension

*Sección: Extensions*

This page contains additional information on how to package and distribute extensions.

## Package your extension

Docker extensions are packaged as Docker images. The entire extension runtime including the UI, backend services (host or VM), and any necessary binary must be included in the extension image.
Every extension image must contain a `metadata.json` file at the root of its filesystem that defines the [contents of the extension](../architecture/metadata.md).

The Docker image must have several [image labels](labels.md), providing information about the extension. See how to use [extension labels](labels.md) to provide extension overview information.

To package and release an extension, you must build a Docker image (`docker build`), and push the image to [Docker Hub](https://hub.docker.com/) (`docker push`) with a specific tag that lets you manage versions of the extension.

## Release your extension

Docker image tags must follow semver conventions in order to allow fetching the latest version of the extension, and to know if there are updates available. See [semver.org](https://semver.org/) to learn more about semantic versioning.

Extension images must be multi-arch images so that users can install extensions on ARM/AMD hardware. These multi-arch images can include ARM/AMD specific binaries. Mac users will automatically use the right image based on their architecture.
Extensions that install binaries on the host must also provide Windows binaries in the same extension image. See how to [build a multi-arch image](multi-arch.md) for your extension.

You can implement extensions without any constraints on the code repository. Docker doesn't need access to the code repository in order to use the extension. Also, you can manage new releases of your extension, without any dependency on Docker Desktop releases.

## New releases and updates

You can release a new version of your Docker extension by pushing a new image with a new tag to Docker Hub.

Any new image pushed to an image repository corresponding to an extension defines a new version of that extension. Image tags are used to identify version numbers. Extension versions must follow semver to make it easy to understand and compare versions.

Docker Desktop scans the list of extensions published in the marketplace for new versions, and provides notifications to users when they can upgrade a specific extension. Extensions that aren't part of the Marketplace don't have automatic update notifications at the moment.

Users can download and install the newer version of any extension without updating Docker Desktop itself.

## Extension API dependencies

Extensions must specify the Extension API version they rely on. Docker Desktop checks the extension's required version, and only proposes to install extensions that are compatible with the current Docker Desktop version installed. Users might need to update Docker Desktop in order to install the latest extensions available.

Extension image labels must specify the API version that the extension relies upon. This allows Docker Desktop to inspect newer versions of extension images without downloading the full extension image upfront.

## License on extensions and the extension SDK

The [Docker Extension SDK](https://www.npmjs.com/package/@docker/extension-api-client) is licensed under the Apache 2.0 License and is free to use.

There is no constraint on how each extension should be licensed, this is up to you to decide when creating a new extension.


---

# Part two: Publish

*Sección: Extensions*

This section describes how to make your extension available and more visible, so users can discover it and install it with a single click.

## Release your extension

After you have developed your extension and tested it locally, you are ready to release the extension and make it available for others to install and use (either internally with your team, or more publicly).

Releasing your extension consists of:

- Providing information about your extension: description, screenshots, etc. so users can decide to install your extension
- [Validating](validate.md) that the extension is built in the right format and includes the required information
- Making the extension image available on [Docker Hub](https://hub.docker.com/)

See [Package and release your extension](distribution.md) for more details about the release process.

## Promote your extension

Once your extension is available on Docker Hub, users who have access to the extension image can install it using the Docker CLI.

### Use a share extension link

You can also [generate a share URL](share.md) in order to share your extension within your team, or promote your extension on the internet. The share link lets users view the extension description and screenshots.

### Publish your extension in the Marketplace

You can publish your extension in the Extensions Marketplace to make it more discoverable. You must [submit your extension](publish.md) if you want to have it published in the Marketplace.

## What happens next

### New releases

Once you have released your extension, you can push a new release just by pushing a new version of the extension image, with an incremented tag (still using `semver` conventions).
Extensions published in the Marketplace benefit from update notifications to all Desktop users that have installed the extension. For more details, see [new releases and updates](distribution.md#new-releases-and-updates).

### Extension support and user feedback

In addition to providing a description of your extension's features and screenshots, you should also specify additional URLs using [extension labels](labels.md). This direct users to your website for reporting bugs and feedback, and accessing documentation and support.

{{% include "extensions-form.md" %}}


---

# Extension image labels

*Sección: Extensions*

Extensions use image labels to provide additional information such as a title, description, screenshots, and more.

This information is then displayed as an overview of the extension, so users can choose to install it.

![An extension overview, generated from labels](images/marketplace-details.png)

You can define [image labels](../../../build/concepts/dockerfile.md#label) in the extension's `Dockerfile`.

> [!IMPORTANT]
>
> If any of the **required** labels are missing in the `Dockerfile`, Docker Desktop considers the extension invalid and doesn't list it in the Marketplace.


Here is the list of labels you can or need to specify when building your extension:

| Label                                       | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           | Example                                                                                                                                                                                                                                                         |
| ------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `org.opencontainers.image.title`            | Yes      | Human-readable title of the image (string). This appears in the UI for Docker Desktop.                                                                                                                                                                                                                                                                                                                                                                                                                | my-extension                                                                                                                                                                                                                                                    |
| `org.opencontainers.image.description`      | Yes      | Human-readable description of the software packaged in the image (string)                                                                                                                                                                                                                                                                                                                                                                                                                             | This extension is cool.                                                                                                                                                                                                                                         |
| `org.opencontainers.image.vendor`           | Yes      | Name of the distributing entity, organization, or individual.                                                                                                                                                                                                                                                                                                                                                                                                                                         | Acme, Inc.                                                                                                                                                                                                                                                      |
| `com.docker.desktop.extension.api.version`  | Yes      | Version of the Docker Extension manager that the extension is compatible with. It must follow [semantic versioning](https://semver.org/).                                                                                                                                                                                                                                                                                                                                                             | A specific version like `0.1.0` or, a constraint expression: `>= 0.1.0`, `>= 1.4.7, < 2.0` . For your first extension, you can use `docker extension version` to know the SDK API version and specify `>= <SDK_API_VERSION>`.                                   |
| `com.docker.desktop.extension.icon`         | Yes      | The extension icon (format: .svg .png .jpg)                                                                                                                                                                                                                                                                                                                                                                                                                                                           | `https://example.com/assets/image.svg`                                                                                                                                                                                                                          |
| `com.docker.extension.screenshots`          | Yes      | A JSON array of image URLs and an alternative text displayed to users (in the order they appear in your metadata) in your extension's details page. **Note:** The recommended size for screenshots is 2400x1600 pixels.                                                                                                                                                                                                                                                                               | `[{"alt":"alternative text for image 1",` `"url":"https://example.com/image1.png"},` `{"alt":"alternative text for image2",` `"url":"https://example.com/image2.jpg"}]`                                                                                         |
| `com.docker.extension.detailed-description` | Yes      | Additional information in plain text or HTML about the extension to display in the details dialog.                                                                                                                                                                                                                                                                                                                                                                                                    | `My detailed description` or `<h1>My detailed description</h1>`                                                                                                                                                                                                 |
| `com.docker.extension.publisher-url`        | Yes      | The publisher website URL to display in the details dialog.                                                                                                                                                                                                                                                                                                                                                                                                                                           | `https://example.com`                                                                                                                                                                                                                                           |
| `com.docker.extension.additional-urls`      | No       | A JSON array of titles and additional URLs displayed to users (in the order they appear in your metadata) in your extension's details page. Docker recommends you display the following links if they apply: documentation, support, terms of service, and privacy policy links.                                                                                                                                                                                                                      | `[{"title":"Documentation","url":"https://example.com/docs"},` `{"title":"Support","url":"https://example.com/bar/support"},` `{"title":"Terms of Service","url":"https://example.com/tos"},` `{"title":"Privacy policy","url":"https://example.com/privacy"}]` |
| `com.docker.extension.changelog`            | Yes      | Changelog in plain text or HTML containing the change for the current version only.                                                                                                                                                                                                                                                                                                                                                                                                                   | `Extension changelog` or `<p>Extension changelog<ul>` `<li>New feature A</li>` `<li>Bug fix on feature B</li></ul></p>`                                                                                                                                         |
| `com.docker.extension.account-info`         | No       | Whether the user needs to register to a SaaS platform to use some features of the extension.                                                                                                                                                                                                                                                                                                                                                                                                          | `required` in case it does, leave it empty otherwise.                                                                                                                                                                                                           |
| `com.docker.extension.categories`           | No       | The list of Marketplace categories that your extension belongs to: `ci-cd`, `container-orchestration`, `cloud-deployment`, `cloud-development`, `database`, `kubernetes`, `networking`, `image-registry`, `security`, `testing-tools`, `utility-tools`,`volumes`. If you don't specify this label, users won't be able to find your extension in the Extensions Marketplace when filtering by a category. Extensions published to the Marketplace before the 22nd of September 2022 have been auto-categorized by Docker. | Specified as comma separated values in case of having multiple categories e.g: `kubernetes,security` or a single value e.g. `kubernetes`.                                                                                                   |

> [!TIP]
>
> Docker Desktop applies CSS styles to the provided HTML content. You can make sure that it renders correctly 
> [within the Marketplace](#preview-the-extension-in-the-marketplace). It is recommended that you follow the 
> [styling guidelines](../design/index.md).

## Preview the extension in the Marketplace

You can validate that the image labels render as you expect.

When you create and install your unpublished extension, you can preview the extension in the Marketplace's **Managed** tab. You can see how the extension labels render in the list and in the details page of the extension.

> Preview extensions already listed in Marketplace
>
> When you install a local image of an extension already published in the Marketplace, for example with the tag `latest`, your local image is not detected as "unpublished".
>
> You can re-tag your image in order to have a different image name that's not listed as a published extension.
> Use `docker tag org/published-extension unpublished-extension` and then `docker extension install unpublished-extension`.

![List preview](images/list-preview.png)


---

# Build multi-arch extensions

*Sección: Extensions*

It is highly recommended that, at a minimum, your extension is supported for the following architectures:

- `linux/amd64`
- `linux/arm64`

Docker Desktop retrieves the extension image according to the user’s system architecture. If the extension does not provide an image that matches the user’s system architecture, Docker Desktop is not able to install the extension. As a result, users can’t run the extension in Docker Desktop.

## Build and push for multiple architectures

If you created an extension from the `docker extension init` command, the
`Makefile` at the root of the directory includes a target with name
`push-extension`.

You can run `make push-extension` to build your extension against both
`linux/amd64` and `linux/arm64` platforms, and push them to Docker Hub.

For example:

```console
$ make push-extension
```

Alternatively, if you started from an empty directory, use the command below
to build your extension for multiple architectures:

```console
$ docker buildx build --push --platform=linux/amd64,linux/arm64 --tag=username/my-extension:0.0.1 .
```

You can then check the image manifest to see if the image is available for both
architectures using the [`docker buildx imagetools` command](/reference/cli/docker/buildx/imagetools/):

```console
$ docker buildx imagetools inspect username/my-extension:0.0.1
Name:      docker.io/username/my-extension:0.0.1
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:f3b552e65508d9203b46db507bb121f1b644e53a22f851185d8e53d873417c48

Manifests:
  Name:      docker.io/username/my-extension:0.0.1@sha256:71d7ecf3cd12d9a99e73ef448bf63ae12751fe3a436a007cb0969f0dc4184c8c
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/amd64

  Name:      docker.io/username/my-extension:0.0.1@sha256:5ba4ceea65579fdd1181dfa103cc437d8e19d87239683cf5040e633211387ccf
  MediaType: application/vnd.docker.distribution.manifest.v2+json
  Platform:  linux/arm64
```

> [!TIP]
>
> If you're having trouble pushing the image, make sure you're signed in to Docker Hub. Otherwise, run `docker login` to authenticate.

For more information, see [Multi-platform images](../../../build/building/multi-platform.md) page.

## Adding multi-arch binaries

If your extension includes some binaries that deploy to the host, it’s important that they also have the right architecture when building the extension against multiple architectures.

Currently, Docker does not provide a way to explicitly specify multiple binaries for every architecture in the `metadata.json` file. However, you can add architecture-specific binaries depending on the `TARGETARCH` in the extension’s `Dockerfile`.

The following example shows an extension that uses a binary as part of its operations. The extension needs to run both in Docker Desktop for Mac and Windows.

In the `Dockerfile`, download the binary depending on the target architecture:

```Dockerfile
#syntax=docker/dockerfile:1.3-labs

FROM alpine AS dl
WORKDIR /tmp
RUN apk add --no-cache curl tar
ARG TARGETARCH
RUN <<EOT ash
    mkdir -p /out/darwin
    curl -fSsLo /out/darwin/kubectl "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/darwin/${TARGETARCH}/kubectl"
    chmod a+x /out/darwin/kubectl
EOT
RUN <<EOT ash
    if [ "amd64" = "$TARGETARCH" ]; then
        mkdir -p /out/windows
        curl -fSsLo /out/windows/kubectl.exe "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/windows/amd64/kubectl.exe"
    fi
EOT

FROM alpine
LABEL org.opencontainers.image.title="example-extension" \
    org.opencontainers.image.description="My Example Extension" \
    org.opencontainers.image.vendor="Docker Inc." \
    com.docker.desktop.extension.api.version=">= 0.3.3"

COPY --from=dl /out /
```

In the `metadata.json` file, specify the path for every binary on every platform:

```json
{
  "icon": "docker.svg",
  "ui": {
    "dashboard-tab": {
      "title": "Example Extension",
      "src": "index.html",
      "root": "ui"
    }
  },
  "host": {
    "binaries": [
      {
        "darwin": [
          {
            "path": "/darwin/kubectl"
          }
        ],
        "windows": [
          {
            "path": "/windows/kubectl.exe"
          }
        ]
      }
    ]
  }
}
```

As a result, when `TARGETARCH` equals:

- `arm64`, the `kubectl` binary fetched corresponds to the `arm64` architecture, and is copied to `/darwin/kubectl` in the final stage.
- `amd64`, two `kubectl` binaries are fetched. One for Darwin and another for Windows. They are copied to `/darwin/kubectl` and `/windows/kubectl.exe` respectively, in the final stage.

> [!NOTE]
>
> The binary destination path for Darwin is `darwin/kubectl` in both cases. The only change is the architecture-specific binary that is downloaded.

When the extension is installed, the extension framework copies the binaries from the extension image at `/darwin/kubectl` for Darwin, or `/windows/kubectl.exe` for Windows, to a specific location in the user’s host filesystem.

## Can I develop extensions that run Windows containers?

Although Docker Extensions is supported on Docker Desktop for Windows, Mac, and Linux, the extension framework only supports Linux containers. Therefore, you must target `linux` as the OS when you build your extension image.


---

# Publish in the Marketplace

*Sección: Extensions*

> [!IMPORTANT]
>
> New submissions to the Docker Extensions Marketplace are paused while Docker reviews Marketplace security. You can still update existing extensions, and private Marketplace extensions are unaffected. Contact extensions@docker.com if you have additional questions.

## Submit your extension to the Marketplace

Docker Desktop displays published extensions in the Extensions Marketplace on [Docker Desktop](https://open.docker.com/extensions/marketplace) and [Docker Hub](https://hub.docker.com/search?q=&type=extension).
The Extensions Marketplace is a space where developers can discover extensions to improve their developer experience and propose their own extension to be available for all Desktop users.

Whenever you are [ready to publish](distribution.md) your extension in the Marketplace, you can [self-publish your extension](https://github.com/docker/extensions-submissions/issues/new?assignees=&labels=&template=1_automatic_review.yaml&title=%5BSubmission%5D%3A+)

> [!NOTE]
>
> As the Extension Marketplace continues to add new features for both Extension users and publishers, you are expected
> to maintain your extension over time to ensure it stays available in the Marketplace.

> [!IMPORTANT]
>
> The Docker manual review process for extensions is paused at the moment. Submit your extension through the [automated submission process](https://github.com/docker/extensions-submissions/issues/new?assignees=&labels=&template=1_automatic_review.yaml&title=%5BSubmission%5D%3A+)

### Before you submit

Before you submit your extension, it must pass the [validation](validate.md) checks.

It is highly recommended that your extension follows the guidelines outlined in this section before submitting your
extension. If you request a review from the Docker Extensions team and have not followed the guidelines, the review process may take longer. 

These guidelines don't replace Docker's terms of service or guarantee approval:
- Review the [design guidelines](../design/design-guidelines.md)
- Ensure the [UI styling](../design/index.md) is in line with Docker Desktop guidelines
- Ensure your extensions support both light and dark mode
- Consider the needs of both new and existing users of your extension
- Test your extension with potential users
- Test your extension for crashes, bugs, and performance issues
- Test your extension on various platforms (Mac, Windows, Linux)
- Read the [Terms of Service](https://www.docker.com/legal/extensions_marketplace_developer_agreement/)

#### Validation process

Submitted extensions go through an automated validation process. If all the validation checks pass successfully, the extension is
published on the Marketplace and accessible to all users within a few hours.
It is the fastest way to get developers the tools they need and to get feedback from them as you work to
evolve/polish your extension.

> [!IMPORTANT]
>
> Docker Desktop caches the list of extensions available in the Marketplace for 12 hours. If you don't see your
> extension in the Marketplace, you can restart Docker Desktop to force the cache to refresh.


---

# Share your extension

*Sección: Extensions*

Once your extension image is accessible on Docker Hub, anyone with access to the image can install the extension.

People can install your extension by typing `docker extension install my/awesome-extension:latest` in to the terminal.

However, this option doesn't provide a preview of the extension before it's installed.

## Create a share URL

Docker lets you share your extensions using a URL.

When people navigate to this URL, it opens Docker Desktop and displays a preview of your extension in the same way as an extension in the Marketplace. From the preview, users can then select **Install**.

![Navigate to extension link](images/open-share.png)

To generate this link you can either:

- Run the following command:

  ```console
  $ docker extension share my/awesome-extension:0.0.1
  ```

- Once you have installed your extension locally, navigate to the **Manage** tab and select **Share**.

  ![Share button](images/list-preview.png)

> [!NOTE]
>
> Previews of the extension description or screenshots, for example, are created using [extension labels](labels.md).


---

# Validate your extension

*Sección: Extensions*

Validate your extension before you share or publish it. Validating the extension ensures that the extension:

- Is built with the [image labels](labels.md) it requires to display correctly in the marketplace
- Installs and runs without problems

The Extensions CLI lets you validate your extension before installing and running it locally.

The validation checks if the extension’s `Dockerfile` specifies all the required labels and if the metadata file is valid against the JSON schema file.

To validate, run:

```console
$ docker extension validate <name-of-your-extension>
```

If your extension is valid, the following message displays:

```console
The extension image "name-of-your-extension" is valid
```

Before the image is built, it's also possible to validate only the `metadata.json` file:

```console
$ docker extension validate /path/to/metadata.json
```

The JSON schema used to validate the `metadata.json` file against can be found under the [releases page](https://github.com/docker/extensions-sdk/releases/latest).


---

# Developer Guides

*Sección: Extensions*




---

# Invoke host binaries

*Sección: Extensions*

In some cases, your extension may need to invoke some command from the host. For example, you
might want to invoke the CLI of your cloud provider to create a new resource, or the CLI of a tool your extension
provides, or even a shell script that you want to run on the host. 

You could do that by executing the CLI from a container with the extension SDK. But this CLI needs to access the host's filesystem, which isn't easy nor fast if it runs in a container.

This page describes how to run executables on the host (binaries, shell scripts) that are shipped as part of your extension and deployed to the host. As extensions can run on multiple platforms, this
means that you need to ship the executables for all the platforms you want to support.

Learn more about extensions [architecture](../architecture/index.md).

> [!NOTE]
>
>  Note that extensions run with user access rights, this API is not restricted to binaries listed in the [host section](../architecture/metadata.md#host-section) of the extension metadata (some extensions might install software during user interaction, and invoke newly installed binaries even if not listed in the extension metadata).

In this example, the CLI is a simple `Hello world` script that must be invoked with a parameter and returns a 
string.

## Add the executables to the extension

{{< tabs >}}
{{< tab name="Mac and Linux" >}}

Create a `bash` script for macOS and Linux, in the file `binaries/unix/hello.sh` with the following content:

```bash
#!/bin/sh
echo "Hello, $1!"
```

{{< /tab >}}
{{< tab name="Windows" >}}

Create a `batch script` for Windows in another file `binaries/windows/hello.cmd` with the following content:

```bash
@echo off
echo "Hello, %1!"
```

{{< /tab >}}
{{< /tabs >}}

Then update the `Dockerfile` to copy the `binaries` folder into the extension's container filesystem and make the
files executable.

```dockerfile
# Copy the binaries into the right folder
COPY --chmod=0755 binaries/windows/hello.cmd /windows/hello.cmd
COPY --chmod=0755 binaries/unix/hello.sh /linux/hello.sh
COPY --chmod=0755 binaries/unix/hello.sh /darwin/hello.sh
```

## Invoke the executable from the UI

In your extension, use the Docker Desktop Client object to [invoke the shell script](../dev/api/backend.md#invoke-an-extension-binary-on-the-host)
provided by the extension with the `ddClient.extension.host.cli.exec()` function.
In this example, the binary returns a string as result, obtained by `result?.stdout`, as soon as the extension view is rendered.

{{< tabs group="framework" >}}
{{< tab name="React" >}}

```typescript
export function App() {
  const ddClient = createDockerDesktopClient();
  const [hello, setHello] = useState("");

  useEffect(() => {
    const run = async () => {
      let binary = "hello.sh";
      if (ddClient.host.platform === 'win32') {
        binary = "hello.cmd";
      }

      const result = await ddClient.extension.host?.cli.exec(binary, ["world"]);
      setHello(result?.stdout);

    };
    run();
  }, [ddClient]);
    
  return (
    <div>
      {hello}
    </div>
  );
}
```

{{< /tab >}}
{{< tab name="Vue" >}}

> [!IMPORTANT]
>
> We don't have an example for Vue yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Vue)
> and let us know if you'd like a sample with Vue.

{{< /tab >}}
{{< tab name="Angular" >}}

> [!IMPORTANT]
>
> We don't have an example for Angular yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Angular)
> and let us know if you'd like a sample with Angular.

{{< /tab >}}
{{< tab name="Svelte" >}}

> [!IMPORTANT]
>
> We don't have an example for Svelte yet. [Fill out the form](https://docs.google.com/forms/d/e/1FAIpQLSdxJDGFJl5oJ06rG7uqtw1rsSBZpUhv_s9HHtw80cytkh2X-Q/viewform?usp=pp_url&entry.1333218187=Svelte)
> and let us know if you'd like a sample with Svelte.

{{< /tab >}}
{{< /tabs >}}

## Configure the metadata file

The host binaries must be specified in the `metadata.json` file so that Docker Desktop copies them on to the host when installing
the extension. Once the extension is uninstalled, the binaries that were copied are removed as well.

```json
{
  "vm": {
    ...
  },
  "ui": {
    ...
  },
  "host": {
    "binaries": [
      {
        "darwin": [
          {
            "path": "/darwin/hello.sh"
          }
        ],
        "linux": [
          {
            "path": "/linux/hello.sh"
          }
        ],
        "windows": [
          {
            "path": "/windows/hello.cmd"
          }
        ]
      }
    ]
  }
}
```

The `path` must reference the path of the binary inside the container.


---

# Interacting with Kubernetes from an extension

*Sección: Extensions*

The Extensions SDK does not provide any API methods to directly interact with the Docker Desktop managed Kubernetes cluster or any other created using other tools such as KinD. However, this page provides a way for you to use other SDK APIs to interact indirectly with a Kubernetes cluster from your extension.

To request an API that directly interacts with Docker Desktop-managed Kubernetes, you can upvote [this issue](https://github.com/docker/extensions-sdk/issues/181) in the Extensions SDK GitHub repository.

## Prerequisites

### Turn on Kubernetes

You can use the built-in Kubernetes in Docker Desktop to start a Kubernetes single-node cluster.
A `kubeconfig` file is used to configure access to Kubernetes when used in conjunction with the `kubectl` command-line tool, or other clients.
Docker Desktop conveniently provides the user with a local preconfigured `kubeconfig` file and `kubectl` command within the user’s home area. It is a convenient way to fast-tracking access for those looking to leverage Kubernetes from Docker Desktop.

## Ship the `kubectl` as part of the extension

If your extension needs to interact with Kubernetes clusters, it is recommended that you include the `kubectl` command line tool as part of your extension. By doing this, users who install your extension get `kubectl` installed on their host.

To find out how to ship the `kubectl` command line tool for multiple platforms as part of your Docker Extension image, see [Build multi-arch extensions](../extensions/multi-arch.md#adding-multi-arch-binaries).

## Examples

The following code snippets have been put together in the [Kubernetes Sample Extension](https://github.com/docker/extensions-sdk/tree/main/samples/kubernetes-sample-extension). It shows how to interact with a Kubernetes cluster by shipping the `kubectl` command-line tool.

### Check the Kubernetes API server is reachable

Once the `kubectl` command-line tool is added to the extension image in the `Dockerfile`, and defined in the `metadata.json`, the Extensions framework deploys `kubectl` to the users' host when the extension is installed.

You can use the JS API `ddClient.extension.host?.cli.exec` to issue `kubectl` commands to, for instance, check whether the Kubernetes API server is reachable given a specific context:

```typescript
const output = await ddClient.extension.host?.cli.exec("kubectl", [
  "cluster-info",
  "--request-timeout",
  "2s",
  "--context",
  "docker-desktop",
]);
```

### List Kubernetes contexts

```typescript
const output = await ddClient.extension.host?.cli.exec("kubectl", [
  "config",
  "view",
  "-o",
  "jsonpath='{.contexts}'",
]);
```

### List Kubernetes namespaces

```typescript
const output = await ddClient.extension.host?.cli.exec("kubectl", [
  "get",
  "namespaces",
  "--no-headers",
  "-o",
  'custom-columns=":metadata.name"',
  "--context",
  "docker-desktop",
]);
```

## Persisting the kubeconfig file

Below there are different ways to persist and read the `kubeconfig` file from the host filesystem. Users can add, edit, or remove Kubernetes context to the `kubeconfig` file at any time.

> Warning
>
> The `kubeconfig` file is very sensitive and if found can give an attacker administrative access to the Kubernetes Cluster.

### Extension's backend container

If you need your extension to persist the `kubeconfig` file after it's been read, you can have a backend container that exposes an HTTP POST endpoint to store the content of the file either in memory or somewhere within the container filesystem. This way, if the user navigates out of the extension to another part of Docker Desktop and then comes back, you don't need to read the `kubeconfig` file again.

```typescript
export const updateKubeconfig = async () => {
  const kubeConfig = await ddClient.extension.host?.cli.exec("kubectl", [
    "config",
    "view",
    "--raw",
    "--minify",
    "--context",
    "docker-desktop",
  ]);
  if (kubeConfig?.stderr) {
    console.log("error", kubeConfig?.stderr);
    return false;
  }

  // call backend container to store the kubeconfig retrieved into the container's memory or filesystem
  try {
    await ddClient.extension.vm?.service?.post("/store-kube-config", {
      data: kubeConfig?.stdout,
    });
  } catch (err) {
    console.log("error", JSON.stringify(err));
  }
};
```

### Docker volume

Volumes are the preferred mechanism for persisting data generated by and used by Docker containers. You can make use of them to persist the `kubeconfig` file.
By persisting the `kubeconfig` in a volume you won't need to read the `kubeconfig` file again when the extension pane closes. This makes it ideal for persisting data when navigating out of the extension to other parts of Docker Desktop.

```typescript
const kubeConfig = await ddClient.extension.host?.cli.exec("kubectl", [
  "config",
  "view",
  "--raw",
  "--minify",
  "--context",
  "docker-desktop",
]);
if (kubeConfig?.stderr) {
  console.log("error", kubeConfig?.stderr);
  return false;
}

await ddClient.docker.cli.exec("run", [
  "--rm",
  "-v",
  "my-vol:/tmp",
  "alpine",
  "/bin/sh",
  "-c",
  `"touch /tmp/.kube/config && echo '${kubeConfig?.stdout}' > /tmp/.kube/config"`,
]);
```

### Extension's `localStorage`

`localStorage` is one of the mechanisms of a browser's web storage. It allows users to save data as key-value pairs in the browser for later use.
`localStorage` does not clear data when the browser (the extension pane) closes. This makes it ideal for persisting data when navigating out of the extension to other parts of Docker Desktop.

```typescript
localStorage.setItem("kubeconfig", kubeConfig);
```

```typescript
localStorage.getItem("kubeconfig");
```


---

# Authentication

*Sección: Extensions*

> [!NOTE]
>
> This page assumes that you already have an Identity Provider (IdP), such as Google, Entra ID (formerly Azure AD) or Okta, which handles the authentication process and returns an access token.

Learn how you can let users authenticate from your extension using OAuth 2.0 via a web browser, and return to your extension.

In OAuth 2.0, the term "grant type" refers to the way an application gets an access token. Although OAuth 2.0 defines several grant types, this page only describes how to authorize users from your extension using the Authorization Code grant type.

## Authorization code grant flow

The Authorization Code grant type is used by confidential and public clients to exchange an authorization code for an access token.

After the user returns to the client via the redirect URL, the application gets the authorization code from the URL and uses it to request an access token.

![Flow for OAuth 2.0](images/oauth.png)

The image above shows that:

- The Docker extension asks the user to authorize access to their data.
- If the user grants access, the extension then requests an access token from the service provider, passing the access grant from the user and authentication details to identify the client.
- The service provider then validates these details and returns an access token.
- The extension uses the access token to request the user data with the service provider.

### OAuth 2.0 terminology

- Auth URL: The endpoint for the API provider authorization server, to retrieve the auth code.
- Redirect URI: The client application callback URL to redirect to after auth. This must be registered with the API provider.

Once the user enters the username and password, they're successfully authenticated.

## Open a browser page to authenticate the user

From the extension UI, you can provide a button that, when selected, opens a new window in a browser to authenticate the user.

Use the [ddClient.host.openExternal](../dev/api/dashboard.md#open-a-url) API to open a browser to the auth URL. For
example:

```typescript
window.ddClient.openExternal("https://authorization-server.com/authorize?
  response_type=code
  &client_id=T70hJ3ls5VTYG8ylX3CZsfIu
  &redirect_uri=${REDIRECT_URI});
```

## Get the authorization code and access token

You can get the authorization code from the extension UI by listing `docker-desktop://dashboard/extension-tab?extensionId=awesome/my-extension` as the `redirect_uri` in the OAuth app you're using and concatenating the authorization code as a query parameter. The extension UI code will then be able to read the corresponding code query-param.

> [!IMPORTANT]
>
> Using this feature requires the extension SDK 0.3.3 in Docker Desktop. You need to ensure that the required SDK version for your extension set with `com.docker.desktop.extension.api.version` in [image labels](../extensions/labels.md) is higher than 0.3.3.

#### Authorization

This step is where the user enters their credentials in the browser. After the authorization is complete, the user is redirected back to your extension user interface, and the extension UI code can consume the authorization code that's part of the query parameters in the URL.

#### Exchange the Authorization Code

Next, you exchange the authorization code for an access token.

The extension must send a `POST` request to the 0Auth authorization server with the following parameters:

```text
POST https://authorization-server.com/token
&client_id=T70hJ3ls5VTYG8ylX3CZsfIu
&client_secret=YABbyHQShPeO1T3NDQZP8q5m3Jpb_UPNmIzqhLDCScSnRyVG
&redirect_uri=${REDIRECT_URI}
&code=N949tDLuf9ai_DaOKyuFBXStCNMQzuQbtC1QbvLv-AXqPJ_f
```

> [!NOTE]
>
> The client's credentials are included in the `POST` query params in this example. OAuth authorization servers may require that the credentials are sent as a HTTP Basic Authentication header or might support different formats. See your OAuth provider docs for details.

### Store the access token

The Docker Extensions SDK doesn't provide a specific mechanism to store secrets.

It's highly recommended that you use an external source of storage to store the access token.

> [!NOTE]
>
> The user interface Local Storage is isolated between extensions (an extension can't access another extension's local storage), and each extension's local storage gets deleted when users uninstall an extension.

## What's next

Learn how to [publish and distribute your extension](../extensions/index.md)


---

# Use the Docker socket from the extension backend

*Sección: Extensions*

Extensions can invoke Docker commands directly from the frontend with the SDK. 

In some cases, it is useful to also interact with Docker Engine from the backend. 

Extension backend containers can mount the Docker socket and use it to
interact with Docker Engine from the extension backend logic. Learn more about the [Docker Engine socket](/reference/cli/dockerd/#examples)

However, when mounting the Docker socket from an extension container that lives in the Desktop virtual machine, you want
to mount the Docker socket from inside the VM, and not mount `/var/run/docker.sock` from the host filesystem (using
the Docker socket from the host can lead to permission issues in containers).

In order to do so, you can use `/var/run/docker.sock.raw`. Docker Desktop mounts the socket that lives in the Desktop VM, and not from the host.

```yaml
services:
  myExtension:
    image: ${DESKTOP_PLUGIN_IMAGE}
    volumes:
      - /var/run/docker.sock.raw:/var/run/docker.sock
```


---

# The build and publish process

*Sección: Extensions*

This documentation is structured so that it matches the steps you need to take when creating your extension. 

There are two main parts to creating a Docker extension:

1. Build the foundations
2. Publish the extension

> [!NOTE]
>
> You do not need to pay to create a Docker extension. The [Docker Extension SDK](https://www.npmjs.com/package/@docker/extension-api-client) is licensed under the Apache 2.0 License and is free to use. Anyone can create new extensions and share them without constraints.
> 
> There is also no constraint on how each extension should be licensed, this is up to you to decide when creating a new extension.

## Part one: Build the foundations

The build process consists of:

- Installing the latest version of Docker Desktop.
- Setting up the directory with files, including the extension’s source code and the required extension-specific files.
- Creating the `Dockerfile` to build, publish, and run your extension in Docker Desktop.
- Configuring the metadata file which is required at the root of the image filesystem.
- Building and installing the extension.

For further inspiration, see the other examples in the [samples folder](https://github.com/docker/extensions-sdk/tree/main/samples).

> [!TIP]
>
> Whilst creating your extension, make sure you follow the [design](design/design-guidelines.md) and [UI styling](design/index.md) guidelines to ensure visual consistency and [level AA accessibility standards](https://www.w3.org/WAI/WCAG2AA-Conformance).

## Part two: Publish and distribute your extension

> [!IMPORTANT]
>
> New submissions to the Docker Extensions Marketplace are paused while Docker reviews Marketplace security. You can still update existing extensions, and private Marketplace extensions are unaffected. Contact extensions@docker.com if you have additional questions.

Docker Desktop displays published extensions in the Extensions Marketplace. The Extensions Marketplace is a curated space where developers can discover extensions to improve their developer experience and upload their own extension to share with the world.

If you want your extension published in the Marketplace, read the [publish documentation](extensions/publish.md).

{{% include "extensions-form.md" %}}

## What’s next?

If you want to get up and running with creating a Docker Extension, see the [Quickstart guide](quickstart.md).

Alternatively, get started with reading the "Part one: Build" section for more in-depth information about each step of the extension creation process.

For an in-depth tutorial of the entire build process, we recommend the following video walkthrough from DockerCon 2022.

<iframe width="560" height="315" src="https://www.youtube.com/embed/Yv7OG-EGJsg" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


---

# Quickstart

*Sección: Extensions*

Follow this guide to get started with creating a basic Docker extension. The Quickstart guide automatically generates boilerplate files for you.

## Prerequisites

- [Docker Desktop](../../desktop/release-notes.md)
- [NodeJS](https://nodejs.org/)
- [Go](https://go.dev/dl/)

> [!NOTE]
>
> NodeJS and Go are only required when you follow the quickstart guide to create an extension. It uses the `docker extension init` command to automatically generate boilerplate files. This command uses a template based on a ReactJS and Go application.

In Docker Desktop settings, ensure you can install the extension you're developing. You may need to navigate to the **Extensions** tab in Docker Desktop settings and deselect **Allow only extensions distributed through the Docker Marketplace**.

## Step one: Set up your directory

To set up your directory, use the `init` subcommand and provide a name for your extension.

```console
$ docker extension init <my-extension>
```

The command asks a series of questions about your extension, such as its name, a description, and the name of your Hub repository. This helps the CLI generate a set of boilerplate files for you to get started. It stores the boilerplate files in the `my-extension` directory.

The automatically generated extension contains:

- A Go backend service in the `backend` folder that listens on a socket. It has one endpoint `/hello` that returns a JSON payload.
- A React frontend in the `frontend` folder that can call the backend and output the backend’s response.

For more information and guidelines on building the UI, see the [Design and UI styling section](design/design-guidelines.md).

## Step two: Build the extension

To build the extension, move into the newly created directory and run:

```console
$ docker build -t <name-of-your-extension> .
```

`docker build` builds the extension and generates an image named the same as the chosen hub repository. For example, if you typed `john/my-extension` as the answer to the following question:

```console
? Hub repository (eg. namespace/repository on hub): john/my-extension`
```

The `docker build` generates an image with name `john/my-extension`.

## Step three: Install and preview the extension

To install the extension in Docker Desktop, run:

```console
$ docker extension install <name-of-your-extension>
```

To preview the extension in Docker Desktop, once the installation is complete and you should
see a **Quickstart** item underneath the **Extensions** menu. Selecting this item opens the extension's frontend.

> [!TIP]
>
> During UI development, it’s helpful to use hot reloading to test your changes without rebuilding your entire
> extension. See [Preview whilst developing the UI](dev/test-debug.md#hot-reloading-whilst-developing-the-ui) for more information.

You may also want to inspect the containers that belong to the extension. By default, extension containers are
hidden from the Docker Dashboard. You can change this in **Settings**, see
[how to show extension containers](dev/test-debug.md#show-the-extension-containers) for more information.

## Step four: Submit and publish your extension to the Marketplace

> [!IMPORTANT]
>
> New submissions to the Docker Extensions Marketplace are paused while Docker reviews Marketplace security. You can still update existing extensions, and private Marketplace extensions are unaffected. Contact extensions@docker.com if you have additional questions.

If you want to make your extension available to all Docker Desktop users, you can submit it for publication in the Marketplace. For more information, see [Publish](extensions/index.md).

## Clean up

To remove the extension, run:

```console
$ docker extension rm <name-of-your-extension>
```

## What's next

- Build a more [advanced frontend](build/frontend-extension-tutorial.md) for your extension.
- Learn how to [test and debug](dev/test-debug.md) your extension.
- Learn how to [setup CI for your extension](dev/continuous-integration.md).
- Learn more about extensions [architecture](architecture/index.md).
- Learn more about [designing the UI](design/design-guidelines.md).


---

# Marketplace extensions

*Sección: Extensions*

There are two types of extensions available in the Extensions Marketplace:
- Docker-reviewed extensions
- Self-published extensions

Docker-reviewed extensions are manually reviewed by the Docker Extensions team to ensure an extra level of trust
and quality. They appear as **Reviewed** in the Marketplace.

Self-published extensions are autonomously published by extension developers and go through an automated validation process. They appear as **Not reviewed** in the Marketplace.

> [!IMPORTANT]
>
> Marketplace extensions are reviewed by Docker, but are not subject to a full security audit. Extensions run with host-level privileges. They can install binaries, access Docker Engine, invoke commands, and access files on your machine. Only install extensions from publishers you trust.

## Install an extension

> [!NOTE]
>
> For some extensions, a separate account needs to be created before use.

To install an extension:

1. Open Docker Desktop.
2. From the Docker Desktop Dashboard, select the **Extensions** tab.
   The Extensions Marketplace opens on the **Browse** tab.
3. Browse the available extensions.
   You can sort the list of extensions by **Recently added**, **Most installed**, or alphabetically. Alternatively, use the **Content** or **Categories** drop-down menu to search for extensions by whether they have been reviewed or not, or by category.
4. Choose an extension and select **Install**.

From here, you can select **Open** to access the extension or install additional extensions. The extension also appears in the left-hand menu and in the **Manage** tab.

## Update an extension

You can update any extension outside of Docker Desktop releases. To update an extension to the latest version, navigate to the Docker Desktop Dashboard and select the **Manage** tab.

The **Manage** tab displays with all your installed extensions. If an extension has a new version available, it displays an **Update** button.


## Uninstall an extension

You can uninstall an extension at any time.

> [!NOTE]
>
> Any data used by the extension that's stored in a volume must be manually deleted.

1. Navigate to the Docker Desktop Dashboard and select the **Manage** tab.
   This displays a list of extensions you've installed.
2. Select the ellipsis to the right of extension you want to uninstall.
3. Select **Uninstall**.


---

# Non-marketplace extensions

*Sección: Extensions*

## Install an extension not available in the Marketplace

> [!WARNING]
>
> Extensions installed outside the Marketplace have not gone through Docker's review process. Like all Docker extensions, they run with host-level privileges. They can install binaries, access Docker Engine, invoke commands, and access files on your machine. Install only if you trust the publisher and have verified the source.

The Extensions Marketplace is the trusted and official place to install extensions from within Docker Desktop. These extensions have gone through a review process by Docker. However, other extensions can also be installed in Docker Desktop if you trust the extension author.

Given the nature of a Docker Extension (i.e. a Docker image) you can find other places where users have their extension's source code published. For example on GitHub, GitLab or even hosted in image registries like DockerHub or GHCR.
You can install an extension that has been developed by the community or internally at your company from a teammate. You are not limited to installing extensions just from the Marketplace.

> [!NOTE]
>
> Ensure the option **Allow only extensions distributed through the Docker Marketplace** is disabled. Otherwise, this prevents any extension not listed in the Marketplace, via the Extension SDK tools from, being installed.
> You can change this option in **Settings**. 

To install an extension which is not present in the Marketplace, you can use the Extensions CLI that is bundled with Docker Desktop.

In a terminal, type `docker extension install IMAGE[:TAG]` to install an extension by its image reference and optionally a tag. Use the `-f` or `--force` flag to avoid interactive confirmation.

Go to the Docker Desktop Dashboard to see the new extension installed.

## List installed extensions

Regardless whether the extension was installed from the Marketplace or manually by using the Extensions CLI, you can use the `docker extension ls` command to display the list of extensions installed.
As part of the output you'll see the extension ID, the provider, version, the title and whether it runs a backend container or has deployed binaries to the host, for example:

```console
$ docker extension ls
ID                  PROVIDER            VERSION             UI                    VM                  HOST
john/my-extension   John                latest              1 tab(My-Extension)   Running(1)          -
```

Go to the Docker Desktop Dashboard, select **Add Extensions** and on the **Managed** tab to see the new extension installed.
Notice that an `UNPUBLISHED` label displays which indicates that the extension has not been installed from the Marketplace.

## Update an extension 

To update an extension which isn't present in the Marketplace, in a terminal type `docker extension update IMAGE[:TAG]` where the `TAG` should be different from the extension that's already installed.

For instance, if you installed an extension with `docker extension install john/my-extension:0.0.1`, you can update it by running `docker extension update john/my-extension:0.0.2`.
Go to the Docker Desktop Dashboard to see the new extension updated.

> [!NOTE]
>
> Extensions that aren't installed through the Marketplace don't receive update notifications from Docker Desktop.

## Uninstall an extension

To uninstall an extension which is not present in the Marketplace, you can either navigate to the **Managed** tab in the Marketplace and select the **Uninstall** button, or from a terminal type `docker extension uninstall IMAGE[:TAG]`.


---

# Configure a private marketplace for extensions

*Sección: Extensions*

{{< summary-bar feature_name="Private marketplace" >}}

Learn how to configure and set up a private marketplace with a curated list of extensions for your Docker Desktop users.

Docker Extensions' private marketplace is designed specifically for organizations who don’t give developers root access to their machines. It makes use of [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md) so administrators have complete control over the private marketplace.

## Prerequisites

- [Download and install Docker Desktop](https://docs.docker.com/desktop/release-notes/).
- You must be an administrator for your organization.
- You have the ability to push the `extension-marketplace` folder and `admin-settings.json` file to the locations specified below through device management software such as [Jamf](https://www.jamf.com/).

## Step one: Initialize the private marketplace

1. Create a folder locally for the content that will be deployed to your developers’ machines:

   ```console
   $ mkdir my-marketplace
   $ cd my-marketplace
   ```

2. Initialize the configuration files for your marketplace:

   {{< tabs group="os_version" >}}
   {{< tab name="Mac" >}}

   ```console
   $ /Applications/Docker.app/Contents/Resources/bin/extension-admin init
   ```

   {{< /tab >}}
   {{< tab name="Windows" >}}

   ```console
   # For all-user installations
   $ C:\Program Files\Docker\Docker\resources\bin\extension-admin init

   # For per-user installations
   $ %LOCALAPPDATA%\Programs\DockerDesktop\resources\bin\extension-admin init
   ```

   {{< /tab >}}
   {{< tab name="Linux" >}}

   ```console
   $ /opt/docker-desktop/extension-admin init
   ```

   {{< /tab >}}
   {{< /tabs >}}

This creates 2 files:

- `admin-settings.json`, which activates the private marketplace feature once it’s applied to Docker Desktop on your developers’ machines.
- `extensions.txt`, which determines which extensions to list in your private marketplace.

> [!IMPORTANT]
>
> If your org is using [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md) via [Docker Home](manuals/enterprise/security/hardened-desktop/settings-management/configure-admin-console/_index.md), you will not need the `admin-settings.json` file. Delete the generated file and keep only the `extensions.txt` file.

## Step two: Set the behaviour

The generated `admin-settings.json` file includes various settings you can modify.

> [!IMPORTANT]
>
> If your org is managing settings via [Docker Home](manuals/enterprise/security/hardened-desktop/settings-management/configure-admin-console/_index.md), you will define the same settings in Docker Home instead of the `admin-settings.json` file.

Each setting has a `value` that you can set, including a `locked` field that lets you lock the setting and make it unchangeable by your developers.

- `extensionsEnabled` enables Docker Extensions.
- `extensionsPrivateMarketplace` activates the private marketplace and ensures Docker Desktop connects to content defined and controlled by the administrator instead of the public Docker marketplace.
- `onlyMarketplaceExtensions` allows or blocks developers from installing other extensions by using the command line. Teams developing new extensions must have this setting unlocked (`"locked": false`) to install and test extensions being developed.
- `extensionsPrivateMarketplaceAdminContactURL` defines a contact link for developers to request new extensions in the private marketplace. If `value` is empty then no link is shown to your developers on Docker Desktop, otherwise this can be either an HTTP link or a “mailto:” link. For example,

  ```json
  "extensionsPrivateMarketplaceAdminContactURL": {
    "locked": true,
    "value": "mailto:admin@acme.com"
  }
  ```

To find out more information about the `admin-settings.json` file, see [Settings Management](../enterprise/security/hardened-desktop/settings-management/index.md).

## Step three: List allowed extensions

The generated `extensions.txt` file defines the list of extensions that are available in your private marketplace.

Each line in the file is an allowed extension and follows the format of `org/repo:tag`.

For example, if you want to permit the Disk Usage extension you would enter the following into your `extensions.txt` file:

```console
docker/disk-usage-extension:0.2.8
```

If no tag is provided, the latest tag available for the image is used. You can also comment out lines with `#` so the extension is ignored.

This list can include different types of extension images:

- Extensions from the public marketplace or any public image stored in Docker Hub.
- Extension images stored in Docker Hub as private images. Developers need to be signed in and have pull access to these images.
- Extension images stored in a private registry. Developers need to be signed in and have pull access to these images.

> [!IMPORTANT]
>
> Your developers can only install the version of the extension that you’ve listed.

## Step four: Generate the private marketplace

Once the list in `extensions.txt` is ready, you can generate the marketplace:

{{< tabs group="os_version" >}}
{{< tab name="Mac" >}}

```console
$ /Applications/Docker.app/Contents/Resources/bin/extension-admin generate
```

{{< /tab >}}
{{< tab name="Windows" >}}

```console
# For all-user installations
$ C:\Program Files\Docker\Docker\resources\bin\extension-admin generate

# For per-user installations
$ %LOCALAPPDATA%\Programs\DockerDesktop\resources\bin\extension-admin generate
```

{{< /tab >}}
{{< tab name="Linux" >}}

```console
$ /opt/docker-desktop/extension-admin generate
```

{{< /tab >}}
{{< /tabs >}}

This creates an `extension-marketplace` directory and downloads the marketplace metadata for all the allowed extensions.

The marketplace content is generated from extension image information as image labels, which is the [same format as public extensions](extensions-sdk/extensions/labels.md). It includes the extension title, description, screenshots, links, etc.

## Step five: Test the private marketplace setup

It's recommended that you try the private marketplace on your Docker Desktop installation.

1. Run the following command in your terminal. This command automatically copies the generated files to the location where Docker Desktop reads the configuration files. Depending on your operating system, the location is:

    - Mac: `/Library/Application\ Support/com.docker.docker`
    - Windows: `C:\ProgramData\DockerDesktop`
    - Linux: `/usr/share/docker-desktop`

   {{< tabs group="os_version" >}}
   {{< tab name="Mac" >}}

   ```console
   $ sudo /Applications/Docker.app/Contents/Resources/bin/extension-admin apply
   ```

   {{< /tab >}}
   {{< tab name="Windows (run as admin)" >}}

   ```console
   # For all-user installations
   $ C:\Program Files\Docker\Docker\resources\bin\extension-admin apply

   # For per-user installations
   $ %LOCALAPPDATA%\Programs\DockerDesktop\resources\bin\extension-admin apply
   ```

   {{< /tab >}}
   {{< tab name="Linux" >}}

   ```console
   $ sudo /opt/docker-desktop/extension-admin apply
   ```

   {{< /tab >}}
   {{< /tabs >}}

2. Quit and re-open Docker Desktop. 
3. Sign in with a Docker account.

> [!IMPORTANT]
>
> > If your org is managing settings via [Docker Home](manuals/enterprise/security/hardened-desktop/settings-management/configure-admin-console/_index.md), in Docker Desktop 4.59 and earlier, you must manually delete the `admin-settings.json` file created in the target folder by the `apply` command before step 2. In Docker Desktop 4.60 and later, this step is no longer necessary. 

When you select the **Extensions** tab, you should see the private marketplace listing only the extensions you have allowed in `extensions.txt`.

![Extensions Private Marketplace](/assets/images/extensions-private-marketplace.webp)

## Step six: Distribute the private marketplace

Once you’ve confirmed that the private marketplace configuration works, the final step is to distribute the files to the developers’ machines with the MDM software your organization uses. For example, [Jamf](https://www.jamf.com/).

The files to distribute are:
* `admin-settings.json` (except if your org is managing settings via [Docker Home](manuals/enterprise/security/hardened-desktop/settings-management/configure-admin-console/_index.md))
* the entire `extension-marketplace` folder and its subfolders

These files must be placed on developer's machines. Depending on your operating system, the target location is (as mentioned above):

- Mac: `/Library/Application\ Support/com.docker.docker`
- Windows: `C:\ProgramData\DockerDesktop`
- Linux: `/usr/share/docker-desktop`

Make sure your developers are signed in to Docker Desktop in order for the private marketplace configuration to take effect. As an administrator, you should [enforce sign-in](../enterprise/security/enforce-sign-in/index.md).

## Feedback

Give feedback or report any bugs you may find by emailing `extensions@docker.com`.


---

# Settings and feedback for Docker Extensions

*Sección: Extensions*

## Settings

### Turn on or turn off extensions

Docker Extensions is switched off by default. To change your settings:

1. Navigate to **Settings**.
2. Select the **Extensions** tab.
3. Next to **Enable Docker Extensions**, select or clear the checkbox to set your desired state.
4. In the bottom-right corner, select **Apply**.

> [!NOTE]
>
> If you are an [organization owner](../accounts/organization/manage/manage-a-team.md#what-is-an-organization-owner), you can turn off extensions for your users. Open the `settings-store.json` file, and set `"extensionsEnabled"` to `false`.
> The `settings-store.json` file is located at:
>   - `~/Library/Group Containers/group.com.docker/settings-store.json` on Mac
>   - `C:\Users\[USERNAME]\AppData\Roaming\Docker\settings-store.json` on Windows
>
> This can also be done with [Hardened Docker Desktop](../enterprise/security/hardened-desktop/index.md)

### Turn on or turn off extensions not available in the Marketplace

You can install extensions through the Marketplace or through the Extensions SDK tools. You can choose to only allow published extensions. These are extensions that have been reviewed and published in the Extensions Marketplace.

1. Navigate to **Settings**.
2. Select the **Extensions** tab.
3. Next to **Allow only extensions distributed through the Docker Marketplace**, select or clear the checkbox to set your desired state.
4. In the bottom-right corner, select **Apply**.

### See containers created by extensions

By default, containers created by extensions are hidden from the list of containers in the Docker Desktop Dashboard and the Docker CLI. To make them visible
update your settings:

1. Navigate to **Settings**.
2. Select the **Extensions** tab.
3. Next to **Show Docker Extensions system containers**, select or clear the checkbox to set your desired state.
4. In the bottom-right corner, select **Apply**.

> [!NOTE]
>
> Enabling extensions doesn't use computer resources (CPU / Memory) by itself.
>
> Specific extensions might use computer resources, depending on the features and implementation of each extension, but there is no reserved resources or usage cost associated with enabling extensions.

## Submit feedback

Feedback can be given to an extension author through a dedicated Slack channel or GitHub. To submit feedback about a particular extension:

1. Navigate to the Docker Desktop Dashboard and select the **Manage** tab.
   This displays a list of extensions you've installed.
2. Select the extension you want to provide feedback on. 
3. Scroll down to the bottom of the extension's description and, depending on the 
extension, select:
    - Support
    - Slack
    - Issues. You'll be sent to a page outside of Docker Desktop to submit your feedback.

If an extension doesn't provide a way for you to give feedback, contact us and we'll pass on the feedback for you. To provide feedback, select the **Give feedback** to the right of **Extensions Marketplace**.


---

# FAQs

*Sección: Faqs*

Answers to common questions about Docker accounts, organizations, companies,
subscriptions, billing, and security.

## Next steps

{{< grid >}}


---

# Account FAQs

*Sección: Faqs*

## Individual accounts

### What is a Docker ID?

A Docker ID is a username for your Docker account that lets you access Docker
products. To create a Docker ID you need one of the following:

- An email address
- A Google account
- A GitHub account

Your Docker ID must be between 4 and 30 characters long, and can only contain
numbers and lowercase letters. You can't use any special characters or spaces.

For more information, see
[Create a Docker account](../accounts/individual/create-account.md).

### Can I change my Docker ID?

No. You can't change your Docker ID once it's created. If you need a different
Docker ID, you must create a new Docker account with a new Docker ID.

Docker IDs can't be reused after deactivation.

### What if my Docker ID is taken?

All Docker IDs are first-come, first-served except for companies that have a
U.S. Trademark on a username.

If you have a trademark for your Docker ID,
[Docker Support](https://hub.docker.com/support/contact/) can retrieve the
Docker ID for you.

## Organizations

### What's an organization name or namespace?

The organization name, sometimes referred to as the organization namespace or
the organization ID, is the unique identifier of a Docker organization. The
organization name can't be the same as an existing Docker ID.

For more information, see
[Organization accounts](../accounts/organization/index.md).

### How can I see how many active users are in my organization?

If your organization uses a Software Asset Management tool, you can use it to
find out how many users have Docker Desktop installed. If your organization
doesn't use this software, you can run an internal survey
to find out who is using Docker Desktop.

For more information, see [Identify your Docker users and their Docker accounts](../accounts/organization/setup/onboard.md#step-one-identify-your-docker-users).

### Do users need to authenticate with Docker before an owner can add them to an organization?

No. Organization owners can invite users with their email addresses, and also
assign them to a team during the invite process.

### Can I force my organization's members to authenticate before using Docker Desktop and are there any benefits?

Yes. You can
[enforce sign-in](../enterprise/security/enforce-sign-in/index.md).

Some benefits of enforcing sign-in are:

- Ensures users receive the benefits of your subscription.
- Ensures security features like [Image Access Management](../enterprise/security/hardened-desktop/image-access-management.md) and [Registry Access Management](../enterprise/security/hardened-desktop/registry-access-management.md) are applied.
- Ensures you gain insights into users' activity.

### Can I convert my personal Docker ID to an organization account?

Yes. You can convert your user account to an organization account. Once you
convert a user account into an organization, it's not possible to
revert it to a personal user account.

For prerequisites and instructions, see
[Convert an account into an organization](../accounts/organization/setup/convert-account.md).

### Do organization invitees take up seats?

Yes. A user invited to an organization will take up one of the provisioned
seats, even if that user hasn’t accepted their invitation yet.

To manage invites, see [Manage organization members](../accounts/organization/manage/members.md).

### Do organization owners take a seat?

Yes. Organization owners occupy a seat.

### What is the difference between user, invitee, seat, and member?

- User: Docker user with a Docker ID.
- Invitee: A user that an administrator has invited to join an organization but
  has not yet accepted their invitation.
- Seats: The number of purchased seats in an organization.
- Member: A user who has received and accepted an invitation to join an
  organization. Member can also refer to a member of a team within an
  organization.

### If I have two organizations and a user belongs to both organizations, do they take up two seats?

Yes. In a scenario where a user belongs to two organizations, they take up one
seat in each organization.

### Companies

#### Can I use a parent company if some of my organizations don’t have a Docker Business subscription?

Yes, but you can only add organizations with a Docker Business subscription
to a company. For more details, see [Add more organizations](../accounts/company/manage.md#add-more-organizations).

#### What happens if one of my organizations downgrades from Docker Business, but I still need access as a company owner?

To access and manage a nested organization, it must have a Docker Business
subscription. If an organization downgrades from Docker Business, its owner must
manage it outside of the company. For more details, see
[Add more organizations](../accounts/company/manage.md#add-more-organizations).

#### Do company owners occupy a subscription seat?

Company owners don't occupy a seat unless one of the following is true:

- They are added as a member of an organization under your company
- SSO is enabled and the company owner signs in through SSO, which
  automatically adds them as an organization member

When you first create a company, your account is both a company owner and an
organization owner, so it occupies a seat as long as you remain an organization
owner. To free up that seat,
[assign another user as the organization owner](../accounts/organization/manage/members.md#update-a-member-role)
and remove yourself from the organization. You keep full administrative access
as a company owner without using a subscription seat.

#### What permissions does the company owner have in the associated/nested organizations?

Company owners can navigate to the **Organizations** page to view all their
nested organizations in a single location. They can also view or edit
organization members and change single sign-on (SSO) and System for
Cross-domain Identity Management (SCIM) settings. Changes to company settings
impact all users in each organization under the company.

For more information, see [Roles and permissions](/manuals/security/roles-and-permissions.md).


---

# Platform FAQs

*Sección: Faqs*

## General

### How do I report a vulnerability?

If you've discovered a security vulnerability in Docker, report it responsibly to security@docker.com so Docker can quickly address it.

### Does Docker lockout users after failed sign-ins?

Docker Hub locks out users after 10 failed sign-in attempts within 5 minutes. The lockout duration is 5 minutes. This policy applies to Docker Hub, Docker Desktop, and Docker Scout authentication.

### Do you support physical multi-factor authentication (MFA) with YubiKeys?

You can configure physical multi-factor authentication (MFA) through SSO using your identity provider (IdP). Check with your IdP if they support physical MFA devices like YubiKeys.

### How are sessions managed and do they expire?

Docker uses tokens to manage user sessions with different expiration periods:

- Docker Desktop: Signs you out after 90 days, or 30 days of inactivity
- Docker Hub and Docker Home: Sign you out after 24 hours

Docker also supports your IdP's default session timeout through SAML attributes. For more information, see [SSO attributes](../security/provisioning/index.md#sso-attributes).

### How does Docker distinguish between employee users and contractor users?

Organizations use verified domains to distinguish user types. Team members with email domains other than verified domains appear as "Guest" users in the organization.

### How long are activity logs available?

Docker activity logs are available for 90 days. You're responsible for exporting logs or setting up drivers to send logs to your internal systems for longer retention.

### Can I export a list of users with their roles and privileges?

Yes, use the [Export Members](../accounts/organization/manage/members.md#export-members-csv-file) feature to export a CSV file containing your organization's users with role and team information.

### How do I remove users who aren't part of my IdP when using SSO without SCIM?

If SCIM isn't turned on, you must manually remove users from the organization. SCIM can automate user removal, but only for users added after SCIM is turned on. Users added before SCIM was turned on must be removed manually.

For more information, see [Manage organization members](../accounts/organization/manage/members.md).

### What metadata does Scout collect from container images?

For information about metadata stored by Docker Scout, see [Data handling](../scout/deep-dive/data-handling.md).

### How are Marketplace extensions vetted for security?

Security vetting for extensions isn't implemented. Extensions aren't covered as part of Docker's Third-Party Risk Management Program.

### Can I prevent users from pushing images to Docker Hub private repositories?

No direct setting exists to disable private repositories. However, [Registry Access Management](../enterprise/security/hardened-desktop/registry-access-management.md) lets administrators control which registries developers can access through Docker Desktop via Docker Home.

## Docker Desktop

### How does Docker Desktop handle authentication information?

Docker Desktop uses the host operating system's secure key management to store authentication tokens:

- macOS: [Keychain](https://support.apple.com/guide/security/keychain-data-protection-secb0694df1a/web)
- Windows: [Security and Identity API via Wincred](https://learn.microsoft.com/en-us/windows/win32/api/wincred/)
- Linux: [Pass](https://www.passwordstore.org/).

### Containers

#### How are containers isolated from the host in Docker Desktop?

Docker Desktop runs all containers inside a customized Linux virtual machine (except for native Windows containers). This adds strong isolation between containers and the host machine, even when containers run as root.

Important considerations include:

- Containers have access to host files configured for file sharing via Docker Desktop settings
- Containers run as root with limited capabilities inside the Docker Desktop VM by default
- Privileged containers (`--privileged`, `--pid=host`, `--cap-add`) run with elevated privileges inside the VM, giving them access to VM internals and Docker Engine

With Enhanced Container Isolation turned on, each container runs in a dedicated Linux user namespace inside the Docker Desktop VM. Even privileged containers only have privileges within their container boundary, not the VM. ECI uses advanced techniques to prevent containers from breaching the Docker Desktop VM and Docker Engine.

#### Which portions of the host filesystem can containers access?

Containers can only access host files that are:

1. Shared using Docker Desktop settings
1. Explicitly bind-mounted into the container (e.g., `docker run -v /path/to/host/file:/mnt`)

#### Can containers running as root access admin-owned files on the host?

No. Host file sharing uses a user-space file server (running in `com.docker.backend` as the Docker Desktop user), so containers can only access files that the Docker Desktop user already has permission to access.

### Networking and VMs

#### How can I limit container internet access?

Docker Desktop doesn't have a built-in mechanism for this, but you can use process-level firewalls on the host. Apply rules to the `com.docker.vpnkit` user-space process to control where it can connect (DNS allowlists, packet filters) and which ports/protocols it can use.

For enterprise environments, consider [Air-gapped containers](../enterprise/security/hardened-desktop/air-gapped-containers.md) which provide network access controls for containers.

#### Can I apply firewall rules to container network traffic?

Yes. Docker Desktop uses a user-space process (`com.docker.vpnkit`) for network connectivity, which inherits constraints like firewall rules, VPN settings, and HTTP proxy properties from the user that launched it.

#### Does Docker Desktop for Windows with Hyper-V allow users to create other VMs?

No. The `DockerDesktopVM` name is hard-coded in the service, so you cannot use Docker Desktop to create or manipulate other virtual machines.

#### How does Docker Desktop achieve network isolation with Hyper-V and WSL 2?

Docker Desktop uses the same VM processes for both WSL 2 (in the `docker-desktop` distribution) and Hyper-V (in `DockerDesktopVM`). Host/VM communication uses `AF_VSOCK` hypervisor sockets (shared memory) rather than network switches or interfaces. All host networking is performed using standard TCP/IP sockets from the `com.docker.vpnkit.exe` and `com.docker.backend.exe` processes.

For more information, see [How Docker Desktop networking works under the hood](https://www.docker.com/blog/how-docker-desktop-networking-works-under-the-hood/).


---

# Security FAQs

*Sección: Faqs*

## SSO

### What SSO flows does Docker support?

Docker supports Service Provider Initiated (SP-initiated) SSO flow. Users must sign in to Docker Hub or Docker Desktop to initiate the SSO authentication process.

### Does Docker SSO support multi-factor authentication?

When an organization uses SSO, multi-factor authentication is controlled at the identity provider level, not on the Docker platform.

### Can I retain my Docker ID when using SSO?

Users with personal Docker IDs retain ownership of their repositories, images, and assets. When SSO is enforced, existing accounts with company domain emails are connected to the organization. Users signing in without existing accounts automatically have new accounts and Docker IDs created.

### Are there any firewall rules required for SSO configuration?

No specific firewall rules are required as long as `login.docker.com` is accessible. This domain is commonly accessible by default, but some organizations may need to allow it in their firewall settings if SSO setup encounters issues.

### Does Docker use my IdP's default session timeout?

Yes, Docker supports your IdP's session timeout using a custom `dockerSessionMinutes` SAML attribute instead of the standard `SessionNotOnOrAfter` element. See [SSO attributes](../security/provisioning/index.md#sso-attributes) for more information.

### Can I use multiple identity providers with Docker SSO?

Yes, Docker supports multiple IdP configurations. A domain can be associated with multiple IdPs. Docker supports Entra ID (formerly Azure AD) and identity providers that support SAML 2.0.

### Can I change my identity provider after configuring SSO?

Yes. Delete your existing IdP configuration in your Docker SSO connection, then [configure SSO using your new IdP](../security/authentication/single-sign-on/connect.md). If you had already turned on enforcement, turn off enforcement before updating the provider connection.

### What information do I need from my identity provider to configure SSO?

To turn on SSO in Docker, you need the following from your IdP:

- SAML: Entity ID, ACS URL, Single Logout URL, and the public X.509 certificate
- Entra ID (formerly Azure AD): Client ID, Client Secret, AD Domain

### What happens if my existing certificate expires?

Contact your identity provider to retrieve a new X.509 certificate. Update with the new certificate in [SSO configuration settings](../security/authentication/single-sign-on/manage.md#manage-sso-connections) from Docker Home.

- If your organization enforces SSO, username and password credentials won't work.
- If your organization doesn't enforce SSO, users can sign in with their username and password credentials.

If you need additional help, contact [Docker support](https://app.docker.com/support/contact).

### What happens if my IdP goes down when SSO is turned on?

If SSO is enforced, users can't access Docker Hub when your IdP is down. Users can still access Docker Hub images from the CLI using personal access tokens.

If SSO is turned on but not enforced, users can fall back to username/password authentication.

### Do bot accounts need seats to access organizations using SSO?

Yes, bot accounts need seats like regular users, requiring a non-aliased domain email in the IdP and using a seat in Docker Hub. You can add bot accounts to your IdP and create access tokens to replace other credentials.

### Does SAML SSO use Just-in-Time provisioning?

The SSO implementation uses Just-in-Time (JIT) provisioning by default. You can optionally turn off JIT in Docker Home if you turn on auto-provisioning using SCIM. See [Just-in-Time provisioning](../security/provisioning/just-in-time.md).

### How can I troubleshoot an Entra ID SSO connection error?

Confirm that you've configured the necessary API permissions in Entra ID for your SSO connection. You need to grant administrator consent within your Entra ID tenant. See [Entra ID (formerly Azure AD) documentation](https://learn.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent?pivots=portal#grant-admin-consent-in-app-registrations).

### Do I need to manually add users to my organization?

No, you don't need to manually add users to your organization. Just ensure user accounts exist in your IdP. When users sign in to Docker with their domain email address, they're automatically added to the organization after successful authentication.

### Can users use different email addresses to authenticate through SSO?

All users must authenticate using the email domain specified during SSO setup. Users with email addresses that don't match the verified domain can sign in as guests with username and password if SSO isn't enforced, but only if they've been invited.

### How will users know they're being added to a Docker organization?

When SSO is turned on, users are prompted to authenticate through SSO the next time they sign in to Docker Hub or Docker Desktop. The system detects their domain email and prompts them to sign in with SSO credentials instead.

For CLI access, users must authenticate using personal access tokens.

### Can I convert existing users from non-SSO to SSO accounts?

Yes, you can convert existing users to SSO accounts. Ensure users have:

- Company domain email addresses and accounts in your IdP
- Docker Desktop version 4.4.2 or later
- Personal access tokens created to replace passwords for CLI access
- CI/CD pipelines updated to use PATs instead of passwords

For detailed instructions, see [Configure single sign-on](../security/authentication/single-sign-on/connect.md).

### Is Docker SSO fully synced with the IdP?

Docker SSO provides Just-in-Time (JIT) provisioning by default. Users are provisioned when they authenticate with SSO. If users leave the organization, administrators must manually [remove the user](../accounts/organization/manage/members.md#remove-a-member-from-the-organization) from the organization.

[SCIM](../security/provisioning/scim/index.md) provides full synchronization with users and groups. When using SCIM, the recommended configuration is to turn off JIT so all auto-provisioning is handled by SCIM.

Additionally, you can use the [Docker Hub API](../reference/api/hub/latest.md) to complete this process.

### How does turning off Just-in-Time provisioning affect user sign-in?

When JIT is turned off (available with SCIM in Docker Home), users must be organization members or have pending invitations to access Docker. Users who don't meet these criteria get an "Access denied" error and need administrator invitations.

See [SSO authentication with JIT provisioning disabled](../security/provisioning/just-in-time.md#sso-authentication-with-jit-provisioning-disabled).

### Can someone join an organization without an invitation?

Not without SSO. Joining requires an invite from an organization owner. When SSO is enforced, users with verified domain emails can automatically join the organization when they sign in.

### What happens to existing licensed users when SCIM is turned on?

Turning on SCIM doesn't immediately remove or modify existing licensed users. They retain current access and roles, but you'll manage them through your IdP after SCIM is active. If SCIM is later turned off, previously SCIM-managed users remain in Docker but are no longer automatically updated based on your IdP.

### Is user information visible in Docker Hub?

All Docker accounts have public profiles associated with their namespace. If you don't want user information (like full names) to be visible, remove those attributes from your SSO and SCIM mappings, or use different identifiers to replace users' full names.

## Enforcement

### Does Docker SSO support authenticating through the command line?

When SSO is enforced, [passwords are prevented from accessing the Docker CLI](../security/security-announcements.md#deprecation-of-password-logins-on-cli-when-sso-enforced). You must use a personal access token (PAT) for CLI authentication instead.

Each user must create a PAT to access the CLI. To learn how to create a PAT, see [Manage personal access tokens](../security/access-tokens/personal-access-tokens.md). Users who already used a PAT before SSO enforcement can continue using that PAT.

### How does SSO affect automation systems and CI/CD pipelines?

Before enforcing SSO, you must [create personal access tokens](../security/access-tokens/personal-access-tokens.md) to replace passwords in automation systems and CI/CD pipelines.

### Can I turn on SSO without enforcing it immediately?

Yes, you can turn on SSO without enforcement. Users can choose between Docker ID (standard email and password) or domain-verified email address (SSO) at the sign-in screen.

### Why can a user sign in with a username and password when SSO is enforced?

Guest users who aren't part of your registered domain but have been invited to your organization don't sign in through your SSO identity provider. SSO enforcement only applies to users who belong to your verified domain.

### Can I test SSO functionality before going to production?

Yes, you can create a test organization with a 5-seat Business subscription. When testing, turn on SSO but don't enforce it, or all domain email users will be forced to sign in to the test environment.

### What is enforcing SSO versus enforcing sign-in?

These are separate features you can use independently or together:

- Enforcing SSO ensures users sign in using SSO credentials instead of their Docker ID, enabling better credential management.
- Enforcing sign-in to Docker Desktop ensures users always sign in to accounts that are members of your organization, so security settings and subscription benefits are always applied.

For more details, see [Enforce sign-in for Desktop](../enterprise/security/enforce-sign-in/index.md#enforcing-sign-in-versus-enforcing-single-sign-on-sso).

## Domain

### Can I add sub-domains?

Yes, you can add sub-domains to your SSO connection. All email addresses must use domains you've added to the connection. Verify that your DNS provider supports multiple TXT records for the same domain.

### Do I need to keep the DNS TXT record permanently?

You can remove the TXT record after one-time verification to add the domain. However, if your organization changes identity providers and needs to set up SSO again, you'll need to verify the domain again.

### Can I verify the same domain for multiple organizations?

You can't verify the same domain for multiple organizations at the organization level. To verify one domain for multiple organizations, you must have a Docker Business subscription and create a company. Companies allow centralized management of organizations and domain verification at the company level.


---

# Subscription and billing FAQs

*Sección: Faqs*

For more information on Docker subscriptions, see
[Subscription and billing](../subscription-billing/index.md).

## Subscriptions

### Can I transfer my subscription from one user or organization account to another?

Subscriptions are non-transferable between accounts or organizations.

### Can I pause or delay my Docker subscription?

You can't pause or delay a subscription, but you can downgrade your
subscription. If a subscription invoice isn't paid by the due date, there's a
15-day grace period starting from the due date.

### Does Docker offer academic pricing?

For academic pricing, contact the
[Docker Sales Team](https://www.docker.com/company/contact).

### How can I contribute to Docker content?

Docker offers two content contribution programs:

- [Docker-Sponsored Open Source Program (DSOS)](../docker-hub/repos/manage/trusted-content/dsos-program.md)
  for open source projects
- [Docker Verified Publisher (DVP)](../docker-hub/repos/manage/trusted-content/dvp-program.md)
  for commercial publishers

You can also join the
[Developer Preview Program](https://www.docker.com/community/get-involved/developer-preview/)
or sign up for early access programs to participate in research and try new
features.

### How do I upgrade to Docker Pro?

To upgrade to Docker Pro, go to the
<a href="https://www.docker.com/pricing?ref=Docs&refAction=DocsSubscriptionFaqPro" id="dkr_docs_pricing_faq_pro" class="link" rel="noopener">Docker pricing page</a>
and select **Buy now**.

## Payments

### What happens if my subscription payment fails?

If your subscription payment fails, there is a grace period of 15 days,
including the due date. Docker attempts to collect the payment three times using
the following schedule:

- 3 days after the due date
- 5 days after the previous attempt
- 7 days after the previous attempt

Docker also sends an email notification
`Action Required - Credit Card Payment Failed` with an attached unpaid invoice
after each failed payment attempt.

If the invoice remains unpaid after the grace period, the
subscription downgrades to a free subscription and all paid features are
disabled.

### Can I manually retry a failed payment?

Yes. If your payment fails, select **Pay now** to retry the payment through
Stripe.

Before retrying, verify that your default payment method is up to date. For
instructions, see
[Manage a payment method](../subscription-billing/manage/payment-method.md#manage-payment-method).

### Can I use pay by invoice for upgrades or additional seats?

No. Pay by invoice is only available for renewing annual subscriptions, not for
purchasing upgrades or additional seats. You must use card payment or US bank
accounts for these changes.

For a list of supported payment methods, see
[Add or update a payment method](../subscription-billing/manage/payment-method.md).

> [!TIP]
>
> Need to upgrade? <a href="https://www.docker.com/pricing?ref=Docs&refAction=DocsSubscriptionFaq" id="pricing-link" class="link" rel="noopener">Compare Docker Team and Docker Business</a> to choose the plan that best fits your team's needs.

## Taxes

### Does Docker collect sales tax and VAT?

Docker collects sales tax or VAT from the following customers:

- For United States customers, Docker began collecting sales tax on
  July 1, 2024.
- For European customers, Docker began collecting VAT on March 1, 2025.
- For United Kingdom customers, Docker began collecting VAT on May 1, 2025.

To help ensure correct tax assessments, keep your
[billing information](../subscription-billing/manage/details.md) up to date. For details on
adding a VAT number or submitting a US tax exemption certificate, see
[Taxes](../subscription-billing/manage/tax-certificate.md).


---

# Docker Offload

*Sección: Offload*

{{< summary-bar feature_name="Docker Offload" >}}

Docker Offload is a fully managed service that lets you offload building and
running containers to the cloud using the Docker tools you already know. It
enables developers to work efficiently in virtual desktop infrastructure (VDI)
environments or systems that don't support nested virtualization.

In the following topics, learn about Docker Offload, how to set it up, use it
for your workflows, and troubleshoot common issues.

{{< grid >}}


---

# About Docker Offload

*Sección: Offload*

{{< summary-bar feature_name="Docker Offload" >}}

Docker Offload is a fully managed service for building and running containers in
the cloud using the Docker tools you already know, including Docker Desktop, the
Docker CLI, and Docker Compose. It extends your local development workflow into a
scalable, cloud-powered environment, enabling developers to work efficiently even
in virtual desktop infrastructure (VDI) environments or systems that don't support
nested virtualization.

## Key features

Docker Offload includes the following capabilities to support modern container
workflows:

- Ephemeral cloud runners: Automatically provision and tear down cloud
  environments for each container session.
- Secure communication: Use encrypted tunnels between Docker Desktop and cloud
  environments with support for secure secrets and image pulling.
- Port forwarding and bind mounts: Retain a local development experience even
  when running containers in the cloud.
- VDI-friendly: [Use Docker Desktop](../desktop/setup/vm-vdi.md) in virtual
  desktop environments or systems that don't support nested virtualization.

For more information, see the [Docker Offload product
page](https://www.docker.com/products/docker-offload/).

## How Docker Offload works

Docker Offload replaces the need to build or run containers locally by connecting
Docker Desktop to secure, dedicated cloud resources.

### Running containers with Docker Offload

When you use Docker Offload to build or run containers, Docker Desktop creates a secure
SSH tunnel to a Docker daemon running in the cloud. Your containers are started
and managed entirely in that remote environment.

Here's what happens:

1. Docker Desktop connects to the cloud and triggers container creation.
2. Docker Offload builds or pulls the required images and starts containers in the cloud.
3. The connection stays open while the containers run and you remain active.
4. When the containers stop running, the environment shuts down and is cleaned
   up automatically.

This setup avoids the overhead of running containers locally and enables fast,
reliable containers even on low-powered machines, including machines that do not
support nested virtualization. This makes Docker Offload ideal for developers
using environments such as virtual desktops, cloud-hosted development machines,
or older hardware.

Despite running remotely, features like bind mounts and port forwarding continue
to work seamlessly, providing a local-like experience from within Docker Desktop
and the CLI.

### Cloud resources

Docker Offload uses cloud hosts with 4 vCPUs and 8 GiB of memory. If you have
different requirements, <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_offload_about" class="link" rel="noopener">contact Docker</a> to explore options.

### Session management and idle state

Docker Offload uses session management and idle state policies to ensure fair use of cloud resources across all users, see [Fair use](#fair-use).

Each user can run one Docker Offload session at a time. When Docker Desktop is in an **Offload idle** state, it waits for activity on the Docker API and only connects to a cloud environment when needed. Once connected, the session moves to an **Offload running** state and stays connected as long as Docker detects activity. Activity includes any Docker API call, a running container, or an active build.

#### When you'll see a prompt

While Docker Offload is running, Docker Desktop shows prompts in the Dashboard to check if you're still active. Prompts appear in two cases:

1. No activity is detected for more than 3 minutes.
2. The session has been running for a long time.

When a prompt appears, you can:
   - Select **Ask me again later** to confirm you're still active and continue your session.
   - Select **Idle now** to return to an idle state immediately.
   - Do nothing, and the session returns to an idle state automatically.

#### What happens when your session goes idle

After your session returns to an idle state, there is a 5-minute grace period. You can resume the session during this time by running any Docker command.

> [!IMPORTANT]
> If the idle period exceeds 5 minutes without activity, the session is terminated. Docker Offload environments are ephemeral, so the remote environment and any containers, images, or volumes in it are deleted. To keep work between sessions, push images to a registry such as [Docker Hub](/docker-hub/) before your session ends.

#### Long session prompts

Long session prompts appear every 3 hours during a session. After 8 hours of cumulative usage in a day, prompts appear every hour. The 8-hour counter resets at the start of each day.

## Fair use

Docker Offload enforces a fair use policy to prevent resource abuse. Fair use is
defined as up to 8 compute hours per named user per day, totaled across all user
sessions. Usage in excess of this threshold may be subject to session management
at Docker's discretion.

## What's next

Get hands-on with Docker Offload by following the [Docker Offload quickstart](/offload/quickstart/).


---

# Configure Docker Offload

*Sección: Offload*

{{< summary-bar feature_name="Docker Offload" >}}

You can configure Docker Offload settings at different levels depending on your
role. Organization owners can manage settings for all users in their
organization, while individual developers can configure their own Docker Desktop
settings when allowed by their organization.

## Manage settings for your organization

For organization owners, you can manage Docker Offload settings for all users in
your organization. For more details, see [Manage Docker
products](../accounts/organization/manage/manage-products.md). To view usage for Docker
Offload, see [Docker Offload usage](/offload/usage/).

## Configure settings in Docker Desktop

For developers, you can enable or disable Docker Offload in Docker Desktop if
allowed by your organization. To manage this setting:

1. Open the Docker Desktop Dashboard and sign in.
2. Select the settings icon in the Docker Desktop Dashboard header.
3. In **Settings**, select **Docker Offload**.
4. Toggle **Enable Docker Offload**. When enabled, you can start Offload sessions.


---

# Give feedback

*Sección: Offload*

There are several ways you can provide feedback on Docker Offload.

## Quick survey

The fastest way to share your thoughts is to fill out this short
[Docker Offload feedback
survey](https://docker.qualtrics.com/jfe/form/SV_br8Ki4CCdqeIYl0). It only takes
a minute and helps the Docker Team improve your experience.

## In-product feedback

On each Docker Desktop Dashboard view, there is a **Give feedback** link. This
opens a feedback form where you can share ideas directly with the Docker Team.

## Report bugs or problems on GitHub

To report bugs or problems, visit the [Docker Desktop issue tracker](https://github.com/docker/desktop-feedback).


---

# Optimize Docker Offload usage

*Sección: Offload*

Docker Offload builds and runs your containers remotely, not on the machine where you invoke the
commands. This means that files must be transferred from your local system to the
cloud over the network.

Transferring files over the network introduces higher latency and lower
bandwidth compared to local transfers.

Even with optimizations, large projects or slower network connections can lead to longer transfer times. Here are
several ways to optimize your setup for Docker Offload:

- [Use `.dockerignore` files](#dockerignore-files)
- [Choose slim base images](#slim-base-images)
- [Use multi-stage builds](#multi-stage-builds)
- [Fetch remote files during the build](#fetch-remote-files-in-build)
- [Leverage multi-threaded tools](#multi-threaded-tools)

For general Dockerfile tips, see [Building best practices](../build/building/best-practices.md).

## dockerignore files

A [`.dockerignore` file](../build/concepts/context.md#dockerignore-files)
lets you specify which local files should *not* be included in the build
context. Files excluded by these patterns won’t be uploaded to Docker Offload
during a build.

Typical items to ignore:

- `.git` – avoids transferring your version history. (Note: you won’t be able to run `git` commands in the build.)
- Build artifacts or locally generated binaries.
- Dependency folders such as `node_modules`, if those are restored in the build
  process.

As a rule of thumb, your `.dockerignore` should be similar to your `.gitignore`.

## Slim base images

Smaller base images in your `FROM` instructions can reduce final image size and
improve build performance. The [`alpine`](https://hub.docker.com/_/alpine) image
is a good example of a minimal base.

For fully static binaries, you can use [`scratch`](https://hub.docker.com/_/scratch), which is an empty base image.

## Multi-stage builds

[Multi-stage builds](/build/building/multi-stage/) let you separate build-time
and runtime environments in your Dockerfile. This not only reduces the size of
the final image but also allows for parallel stage execution during the build.

Use `COPY --from` to copy files from earlier stages or external images. This
approach helps minimize unnecessary layers and reduce final image size.

## Fetch remote files in build

When possible, download large files from the internet during the build itself
instead of bundling them in your local context. This avoids network transfer
from your client to Docker Offload.

You can do this using:

- The Dockerfile [`ADD` instruction](/reference/dockerfile/#add)
- `RUN` commands like `wget`, `curl`, or `rsync`

### Multi-threaded tools

Some build tools, such as `make`, are single-threaded by default. If the tool
supports it, configure it to run in parallel. For example, use `make --jobs=4`
to run four jobs simultaneously.

Taking advantage of available CPU resources in the cloud can significantly
improve build time.


---

# Docker Offload quickstart

*Sección: Offload*

{{< summary-bar feature_name="Docker Offload" >}}

[Docker Offload](about.md) lets you build and run containers in the cloud
while using your local Docker Desktop tools and workflow. This means faster
builds, access to powerful cloud resources, and a seamless development
experience.

This quickstart covers the steps developers need to get started with Docker Offload.

> [!NOTE]
>
> If you're an organization owner, to get started you must <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_offload_quickstart" class="link" rel="noopener">contact sales</a> and subscribe your
> organization to use Docker Offload. After subscribing, see [Manage Docker
> products](../accounts/organization/manage/manage-products.md) to learn how to manage
> access for the developers in your organization.


## Prerequisites

- You must have [Docker Desktop](/desktop/) installed. Docker recommends using
  the latest version of Docker Desktop to access the newest features and
  improvements in Docker Offload.
- You must have a Docker Business subscription and a Docker Offload subscription.

## Step 1: Verify access to Docker Offload

To access Docker Offload, you must be part of an organization that has
subscribed to Docker Offload. As a developer, you can verify this by checking if
the Docker Offload toggle appears in the Docker Desktop Dashboard header.

1. Start Docker Desktop and sign in.
2. In the Docker Desktop Dashboard header, look for the Docker Offload toggle.

![Offload toggle](./images/offload-toggle.png)

If you see the Docker Offload toggle, you have access to Docker Offload and can
proceed to the next step. If you don't see the Docker Offload toggle, check if
Docker Offload is disabled in your [Docker Desktop
settings](configuration.md), and then contact your administrator to verify
that your organization has subscribed to Docker Offload and that they have
enabled access for your organization.

## Step 2: Start Docker Offload

You can start Docker Offload from the CLI or in the header of the Docker Desktop
Dashboard. The following steps describe how to start Docker Offload using the
CLI.

1. Start Docker Desktop and sign in.
2. Open a terminal and run the following command to start Docker Offload:

   ```console
   $ docker offload start
   ```

   > [!TIP]
   >
   > To learn more about the Docker Offload CLI commands, see the [Docker Offload CLI
   > reference](/reference/cli/docker/offload/).

3. If you are a member of multiple organizations that have access to Docker
   Offload, you have the option to select a profile. Your usage will be
   associated with the organization of the selected profile.


When Docker Offload is started, you'll see a cloud icon ({{< inline-image
src="./images/cloud-mode.png" alt="Offload mode icon" >}}) in the Docker Desktop
Dashboard header, and the Docker Desktop Dashboard appears purple. You can run
`docker offload status` in a terminal to check the status of Docker Offload.

## Step 3: Run a container with Docker Offload

After starting Docker Offload, Docker Desktop connects to a secure cloud
environment that mirrors your local experience. When you run builds or
containers, they execute remotely, but behave just like local ones.

To verify that Docker Offload is working, run a container:

```console
$ docker run --rm hello-world
```

If Docker Offload is working, you'll see `Hello from Docker!` in the terminal output.

## Step 4: Monitor your Offload session

When Docker Offload is started and you have started session (for example, you've
ran a container), then you can see current session duration estimate in the
Docker Desktop Dashboard footer next to the hourglass icon ({{< inline-image
src="./images/hourglass-icon.png" alt="Offload session duration" >}}).

Also, when Docker Offload is started, you can view detailed session information
by selecting **Docker Offload** > **Insights** in the left navigation of the
Docker Desktop Dashboard.

## Step 5: Stop Docker Offload

Docker Offload automatically
[idles](about.md#session-management-and-idle-state) if you do not respond to
periodic prompts that appear in the Docker Desktop Dashboard. You can stop your
Docker Offload session at any time. To stop Docker Offload:

```console
$ docker offload stop
```

When you stop Docker Offload, the cloud environment is terminated and all
running containers and images are removed. When Docker Offload has been idle for
5 minutes, the environment is also terminated and all running containers and
images are removed.

To start Docker Offload again, run the `docker offload start` command.


---

# Troubleshoot Docker Offload

*Sección: Offload*

{{< summary-bar feature_name="Docker Offload" >}}

Docker Offload requires:

- Authentication
- An active internet connection
- No restrictive proxy or firewall blocking traffic to Docker Cloud
- Access to Docker Offload
- Docker Desktop 4.68 or later

Docker Desktop uses Offload to run both builds and containers in the cloud.
If builds or containers are failing to run, falling back to local, or reporting
session errors, use the following steps to help resolve the issue.

1. Ensure Docker Offload is enabled in Docker Desktop:

   1. Open Docker Desktop and sign in.
   2. Go to **Settings** > **Docker Offload**.
   3. Ensure that **Enable Docker Offload** is toggled on.

2. Use the following command to check if the connection is active:

   ```console
   $ docker offload status
   ```

3. To get more information, run the following command:

   ```console
   $ docker offload diagnose
   ```

4. If you're not connected, start a new session:

   ```console
   $ docker offload start
   ```

5. Verify authentication with `docker login`.

6. If needed, you can sign out and then sign in again:

   ```console
   $ docker logout
   $ docker login
   ```

7. Verify your usage. For more information, see [Docker Offload usage](/offload/usage/).


---

# Docker Offload usage

*Sección: Offload*

{{< summary-bar feature_name="Docker Offload" >}}


The **Offload activity** page in Docker Home provides visibility into user
activity and session metrics for Docker Offload.

To monitor your usage:

1. Sign in to [Docker Home](https://app.docker.com/).
2. If you have access to multiple organizations, select the organization
   associated with your Docker Offload subscription.
3. Select **Offload** > **Offload activity**.

### Overview metrics

Key metrics at the top of the page summarize your Docker Offload usage:

- **Total duration**: The total time spent in Offload sessions
- **Average duration**: The average time per Offload session
- **Total sessions**: The total number of Offload sessions
- **Unique images used**: The number of distinct container images used across
  sessions
- **Unique users**: The number of different users in Docker Offload sessions

### Filter and export your data

You can filter the Offload activity data by:

- **Period**: Select a preset time period or choose a custom date range
- **Users**: Organization owners and members with analytics permissions can
  filter by specific users
- **Additional Filters**: Filter by active sessions and session duration.

Export your session data by selecting the **Download CSV** button. The exported
file includes:

- Session ID
- Username
- Image
- Started time
- Ended time
- Duration (in seconds)
- Status
- Container count

The CSV export includes data for your selected date range and user filters,
letting you download exactly what you're viewing.

### Activity cards

The following cards provide insights into your Docker Offload usage:

- **Offload usage**: Shows your usage trends over time and cloud resource
  consumption patterns.
- **Popular images**: Shows the top 4 most frequently used container images in
  your Docker Offload sessions. Select the card to see more images.
- **Top Offload users**: Shows the top 4 users by session count and duration. Select
  the card to see more users.

### Offload sessions

A detailed list of Offload sessions appears following the activity cards. The list:

- Starts with any currently active sessions
- Shows session details including start time, duration, images used, and user
  information
- Can be filtered using the date and user filters described previously
- Displays **Offload sessions** if you have organization-wide analytics
  permissions, or **My Offload sessions** if viewing only your own data

Select any session to view more details in a side panel.


---

# Reference documentation

*Sección: Reference*

This section includes the reference documentation for the Docker platform's
various APIs, CLIs, drivers and specifications, and file formats.

## File formats

{{< grid items="grid_files" >}}

## Command-line interfaces (CLIs)

{{< grid items="grid_clis" >}}

## Application programming interfaces (APIs)

{{< grid items="grid_apis" >}}


---

# API reference

*Sección: Reference*




---

# Docker AI Governance API

*Sección: Reference*




---

# DVP Data API

*Sección: Reference*




---

# Docker Verified Publisher API changelog

*Sección: Reference*

Here you can learn about the latest changes, new features, bug fixes, and known
issues for Docker Verified Publisher API.

---

## 2025-06-27

### New

- Create changelog


---

# Deprecated Docker Verified Publisher API endpoints

*Sección: Reference*

This page provides an overview of endpoints that are deprecated in Docker Verified Publisher API.

## Endpoint deprecation policy

As changes are made to Docker there may be times when existing endpoints need to be removed or replaced with newer endpoints. Before an existing endpoint is removed it is labeled as "deprecated" within the documentation. After some time it may be removed.

## Deprecated endpoints

The following table provides an overview of the current status of deprecated endpoints:

**Deprecated**: the endpoint is marked "deprecated" and should no longer be used.

The endpoint may be removed, disabled, or change behavior in a future release.

**Removed**: the endpoint was removed, disabled, or hidden.

---

| Status | Feature                                                       | Date       |
|--------|---------------------------------------------------------------|------------|
|        | [Create deprecation log table](#create-deprecation-log-table) | 2025-06-27 |

---

### Create deprecation log table

Reformat page

---


---

# Docker Verified Publisher API reference

*Sección: Reference*




---

# Docker Engine API

*Sección: Reference*

Docker provides an API for interacting with the Docker daemon (called the Docker
Engine API), as well as SDKs for Go and Python. The SDKs allow you to efficiently build and
scale Docker apps and solutions. If Go or Python don't work
for you, you can use the Docker Engine API directly.

For information about Docker Engine SDKs, see [Develop with Docker Engine SDKs](sdk/index.md).

The Docker Engine API is a RESTful API accessed by an HTTP client such as `wget` or
`curl`, or the HTTP library which is part of most modern programming languages.

## View the API reference

You can
[view the reference for the latest version of the API](/reference/api/engine/version/v{{% param latest_engine_api_version %}}.md)
or [choose a specific version](/reference/api/engine/#api-version-matrix).

## Versioned API and SDK

The version of the Docker Engine API you should use depends upon the version of
your Docker daemon and Docker client.

A given version of the Docker Engine SDK supports a specific version of the
Docker Engine API, as well as all earlier versions. If breaking changes occur,
they are documented prominently.

> [!NOTE]
>
> The Docker daemon and client don't necessarily need to be the same version
> at all times. However, keep the following in mind.
>
> - If the daemon is newer than the client, the client doesn't know about new
>   features or deprecated API endpoints in the daemon.
>
> - If the client is newer than the daemon, the client can request API
>   endpoints that the daemon doesn't know about.

A new version of the API is released when new features are added. The Docker API
is backward-compatible, so you don't need to update code that uses the API
unless you need to take advantage of new features.

To see the highest and lowest version of the API your Docker daemon and client
support, use `docker version`:

```console
$ docker version
Client: Docker Engine - Community
 Version:           {{% param "docker_ce_version" %}}
 API version:       {{% param "latest_engine_api_version" %}}
 ...

Server: Docker Engine - Community
 Engine:
  Version:          {{% param "docker_ce_version" %}}
  API version:      {{% param "latest_engine_api_version" %}} (minimum version 1.40)
  ...
```

You can specify the API version to use in any of the following ways:

- When using the SDK, use the latest version. At a minimum, use the version
  that incorporates the API version with the features you need.
- When using `curl` directly, specify the version as the first part of the URL.
  For instance, if the endpoint is `/containers/` you can use
  `/v{{% param "latest_engine_api_version" %}}/containers/`.
- To force the Docker CLI or the Docker Engine SDKs to use an older version
  of the API than the version reported by `docker version`, set the
  environment variable `DOCKER_API_VERSION` to the correct version. This works
  on Linux, Windows, and macOS clients.

  {{% apiVersionPrevious.inline %}}
  {{- $version := site.Params.latest_engine_api_version }}
  {{- $parts := strings.Split $version "." }}
  {{- $major := cast.ToInt (index $parts 0) }}
  {{- $minor := cast.ToInt (index $parts 1) }}
  ```console
  $ DOCKER_API_VERSION={{ $major }}.{{ math.Sub $minor 1 }}
  ```
  {{% /apiVersionPrevious.inline %}}

  While the environment variable is set, that version of the API is used, even
  if the Docker daemon supports a newer version. This environment variable
  disables API version negotiation, so you should only use it if you must
  use a specific version of the API, or for debugging purposes.

- The Docker Go SDK allows you to enable API version negotiation, automatically
  selects an API version that's supported by both the client and the Docker Engine
  that's in use.
- For the SDKs, you can also specify the API version programmatically as a
  parameter to the `client` object. See the
  [Go constructor](https://pkg.go.dev/github.com/docker/docker/client#NewClientWithOpts)
  or the
  [Python SDK documentation for `client`](https://docker-py.readthedocs.io/en/stable/client.html).

### Minimum API version

The Docker Engine API server and client support API-version negotiation. If
a client connects to an older version of the Docker Engine, it negotiates
the highest version of the API supported by both the client and daemon,
downgrading to an older version of the API if necessary.

When downgrading to an older API version, features introduced in later API
versions are disabled, and API requests and responses are adjusted for the
API version negotiated.

API version negotiation allows tools that have not been upgraded yet to the
latest API version specification to communicate with newer Docker Engines
(and vice versa), but compatibility is "best effort"; while Docker strives
to provide full compatibility, some functionality may not be available.

### API version matrix

| Docker version | Maximum API version                          | Minimum API version                          | Change log                                                         |
|:---------------|:---------------------------------------------|:---------------------------------------------|:-------------------------------------------------------------------|
| 29.8           | [1.55](/reference/api/engine/version/v1.56/) | [1.40](/reference/api/engine/version/v1.40/) | [changes](/reference/api/engine/version-history/#v156-api-changes) |
| 29.7           | [1.55](/reference/api/engine/version/v1.55/) | [1.40](/reference/api/engine/version/v1.40/) | [changes](/reference/api/engine/version-history/#v155-api-changes) |
| 29.6           | [1.55](/reference/api/engine/version/v1.55/) | [1.40](/reference/api/engine/version/v1.40/) | [changes](/reference/api/engine/version-history/#v155-api-changes) |
| 29.5           | [1.54](/reference/api/engine/version/v1.54/) | [1.40](/reference/api/engine/version/v1.40/) | [changes](/reference/api/engine/version-history/#v154-api-changes) |
| 29.4           | [1.54](/reference/api/engine/version/v1.54/) | [1.40](/reference/api/engine/version/v1.40/) | [changes](/reference/api/engine/version-history/#v154-api-changes) |
| 29.3           | [1.54](/reference/api/engine/version/v1.54/) | [1.40](/reference/api/engine/version/v1.40/) | [changes](/reference/api/engine/version-history/#v154-api-changes) |
| 29.2           | [1.53](/reference/api/engine/version/v1.53/) | [1.44](/reference/api/engine/version/v1.44/) | [changes](/reference/api/engine/version-history/#v153-api-changes) |
| 29.1           | [1.52](/reference/api/engine/version/v1.52/) | [1.44](/reference/api/engine/version/v1.44/) | [changes](/reference/api/engine/version-history/#v152-api-changes) |
| 29.0           | [1.52](/reference/api/engine/version/v1.52/) | [1.44](/reference/api/engine/version/v1.44/) | [changes](/reference/api/engine/version-history/#v152-api-changes) |
| 28.5           | [1.51](/reference/api/engine/version/v1.51/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v151-api-changes) |
| 28.4           | [1.51](/reference/api/engine/version/v1.51/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v151-api-changes) |
| 28.3           | [1.51](/reference/api/engine/version/v1.51/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v151-api-changes) |
| 28.2           | [1.50](/reference/api/engine/version/v1.50/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v150-api-changes) |
| 28.1           | [1.49](/reference/api/engine/version/v1.49/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v149-api-changes) |
| 28.0           | [1.48](/reference/api/engine/version/v1.48/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v148-api-changes) |
| 27.5           | [1.47](/reference/api/engine/version/v1.47/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v147-api-changes) |
| 27.4           | [1.47](/reference/api/engine/version/v1.47/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v147-api-changes) |
| 27.3           | [1.47](/reference/api/engine/version/v1.47/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v147-api-changes) |
| 27.2           | [1.47](/reference/api/engine/version/v1.47/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v147-api-changes) |
| 27.1           | [1.46](/reference/api/engine/version/v1.46/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v146-api-changes) |
| 27.0           | [1.46](/reference/api/engine/version/v1.46/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v146-api-changes) |
| 26.1           | [1.45](/reference/api/engine/version/v1.45/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v145-api-changes) |
| 26.0           | [1.45](/reference/api/engine/version/v1.45/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v145-api-changes) |
| 25.0           | [1.44](/reference/api/engine/version/v1.44/) | 1.24                                         | [changes](/reference/api/engine/version-history/#v144-api-changes) |
| 24.0           | [1.43](/reference/api/engine/version/v1.43/) | 1.12                                         | [changes](/reference/api/engine/version-history/#v143-api-changes) |
| 23.0           | [1.42](/reference/api/engine/version/v1.42/) | 1.12                                         | [changes](/reference/api/engine/version-history/#v142-api-changes) |
| 20.10          | [1.41](/reference/api/engine/version/v1.41/) | 1.12                                         | [changes](/reference/api/engine/version-history/#v141-api-changes) |
| 19.03          | [1.40](/reference/api/engine/version/v1.40/) | 1.12                                         | [changes](/reference/api/engine/version-history/#v140-api-changes) |

### Deprecated API versions

API versions before v1.40 are deprecated and no longer supported by current
versions of the Docker Engine and CLI. You can find archived documentation
for deprecated versions of the API [in the code repository on GitHub](https://github.com/moby/moby/tree/docker-v{{% param "docker_ce_version" %}}/api/docs):

| Docker version | Maximum API version | Minimum API version | Change log                                                         |
|:---------------|:--------------------|:--------------------|:-------------------------------------------------------------------|
| 18.09          | 1.39                | 1.12                | [changes](/reference/api/engine/version-history/#v139-api-changes) |
| 18.06          | 1.38                | 1.12                | [changes](/reference/api/engine/version-history/#v138-api-changes) |
| 18.05          | 1.37                | 1.12                | [changes](/reference/api/engine/version-history/#v137-api-changes) |
| 18.04          | 1.37                | 1.12                | [changes](/reference/api/engine/version-history/#v137-api-changes) |
| 18.03          | 1.37                | 1.12                | [changes](/reference/api/engine/version-history/#v137-api-changes) |
| 18.02          | 1.36                | 1.12                | [changes](/reference/api/engine/version-history/#v136-api-changes) |
| 17.12          | 1.35                | 1.12                | [changes](/reference/api/engine/version-history/#v135-api-changes) |
| 17.11          | 1.34                | 1.12                | [changes](/reference/api/engine/version-history/#v134-api-changes) |
| 17.10          | 1.33                | 1.12                | [changes](/reference/api/engine/version-history/#v133-api-changes) |
| 17.09          | 1.32                | 1.12                | [changes](/reference/api/engine/version-history/#v132-api-changes) |
| 17.07          | 1.31                | 1.12                | [changes](/reference/api/engine/version-history/#v131-api-changes) |
| 17.06          | 1.30                | 1.12                | [changes](/reference/api/engine/version-history/#v130-api-changes) |
| 17.05          | 1.29                | 1.12                | [changes](/reference/api/engine/version-history/#v129-api-changes) |
| 17.04          | 1.28                | 1.12                | [changes](/reference/api/engine/version-history/#v128-api-changes) |
| 17.03.1        | 1.27                | 1.12                | [changes](/reference/api/engine/version-history/#v127-api-changes) |
| 17.03          | 1.26                | 1.12                | [changes](/reference/api/engine/version-history/#v126-api-changes) |
| 1.13.1         | 1.26                | 1.12                | [changes](/reference/api/engine/version-history/#v126-api-changes) |
| 1.13           | 1.25                | 1.12                | [changes](/reference/api/engine/version-history/#v125-api-changes) |
| 1.12           | 1.24                | 1.12                | [changes](/reference/api/engine/version-history/#v124-api-changes) |
| 1.11           | 1.23                | 1.12                | [changes](/reference/api/engine/version-history/#v123-api-changes) |
| 1.10           | 1.22                | 1.12                | [changes](/reference/api/engine/version-history/#v122-api-changes) |
| 1.9            | 1.21                | 1.12                | [changes](/reference/api/engine/version-history/#v121-api-changes) |
| 1.8            | 1.20                | 1.12                | [changes](/reference/api/engine/version-history/#v120-api-changes) |
| 1.7            | 1.19                | 1.0                 | [changes](/reference/api/engine/version-history/#v119-api-changes) |
| 1.6            | 1.18                | 1.0                 | [changes](/reference/api/engine/version-history/#v118-api-changes) |
| 1.5            | 1.17                | 1.0                 | [changes](/reference/api/engine/version-history/#v117-api-changes) |
| 1.4            | 1.16                | 1.0                 | [changes](/reference/api/engine/version-history/#v116-api-changes) |
| 1.3            | 1.15                | 1.0                 | [changes](/reference/api/engine/version-history/#v115-api-changes) |
| 1.2            | 1.14                | 1.0                 | [changes](/reference/api/engine/version-history/#v114-api-changes) |
| 1.1            | 1.13                | 1.0                 | [changes](/reference/api/engine/version-history/#v113-api-changes) |
| 1.0            | 1.12                | 1.0                 | [changes](/reference/api/engine/version-history/#v112-api-changes) |
| 0.12           | 1.12                | 1.0                 | [changes](/reference/api/engine/version-history/#v112-api-changes) |
| 0.11           | 1.11                | 1.0                 | [changes](/reference/api/engine/version-history/#v111-api-changes) |
| 0.10           | 1.10                | 1.0                 | [changes](/reference/api/engine/version-history/#v110-api-changes) |
| 0.9            | 1.10                | 1.0                 | [changes](/reference/api/engine/version-history/#v110-api-changes) |
| 0.8            | 1.9                 | 1.0                 | [changes](/reference/api/engine/version-history/#v19-api-changes)  |
| 0.7.1          | 1.8                 | 1.0                 | [changes](/reference/api/engine/version-history/#v18-api-changes)  |
| 0.7            | 1.7                 | 1.0                 | [changes](/reference/api/engine/version-history/#v17-api-changes)  |
| 0.6.4          | 1.6                 | 1.0                 | [changes](/reference/api/engine/version-history/#v16-api-changes)  |
| 0.6.2          | 1.5                 | 1.0                 | [changes](/reference/api/engine/version-history/#v15-api-changes)  |
| 0.6            | 1.4                 | 1.0                 | [changes](/reference/api/engine/version-history/#v14-api-changes)  |
| 0.5            | 1.3                 | 1.0                 | [changes](/reference/api/engine/version-history/#v13-api-changes)  |
| 0.4.1          | 1.2                 | 1.0                 | [changes](/reference/api/engine/version-history/#v12-api-changes)  |
| 0.3.4          | 1.1                 | 1.0                 | [changes](/reference/api/engine/version-history/#v11-api-changes)  |
| 0.3.3          | 1.0                 | 1.0                 | [changes](/reference/api/engine/version-history/#v10-api-changes)  |
| 0.3.2          | -                   | -                   |                                                                    |
| 0.2            | -                   | -                   |                                                                    |
| 0.1            | -                   | -                   |                                                                    |


---

# Latest

*Sección: Reference*




---

# Develop with Docker Engine SDKs

*Sección: Reference*

Docker provides an API for interacting with the Docker daemon (called the Docker
Engine API), as well as SDKs for Go and Python. The SDKs allow you to efficiently build and
scale Docker apps and solutions. If Go or Python don't work
for you, you can use the Docker Engine API directly.

The Docker Engine API is a RESTful API accessed by an HTTP client such as `wget` or
`curl`, or the HTTP library which is part of most modern programming languages.

## Install the SDKs

Use the following commands to install the Go or Python SDK. Both SDKs can be
installed and coexist together.

### Go SDK

```console
$ go get github.com/moby/moby/client
```

The client requires a recent version of Go. Run `go version` and ensure that you're running a currently supported version of Go.

For more information, see [Go client reference](https://pkg.go.dev/github.com/moby/moby/client).

### Python SDK

- Recommended: Run `pip install docker`.

- If you can't use `pip`:
  1.  [Download the package directly](https://pypi.python.org/pypi/docker/).
  2.  Extract it and change to the extracted directory.
  3.  Run `python setup.py install`.

For more information, see [Docker Engine Python SDK reference](https://docker-py.readthedocs.io/).

> [!NOTE]
> Docker Desktop for Linux users
>
> Docker Desktop for Linux uses a per-user socket instead of the system-wide `/var/run/docker.sock`. To use Docker SDKs with Docker Desktop for Linux, set the `DOCKER_HOST` environment variable:
>
> ```bash
> export DOCKER_HOST=unix://$HOME/.docker/desktop/docker.sock
> ```
>
> For more details, see [the Linux FAQs](../../../../desktop/troubleshoot-and-support/faqs/linuxfaqs.md#how-do-i-use-docker-sdks-with-docker-desktop-for-linux).

## View the API reference

You can
[view the reference for the latest version of the API](/reference/api/engine/latest/)
or [choose a specific version](/reference/api/engine/#api-version-matrix).

## Versioned API and SDK

The version of the Docker Engine API you should use depends on the version of
your Docker daemon and Docker client. See the [versioned API and SDK](/reference/api/engine/#versioned-api-and-sdk)
section in the API documentation for details.

## SDK and API quickstart

Use the following guidelines to choose the SDK or API version to use in your
code:

- If you're starting a new project, use the [latest version](/reference/api/engine/latest/),
  but use API version negotiation or specify the version you are using. This
  helps prevent surprises.
- If you need a new feature, update your code to use at least the minimum version
  that supports the feature, and prefer the latest version you can use.
- Otherwise, continue to use the version that your code is already using.

As an example, the `docker run` command can be implemented using the
Docker API directly, or using the Python or Go SDK.

{{< tabs >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"io"
	"os"

	"github.com/moby/moby/api/pkg/stdcopy"
	"github.com/moby/moby/api/types/container"
	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv)
	if err != nil {
		panic(err)
	}
	defer apiClient.Close()

	reader, err := apiClient.ImagePull(ctx, "docker.io/library/alpine", client.ImagePullOptions{})
	if err != nil {
		panic(err)
	}
	io.Copy(os.Stdout, reader)

	resp, err := apiClient.ContainerCreate(ctx, client.ContainerCreateOptions{
		Image: "alpine",
		Config: &container.Config{
			Cmd: []string{"echo", "hello world"},
		},
	})
	if err != nil {
		panic(err)
	}

	if _, err := apiClient.ContainerStart(ctx, resp.ID, client.ContainerStartOptions{}); err != nil {
		panic(err)
	}

	wait := apiClient.ContainerWait(ctx, resp.ID, client.ContainerWaitOptions{})
	select {
	case err := <-wait.Error:
		if err != nil {
			panic(err)
		}
	case <-wait.Result:
	}

	out, err := apiClient.ContainerLogs(ctx, resp.ID, client.ContainerLogsOptions{ShowStdout: true})
	if err != nil {
		panic(err)
	}

	stdcopy.StdCopy(os.Stdout, os.Stderr, out)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
print(client.containers.run("alpine", ["echo", "hello", "world"]))
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" \
  -d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}' \
  -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/create
{"Id":"1c6594faf5","Warnings":null}

$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/start

$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/wait
{"StatusCode":0}

$ curl --unix-socket /var/run/docker.sock "http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/logs?stdout=1"
hello world
```

When using cURL to connect over a Unix socket, the hostname is not important. The previous
examples use `localhost`, but any hostname would work.

> [!IMPORTANT]
>
> The previous examples assume you're using cURL 7.50.0 or above. Older versions of
> cURL used a [non-standard URL notation](https://github.com/moby/moby/issues/17960)
> when using a socket connection.
>
> If you're' using an older version of cURL, use `http:/<API version>/` instead,
> for example: `http:/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/start`.

{{< /tab >}}
{{< /tabs >}}

For more examples, take a look at the [SDK examples](examples.md).

## Unofficial libraries

There are a number of community supported libraries available for other
languages. They haven't been tested by Docker, so if you run into any issues,
file them with the library maintainers.

| Language | Library                                                                     |
| :------- | :-------------------------------------------------------------------------- |
| C        | [libdocker](https://github.com/danielsuo/libdocker)                         |
| C#       | [Docker.DotNet](https://github.com/testcontainers/Docker.DotNet)            |
| C++      | [lasote/docker_client](https://github.com/lasote/docker_client)             |
| Clojure  | [clj-docker-client](https://github.com/into-docker/clj-docker-client)       |
| Clojure  | [contajners](https://github.com/lispyclouds/contajners)                     |
| Dart     | [bwu_docker](https://github.com/bwu-dart/bwu_docker)                        |
| Erlang   | [erldocker](https://github.com/proger/erldocker)                            |
| Gradle   | [gradle-docker-plugin](https://github.com/gesellix/gradle-docker-plugin)    |
| Groovy   | [docker-client](https://github.com/gesellix/docker-client)                  |
| Haskell  | [docker-hs](https://github.com/denibertovic/docker-hs)                      |
| Java     | [docker-client](https://github.com/spotify/docker-client)                   |
| Java     | [docker-java](https://github.com/docker-java/docker-java)                   |
| Java     | [docker-java-api](https://github.com/amihaiemil/docker-java-api)            |
| Java     | [jocker](https://github.com/ndeloof/jocker)                                 |
| NodeJS   | [dockerode](https://github.com/apocas/dockerode)                            |
| NodeJS   | [harbor-master](https://github.com/arhea/harbor-master)                     |
| NodeJS   | [the-moby-effect](https://github.com/leonitousconforti/the-moby-effect)     |
| Perl     | [Eixo::Docker](https://github.com/alambike/eixo-docker)                     |
| PHP      | [Docker-PHP](https://github.com/docker-php/docker-php)                      |
| Ruby     | [docker-api](https://github.com/swipely/docker-api)                         |
| Rust     | [bollard](https://github.com/fussybeaver/bollard)                           |
| Rust     | [docker-rust](https://github.com/abh1nav/docker-rust)                       |
| Rust     | [shiplift](https://github.com/softprops/shiplift)                           |
| Scala    | [tugboat](https://github.com/softprops/tugboat)                             |
| Scala    | [reactive-docker](https://github.com/almoehi/reactive-docker)               |
| Swift    | [docker-client-swift](https://github.com/valeriomazzeo/docker-client-swift) |


---

# Examples using the Docker Engine SDKs and Docker API

*Sección: Reference*

After you
[install Docker](/get-started/get-docker.md), you can
[install the Go or Python SDK](../../ai-governance/index.md#install-the-sdks) and
also try out the Docker Engine API.

Each of these examples show how to perform a given Docker operation using the Go
and Python SDKs and the HTTP API using `curl`.

## Run a container

This first example shows how to run a container using the Docker API. On the
command line, you would use the `docker run` command, but this is just as easy
to do from your own apps too.

This is the equivalent of typing `docker run alpine echo hello world` at the
command prompt:

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"io"
	"log"
	"os"

	"github.com/moby/moby/api/pkg/stdcopy"
	"github.com/moby/moby/api/types/container"
	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	reader, err := apiClient.ImagePull(ctx, "docker.io/library/alpine", client.ImagePullOptions{})
	if err != nil {
		log.Fatal(err)
	}

	defer reader.Close()
	// cli.ImagePull is asynchronous.
	// The reader needs to be read completely for the pull operation to complete.
	// If stdout is not required, consider using io.Discard instead of os.Stdout.
	io.Copy(os.Stdout, reader)

	resp, err := apiClient.ContainerCreate(ctx, client.ContainerCreateOptions{
		Config: &container.Config{
			Cmd: []string{"echo", "hello world"},
			Tty: false,
		},
		Image: "alpine",
	})
	if err != nil {
		log.Fatal(err)
	}

	if _, err := apiClient.ContainerStart(ctx, resp.ID, client.ContainerStartOptions{}); err != nil {
		log.Fatal(err)
	}

	wait := apiClient.ContainerWait(ctx, resp.ID, client.ContainerWaitOptions{})
	select {
	case err := <-wait.Error:
		if err != nil {
			log.Fatal(err)
		}
	case <-wait.Result:
	}

	out, err := apiClient.ContainerLogs(ctx, resp.ID, client.ContainerLogsOptions{ShowStdout: true})
	if err != nil {
		log.Fatal(err)
	}

	stdcopy.StdCopy(os.Stdout, os.Stderr, out)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
print(client.containers.run("alpine", ["echo", "hello", "world"]))
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" \
  -d '{"Image": "alpine", "Cmd": ["echo", "hello world"]}' \
  -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/create
{"Id":"1c6594faf5","Warnings":null}

$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/start

$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/wait
{"StatusCode":0}

$ curl --unix-socket /var/run/docker.sock "http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/logs?stdout=1"
hello world
```

When using cURL to connect over a Unix socket, the hostname isn't important. The
previous examples use `localhost`, but any hostname would work.

> [!IMPORTANT]
>
> The previous examples assume you're using cURL 7.50.0 or above. Older versions of
> cURL used a [non-standard URL notation](https://github.com/moby/moby/issues/17960)
> when using a socket connection.
>
> If you're' using an older version of cURL, use `http:/<API version>/` instead,
> for example: `http:/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/start`.

{{< /tab >}}
{{< /tabs >}}

## Run a container in the background

You can also run containers in the background, the equivalent of typing
`docker run -d bfirsh/reticulate-splines`:

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	imageName := "bfirsh/reticulate-splines"

	out, err := apiClient.ImagePull(ctx, imageName, client.ImagePullOptions{})
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	io.Copy(os.Stdout, out)

	resp, err := apiClient.ContainerCreate(ctx, client.ContainerCreateOptions{
		Image: imageName,
	})
	if err != nil {
		log.Fatal(err)
	}

	if _, err := apiClient.ContainerStart(ctx, resp.ID, client.ContainerStartOptions{}); err != nil {
		log.Fatal(err)
	}

	fmt.Println(resp.ID)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
container = client.containers.run("bfirsh/reticulate-splines", detach=True)
print(container.id)
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" \
  -d '{"Image": "bfirsh/reticulate-splines"}' \
  -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/create
{"Id":"1c6594faf5","Warnings":null}

$ curl --unix-socket /var/run/docker.sock -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/1c6594faf5/start
```

{{< /tab >}}
{{< /tabs >}}

## List and manage containers

You can use the API to list containers that are running, just like using
`docker ps`:

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{})
	if err != nil {
		log.Fatal(err)
	}

	for _, container := range containers.Items {
		fmt.Println(container.ID)
	}
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
for container in client.containers.list():
  print(container.id)
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock http://localhost/v{{% param "latest_engine_api_version" %}}/containers/json
[{
  "Id":"ae63e8b89a26f01f6b4b2c9a7817c31a1b6196acf560f66586fbc8809ffcd772",
  "Names":["/tender_wing"],
  "Image":"bfirsh/reticulate-splines",
  ...
}]
```

{{< /tab >}}
{{< /tabs >}}

## Stop all running containers

Now that you know what containers exist, you can perform operations on them.
This example stops all running containers.

> [!NOTE]
>
> Don't run this on a production server. Also, if you're' using swarm
> services, the containers stop, but Docker creates new ones to keep
> the service running in its configured state.

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	containers, err := apiClient.ContainerList(ctx, client.ContainerListOptions{})
	if err != nil {
		log.Fatal(err)
	}

	for _, container := range containers.Items {
		fmt.Print("Stopping container ", container.ID[:10], "... ")
		noWaitTimeout := 0 // to not wait for the container to exit gracefully
		if _, err := apiClient.ContainerStop(ctx, container.ID, client.ContainerStopOptions{Timeout: &noWaitTimeout}); err != nil {
			log.Fatal(err)
		}
		fmt.Println("Success")
	}
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
for container in client.containers.list():
  container.stop()
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock http://localhost/v{{% param "latest_engine_api_version" %}}/containers/json
[{
  "Id":"ae63e8b89a26f01f6b4b2c9a7817c31a1b6196acf560f66586fbc8809ffcd772",
  "Names":["/tender_wing"],
  "Image":"bfirsh/reticulate-splines",
  ...
}]

$ curl --unix-socket /var/run/docker.sock \
  -X POST http://localhost/v{{% param "latest_engine_api_version" %}}/containers/ae63e8b89a26/stop
```

{{< /tab >}}
{{< /tabs >}}

## Print the logs of a specific container

You can also perform actions on individual containers. This example prints the
logs of a container given its ID. You need to modify the code before running it
to change the hard-coded ID of the container to print the logs for.

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"io"
	"log"
	"os"

	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	options := client.ContainerLogsOptions{ShowStdout: true}
	// Replace this ID with a container that really exists
	out, err := apiClient.ContainerLogs(ctx, "f1064a8a4c82", options)
	if err != nil {
		log.Fatal(err)
	}

	io.Copy(os.Stdout, out)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
container = client.containers.get('f1064a8a4c82')
print(container.logs())
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock "http://localhost/v{{% param "latest_engine_api_version" %}}/containers/ca5f55cdb/logs?stdout=1"
Reticulating spline 1...
Reticulating spline 2...
Reticulating spline 3...
Reticulating spline 4...
Reticulating spline 5...
```

{{< /tab >}}
{{< /tabs >}}

## List all images

List the images on your Engine, similar to `docker image ls`:

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	images, err := apiClient.ImageList(ctx, client.ImageListOptions{})
	if err != nil {
		log.Fatal(err)
	}

	for _, image := range images.Items {
		fmt.Println(image.ID)
	}
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
for image in client.images.list():
  print(image.id)
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock http://localhost/v{{% param "latest_engine_api_version" %}}/images/json
[{
  "Id":"sha256:31d9a31e1dd803470c5a151b8919ef1988ac3efd44281ac59d43ad623f275dcd",
  "ParentId":"sha256:ee4603260daafe1a8c2f3b78fd760922918ab2441cbb2853ed5c439e59c52f96",
  ...
}]
```

{{< /tab >}}
{{< /tabs >}}

## Pull an image

Pull an image, like `docker pull`:

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"io"
	"log"
	"os"

	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	out, err := apiClient.ImagePull(ctx, "alpine", client.ImagePullOptions{})
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	io.Copy(os.Stdout, out)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
image = client.images.pull("alpine")
print(image.id)
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ curl --unix-socket /var/run/docker.sock \
  -X POST "http://localhost/v{{% param "latest_engine_api_version" %}}/images/create?fromImage=alpine"
{"status":"Pulling from library/alpine","id":"3.1"}
{"status":"Pulling fs layer","progressDetail":{},"id":"8f13703509f7"}
{"status":"Downloading","progressDetail":{"current":32768,"total":2244027},"progress":"[\u003e                                                  ] 32.77 kB/2.244 MB","id":"8f13703509f7"}
...
```

{{< /tab >}}
{{< /tabs >}}

## Pull an image with authentication

Pull an image, like `docker pull`, with authentication:

> [!NOTE]
>
> Credentials are sent in the clear. Docker's official registries use
> HTTPS. Private registries should also be configured to use HTTPS.

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"io"
	"log"
	"os"

	"github.com/moby/moby/api/pkg/authconfig"
	"github.com/moby/moby/api/types/registry"
	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	authStr, err := authconfig.Encode(registry.AuthConfig{
		Username: "username",
		Password: "password",
	})
	if err != nil {
		log.Fatal(err)
	}

	out, err := apiClient.ImagePull(ctx, "alpine", client.ImagePullOptions{RegistryAuth: authStr})
	if err != nil {
		log.Fatal(err)
	}
	defer out.Close()

	io.Copy(os.Stdout, out)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

The Python SDK retrieves authentication information from the [credentials
store](/reference/cli/docker/login/#credential-stores) file and
integrates with [credential
helpers](https://github.com/docker/docker-credential-helpers). It's possible to override these credentials, but that's out of
scope for this example guide. After using `docker login`, the Python SDK
uses these credentials automatically.

```python
import docker
client = docker.from_env()
image = client.images.pull("alpine")
print(image.id)
```

{{< /tab >}}
{{< tab name="HTTP" >}}

This example leaves the credentials in your shell's history, so consider
this a naive implementation. The credentials are passed as a Base-64-encoded
JSON structure.

```console
$ JSON=$(echo '{"username": "string", "password": "string", "serveraddress": "string"}' | base64)

$ curl --unix-socket /var/run/docker.sock \
  -H "Content-Type: application/tar"
  -X POST "http://localhost/v{{% param "latest_engine_api_version" %}}/images/create?fromImage=alpine"
  -H "X-Registry-Auth"
  -d "$JSON"
{"status":"Pulling from library/alpine","id":"3.1"}
{"status":"Pulling fs layer","progressDetail":{},"id":"8f13703509f7"}
{"status":"Downloading","progressDetail":{"current":32768,"total":2244027},"progress":"[\u003e                                                  ] 32.77 kB/2.244 MB","id":"8f13703509f7"}
...
```

{{< /tab >}}
{{< /tabs >}}

## Commit a container

Commit a container to create an image from its contents:

{{< tabs group="lang" >}}
{{< tab name="Go" >}}

```go
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/moby/moby/api/types/container"
	"github.com/moby/moby/client"
)

func main() {
	ctx := context.Background()
	apiClient, err := client.New(client.FromEnv, client.WithUserAgent("my-application/1.0.0"))
	if err != nil {
		log.Fatal(err)
	}
	defer apiClient.Close()

	createResp, err := apiClient.ContainerCreate(ctx, client.ContainerCreateOptions{
		Config: &container.Config{
			Cmd: []string{"touch", "/helloworld"},
		},
		Image: "alpine",
	})
	if err != nil {
		log.Fatal(err)
	}

	if _, err := apiClient.ContainerStart(ctx, createResp.ID, client.ContainerStartOptions{}); err != nil {
		log.Fatal(err)
	}

	wait := apiClient.ContainerWait(ctx, createResp.ID, client.ContainerWaitOptions{})
	select {
	case err := <-wait.Error:
		if err != nil {
			log.Fatal(err)
		}
	case <-wait.Result:
	}

	commitResp, err := apiClient.ContainerCommit(ctx, createResp.ID, client.ContainerCommitOptions{Reference: "helloworld"})
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(commitResp.ID)
}
```

{{< /tab >}}
{{< tab name="Python" >}}

```python
import docker
client = docker.from_env()
container = client.containers.run("alpine", ["touch", "/helloworld"], detach=True)
container.wait()
image = container.commit("helloworld")
print(image.id)
```

{{< /tab >}}
{{< tab name="HTTP" >}}

```console
$ docker run -d alpine touch /helloworld
0888269a9d584f0fa8fc96b3c0d8d57969ceea3a64acf47cd34eebb4744dbc52
$ curl --unix-socket /var/run/docker.sock\
  -X POST "http://localhost/v{{% param "latest_engine_api_version" %}}/commit?container=0888269a9d&repo=helloworld"
{"Id":"sha256:6c86a5cd4b87f2771648ce619e319f3e508394b5bfc2cdbd2d60f59d52acda6c"}
```

{{< /tab >}}
{{< /tabs >}}


---

# API reference by version

*Sección: Reference*




---

# Docker Engine API v1.40 reference

*Sección: Reference*




---

# Docker Engine API v1.41 reference

*Sección: Reference*




---

# Docker Engine API v1.42 reference

*Sección: Reference*




---

# Docker Engine API v1.43 reference

*Sección: Reference*




---

# Docker Engine API v1.44 reference

*Sección: Reference*




---

# Docker Engine API v1.45 reference

*Sección: Reference*




---

# Docker Engine API v1.46 reference

*Sección: Reference*




---

# Docker Engine API v1.47 reference

*Sección: Reference*




---

# Docker Engine API v1.48 reference

*Sección: Reference*




---

# Docker Engine API v1.49 reference

*Sección: Reference*




---

# Docker Engine API v1.50 reference

*Sección: Reference*




---

# Docker Engine API v1.51 reference

*Sección: Reference*




---

# Docker Engine API v1.52 reference

*Sección: Reference*




---

# Docker Engine API v1.53 reference

*Sección: Reference*




---

# Docker Engine API v1.54 reference

*Sección: Reference*




---

# Docker Engine API v1.55 reference

*Sección: Reference*




---

# Docker Engine API v1.56 reference

*Sección: Reference*




---

# Interface: BackendV0

*Sección: Reference*

## Container Methods

### execInContainer

▸ **execInContainer**(`container`, `cmd`): `Promise`<[`ExecResultV0`](execresultv0.md)\>

Executes a command inside a container.

```typescript
const output = await window.ddClient.backend.execInContainer(container, cmd);

console.log(output);
```

> [!WARNING]
>
> It will be removed in a future version.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `container` | `string` | - |
| `cmd` | `string` | The command to be executed. |

#### Returns

`Promise`<[`ExecResultV0`](execresultv0.md)\>

___

## HTTP Methods

### get

▸ **get**(`url`): `Promise`<`unknown`\>

Performs an HTTP GET request to a backend service.

```typescript
window.ddClient.backend
 .get("/some/service")
 .then((value: any) => console.log(value));
```

> [!WARNING]
>
> It will be removed in a future version. Use [get](httpservice.md#get) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

### post

▸ **post**(`url`, `data`): `Promise`<`unknown`\>

Performs an HTTP POST request to a backend service.

```typescript
window.ddClient.backend
 .post("/some/service", { ... })
 .then((value: any) => console.log(value));
```

> [!WARNING]
>
> It will be removed in a future version. Use [post](httpservice.md#post) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |
| `data` | `any` | The body of the request. |

#### Returns

`Promise`<`unknown`\>

___

### put

▸ **put**(`url`, `data`): `Promise`<`unknown`\>

Performs an HTTP PUT request to a backend service.

```typescript
window.ddClient.backend
 .put("/some/service", { ... })
 .then((value: any) => console.log(value));
```

> [!WARNING]
> 
> It will be removed in a future version. Use [put](httpservice.md#put) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |
| `data` | `any` | The body of the request. |

#### Returns

`Promise`<`unknown`\>

___

### patch

▸ **patch**(`url`, `data`): `Promise`<`unknown`\>

Performs an HTTP PATCH request to a backend service.

```typescript
window.ddClient.backend
 .patch("/some/service", { ... })
 .then((value: any) => console.log(value));
```

> [!WARNING]
>
> It will be removed in a future version. Use [patch](httpservice.md#patch) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |
| `data` | `any` | The body of the request. |

#### Returns

`Promise`<`unknown`\>

___

### delete

▸ **delete**(`url`): `Promise`<`unknown`\>

Performs an HTTP DELETE request to a backend service.

```typescript
window.ddClient.backend
 .delete("/some/service")
 .then((value: any) => console.log(value));
```

> [!WARNING]
>
> It will be removed in a future version. Use [delete](httpservice.md#delete) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

### head

▸ **head**(`url`): `Promise`<`unknown`\>

Performs an HTTP HEAD request to a backend service.

```typescript
window.ddClient.backend
 .head("/some/service")
 .then((value: any) => console.log(value));
```

> [!WARNING]
>
> It will be removed in a future version. Use [head](httpservice.md#head) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

### request

▸ **request**(`config`): `Promise`<`unknown`\>

Performs an HTTP request to a backend service.

```typescript
window.ddClient.backend
 .request({ url: "/url", method: "GET", headers: { 'header-key': 'header-value' }, data: { ... }})
 .then((value: any) => console.log(value));
```

> [!WARNING]
>
> It will be removed in a future version. Use [request](httpservice.md#request) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `config` | [`RequestConfigV0`](requestconfigv0.md) | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

## VM Methods

### execInVMExtension

▸ **execInVMExtension**(`cmd`): `Promise`<[`ExecResultV0`](execresultv0.md)\>

Executes a command inside the backend container.
If your extensions ships with additional binaries that should be run inside the backend container you can use the `execInVMExtension` function.

```typescript
const output = await window.ddClient.backend.execInVMExtension(
  `cliShippedInTheVm xxx`
);

console.log(output);
```

> [!WARNING]
>
> It will be removed in a future version. Use [exec](extensioncli.md#exec) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to be executed. |

#### Returns

`Promise`<[`ExecResultV0`](execresultv0.md)\>

___

### spawnInVMExtension

▸ **spawnInVMExtension**(`cmd`, `args`, `callback`): `void`

Returns a stream from the command executed in the backend container.

```typescript
window.ddClient.spawnInVMExtension(
  `cmd`,
  [`arg1`, `arg2`],
  (data: any, err: any) => {
    console.log(data.stdout, data.stderr);
    // Once the command exits we get the status code
    if (data.code) {
      console.log(data.code);
    }
  }
);
```

> [!WARNING]
>
> It will be removed in a future version.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to be executed. |
| `args` | `string`[] | The arguments of the command to execute. |
| `callback` | (`data`: `any`, `error`: `any`) => `void` | The callback function where to listen from the command output data and errors. |

#### Returns

`void`


---

# Interface: DesktopUI

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### toast

• `Readonly` **toast**: [`Toast`](toast.md)

___

### dialog

• `Readonly` **dialog**: [`Dialog`](dialog.md)

___

### navigate

• `Readonly` **navigate**: [`NavigationIntents`](navigationintents.md)


---

# Interface: Dialog

*Sección: Reference*

Allows opening native dialog boxes.

**`Since`**

0.2.3

## Methods

### showOpenDialog

▸ **showOpenDialog**(`dialogProperties`): `Promise`<[`OpenDialogResult`](opendialogresult.md)\>

Display a native open dialog. Lets you select a file or a folder.

```typescript
ddClient.desktopUI.dialog.showOpenDialog({properties: ['openFile']});
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `dialogProperties` | `any` | Properties to specify the open dialog behaviour, see https://www.electronjs.org/docs/latest/api/dialog#dialogshowopendialogbrowserwindow-options. |

#### Returns

`Promise`<[`OpenDialogResult`](opendialogresult.md)\>


---

# Interface: Docker

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### cli

• `Readonly` **cli**: [`DockerCommand`](dockercommand.md)

You can also directly execute the Docker binary.

```typescript
const output = await ddClient.docker.cli.exec("volume", [
  "ls",
  "--filter",
  "dangling=true"
]);
```

Output:

```json
{
  "stderr": "...",
  "stdout": "..."
}
```

For convenience, the command result object also has methods to easily parse it depending on output format. See [ExecResult](execresult.md) instead.

---

Streams the output as a result of the execution of a Docker command.
It is useful when the output of the command is too long, or you need to get the output as a stream.

```typescript
await ddClient.docker.cli.exec("logs", ["-f", "..."], {
  stream: {
    onOutput(data): void {
        // As we can receive both `stdout` and `stderr`, we wrap them in a JSON object
        JSON.stringify(
          {
            stdout: data.stdout,
            stderr: data.stderr,
          },
          null,
          "  "
        );
    },
    onError(error: any): void {
      console.error(error);
    },
    onClose(exitCode: number): void {
      console.log("onClose with exit code " + exitCode);
    },
  },
});
```

## Methods

### listContainers

▸ **listContainers**(`options?`): `Promise`<`unknown`\>

Get the list of running containers (same as `docker ps`).

By default, this will not list stopped containers.
You can use the option `{"all": true}` to list all the running and stopped containers.

```typescript
const containers = await ddClient.docker.listContainers();
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `options?` | `any` | (Optional). A JSON like `{ "all": true, "limit": 10, "size": true, "filters": JSON.stringify({ status: ["exited"] }), }` For more information about the different properties see [the Docker API endpoint documentation](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerList). |

#### Returns

`Promise`<`unknown`\>

---

### listImages

▸ **listImages**(`options?`): `Promise`<`unknown`\>

Get the list of local container images

```typescript
const images = await ddClient.docker.listImages();
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `options?` | `any` | (Optional). A JSON like `{ "all": true, "filters": JSON.stringify({ dangling: ["true"] }), "digests": true * }` For more information about the different properties see [the Docker API endpoint documentation](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image). |

#### Returns

`Promise`<`unknown`\>


---

# Interface: DockerCommand

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### exec

• **exec**: [`Exec`](exec.md)


---

# Interface: DockerDesktopClient

*Sección: Reference*

An amalgam of the v0 and v1 interfaces of the Docker Desktop API client,
provided for backwards compatibility reasons. Unless you're working with
a legacy extension, use the v1 type instead.

## Properties

### backend

• `Readonly` **backend**: `undefined` \| [`BackendV0`](backendv0.md)

The `window.ddClient.backend` object can be used to communicate with the backend defined in the vm section of
the extension metadata.
The client is already connected to the backend.

> [!WARNING]
>
> It will be removed in a future version. Use [extension](dockerdesktopclient.md#extension) instead.

#### Inherited from

DockerDesktopClientV0.backend

___

### extension

• `Readonly` **extension**: [`Extension`](extension.md)

The `ddClient.extension` object can be used to communicate with the backend defined in the vm section of the
extension metadata.
The client is already connected to the backend.

#### Inherited from

DockerDesktopClientV1.extension

___

### desktopUI

• `Readonly` **desktopUI**: [`DesktopUI`](desktopui.md)

#### Inherited from

DockerDesktopClientV1.desktopUI

___

### host

• `Readonly` **host**: [`Host`](host.md)

#### Inherited from

DockerDesktopClientV1.host

___

### docker

• `Readonly` **docker**: [`Docker`](docker.md)

#### Inherited from

DockerDesktopClientV1.docker

## Container Methods

### listContainers

▸ **listContainers**(`options`): `Promise`<`unknown`\>

Get the list of running containers (same as `docker ps`).

By default, this will not list stopped containers.
You can use the option `{"all": true}` to list all the running and stopped containers.

```typescript
const containers = await window.ddClient.listContainers();
```

> [!WARNING]
>
> It will be removed in a future version. Use [listContainers](docker.md#listcontainers) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `options` | `never` | (Optional). A JSON like `{ "all": true, "limit": 10, "size": true, "filters": JSON.stringify({ status: ["exited"] }), }` For more information about the different properties see [the Docker API endpoint documentation](https://docs.docker.com/reference/api/engine/version/v1.52/#operation/ContainerList). |

#### Returns

`Promise`<`unknown`\>

#### Inherited from

DockerDesktopClientV0.listContainers

___

## Image Methods

### listImages

▸ **listImages**(`options`): `Promise`<`unknown`\>

Get the list of images

```typescript
const images = await window.ddClient.listImages();
```

> [!WARNING]
>
> It will be removed in a future version. Use [listImages](docker.md#listimages) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `options` | `never` | (Optional). A JSON like `{ "all": true, "filters": JSON.stringify({ dangling: ["true"] }), "digests": true }` For more information about the different properties see [the Docker API endpoint documentation](https://docs.docker.com/reference/api/engine/version/v1.52/#tag/Image). |

#### Returns

`Promise`<`unknown`\>

#### Inherited from

DockerDesktopClientV0.listImages

___

## Navigation Methods

### navigateToContainers

▸ **navigateToContainers**(): `void`

Navigate to the container's window in Docker Desktop.
```typescript
window.ddClient.navigateToContainers();
```

> [!WARNING]
>
> It will be removed in a future version. Use [viewContainers](navigationintents.md#viewcontainers) instead.

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.navigateToContainers

___

### navigateToContainer

▸ **navigateToContainer**(`id`): `Promise`<`any`\>

Navigate to the container window in Docker Desktop.
```typescript
await window.ddClient.navigateToContainer(id);
```

> [!WARNING]
>
> It will be removed in a future version.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`any`\>

A promise that fails if the container doesn't exist.

#### Inherited from

DockerDesktopClientV0.navigateToContainer

___

### navigateToContainerLogs

▸ **navigateToContainerLogs**(`id`): `Promise`<`any`\>

Navigate to the container logs window in Docker Desktop.
```typescript
await window.ddClient.navigateToContainerLogs(id);
```

> [!WARNING]
>
> It will be removed in a future version.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`any`\>

A promise that fails if the container doesn't exist.

#### Inherited from

DockerDesktopClientV0.navigateToContainerLogs

___

### navigateToContainerInspect

▸ **navigateToContainerInspect**(`id`): `Promise`<`any`\>

Navigate to the container inspect window in Docker Desktop.
```typescript
await window.ddClient.navigateToContainerInspect(id);
```

> [!WARNING]
>
> It will be removed in a future version.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`any`\>

A promise that fails if the container doesn't exist.

#### Inherited from

DockerDesktopClientV0.navigateToContainerInspect

___

### navigateToContainerStats

▸ **navigateToContainerStats**(`id`): `Promise`<`any`\>

Navigate to the container stats to see the CPU, memory, disk read/write and network I/O usage.

```typescript
await window.ddClient.navigateToContainerStats(id);
```

> [!WARNING]
>
> It will be removed in a future version.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`any`\>

A promise that fails if the container doesn't exist.

#### Inherited from

DockerDesktopClientV0.navigateToContainerStats

___

### navigateToImages

▸ **navigateToImages**(): `void`

Navigate to the images window in Docker Desktop.
```typescript
await window.ddClient.navigateToImages(id);
```

> [!WARNING]
>
> It will be removed in a future version. Use [viewImages](navigationintents.md#viewimages) instead.

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.navigateToImages

___

### navigateToImage

▸ **navigateToImage**(`id`, `tag`): `Promise`<`any`\>

Navigate to a specific image referenced by `id` and `tag` in Docker Desktop.
In this navigation route you can find the image layers, commands, created time and size.

```typescript
await window.ddClient.navigateToImage(id, tag);
```

> [!WARNING]
>
> It will be removed in a future version. Use [viewImage](navigationintents.md#viewimage) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full image id (including sha), e.g. `sha256:34ab3ae068572f4e85c448b4035e6be5e19cc41f69606535cd4d768a63432673`. |
| `tag` | `string` | The tag of the image, e.g. `latest`, `0.0.1`, etc. |

#### Returns

`Promise`<`any`\>

A promise that fails if the container doesn't exist.

#### Inherited from

DockerDesktopClientV0.navigateToImage

___

### navigateToVolumes

▸ **navigateToVolumes**(): `void`

Navigate to the volumes window in Docker Desktop.

```typescript
await window.ddClient.navigateToVolumes();
```

> [!WARNING]
>
> It will be removed in a future version. Use [viewVolumes](navigationintents.md#viewvolumes) instead.

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.navigateToVolumes

___

### navigateToVolume

▸ **navigateToVolume**(`volume`): `void`

Navigate to a specific volume in Docker Desktop.

```typescript
window.ddClient.navigateToVolume(volume);
```

> [!WARNING]
>
> It will be removed in a future version. Use [viewVolume](navigationintents.md#viewvolume) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `volume` | `string` | The name of the volume, e.g. `my-volume`. |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.navigateToVolume

___

## Other Methods

### execHostCmd

▸ **execHostCmd**(`cmd`): `Promise`<[`ExecResultV0`](execresultv0.md)\>

Invoke a binary on the host. The binary is typically shipped with your extension using the host section in the extension metadata. Note that extensions run with user access rights, this API is not restricted to binaries listed in the host section of the extension metadata (some extensions might install software during user interaction, and invoke newly installed binaries even if not listed in the extension metadata) 

```typescript
window.ddClient.execHostCmd(`cliShippedOnHost xxx`).then((cmdResult: any) => {
 console.log(cmdResult);
});
```

> [!WARNING]
>
> It will be removed in a future version. Use [exec](extensioncli.md#exec) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to be executed. |

#### Returns

`Promise`<[`ExecResultV0`](execresultv0.md)\>

#### Inherited from

DockerDesktopClientV0.execHostCmd

___

### spawnHostCmd

▸ **spawnHostCmd**(`cmd`, `args`, `callback`): `void`

Invoke an extension binary on your host and get the output stream.

```typescript
window.ddClient.spawnHostCmd(
  `cliShippedOnHost`,
  [`arg1`, `arg2`],
  (data: any, err: any) => {
    console.log(data.stdout, data.stderr);
    // Once the command exits we get the status code
    if (data.code) {
      console.log(data.code);
    }
  }
);
```

> [!WARNING]
>
> It will be removed in a future version. Use [exec](extensioncli.md#exec) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to be executed. |
| `args` | `string`[] | The arguments of the command to execute. |
| `callback` | (`data`: `any`, `error`: `any`) => `void` | The callback function where to listen from the command output data and errors. |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.spawnHostCmd

___

### execDockerCmd

▸ **execDockerCmd**(`cmd`, `...args`): `Promise`<[`ExecResultV0`](execresultv0.md)\>

You can also directly execute the Docker binary.

```typescript
const output = await window.ddClient.execDockerCmd("info");
```

> [!WARNING]
>
> It will be removed in a future version. Use [exec](dockercommand.md#exec) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to execute. |
| `...args` | `string`[] | The arguments of the command to execute. |

#### Returns

`Promise`<[`ExecResultV0`](execresultv0.md)\>

The result will contain both the standard output and the standard error of the executed command:
```json
{
  "stderr": "...",
  "stdout": "..."
}
```
For convenience, the command result object also has methods to easily parse it depending on the output format:

- `output.lines(): string[]` splits output lines.
- `output.parseJsonObject(): any` parses a well-formed JSON output.
- `output.parseJsonLines(): any[]` parses each output line as a JSON object.

If the output of the command is too long, or you need to get the output as a stream you can use the
 * spawnDockerCmd function:

```typescript
window.ddClient.spawnDockerCmd("logs", ["-f", "..."], (data, error) => {
  console.log(data.stdout);
});
```

#### Inherited from

DockerDesktopClientV0.execDockerCmd

___

### spawnDockerCmd

▸ **spawnDockerCmd**(`cmd`, `args`, `callback`): `void`

> [!WARNING]
>
> It will be removed in a future version. Use [exec](dockercommand.md#exec) instead.

#### Parameters

| Name | Type |
| :------ | :------ |
| `cmd` | `string` |
| `args` | `string`[] |
| `callback` | (`data`: `any`, `error`: `any`) => `void` |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.spawnDockerCmd

___

### openExternal

▸ **openExternal**(`url`): `void`

Opens an external URL with the system default browser.

```typescript
window.ddClient.openExternal("https://docker.com");
```

> [!WARNING]
>
> It will be removed in a future version. Use [openExternal](host.md#openexternal) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL the browser opens (must have the protocol `http` or `https`). |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.openExternal

___

## Toast Methods

### toastSuccess

▸ **toastSuccess**(`msg`): `void`

Display a toast message of type success.

```typescript
window.ddClient.toastSuccess("message");
```

>**Warning`**
>
> It will be removed in a future version. Use [success](toast.md#success) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `msg` | `string` | The message to display in the toast. |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.toastSuccess

___

### toastWarning

▸ **toastWarning**(`msg`): `void`

Display a toast message of type warning.

```typescript
window.ddClient.toastWarning("message");
```

> [!WARNING]
>
> It will be removed in a future version. Use [warning](toast.md#warning) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `msg` | `string` | The message to display in the toast. |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.toastWarning

___

### toastError

▸ **toastError**(`msg`): `void`

Display a toast message of type error.

```typescript
window.ddClient.toastError("message");
```

> [!WARNING]
>
> It will be removed in a future version. Use [error](toast.md#error) instead.

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `msg` | `string` | The message to display in the toast. |

#### Returns

`void`

#### Inherited from

DockerDesktopClientV0.toastError


---

# Interface: Exec

*Sección: Reference*

## Callable

### Exec

▸ **Exec**(`cmd`, `args`, `options?`): `Promise`<[`ExecResult`](execresult.md)\>

Executes a command.

**`Since`**

0.2.0

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to execute. |
| `args` | `string`[] | The arguments of the command to execute. |
| `options?` | [`ExecOptions`](execoptions.md) | The list of options. |

#### Returns

`Promise`<[`ExecResult`](execresult.md)\>

A promise that will resolve once the command finishes.

### Exec

▸ **Exec**(`cmd`, `args`, `options`): [`ExecProcess`](execprocess.md)

Streams the result of a command if `stream` is specified in the `options` parameter.

Specify the `stream` if the output of your command is too long or if you need to stream things indefinitely (for example container logs).

**`Since`**

0.2.2

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `cmd` | `string` | The command to execute. |
| `args` | `string`[] | The arguments of the command to execute. |
| `options` | [`SpawnOptions`](spawnoptions.md) | The list of options. |

#### Returns

[`ExecProcess`](execprocess.md)

The spawned process.


---

# Interface: ExecOptions

*Sección: Reference*

**`Since`**

0.3.0

## Hierarchy

- **`ExecOptions`**

  ↳ [`SpawnOptions`](spawnoptions.md)

## Properties

### cwd

• `Optional` **cwd**: `string`

___

### env

• `Optional` **env**: `ProcessEnv`


---

# Interface: ExecProcess

*Sección: Reference*

**`Since`**

0.2.3

## Methods

### close

▸ **close**(): `void`

Close the process started by exec(streamingOptions)

#### Returns

`void`


---

# Interface: ExecResult

*Sección: Reference*

**`Since`**

0.2.0

## Hierarchy

- [`RawExecResult`](rawexecresult.md)

  ↳ **`ExecResult`**

## Methods

### lines

▸ **lines**(): `string`[]

Split output lines.

#### Returns

`string`[]

The list of lines.

___

### parseJsonLines

▸ **parseJsonLines**(): `any`[]

Parse each output line as a JSON object.

#### Returns

`any`[]

The list of lines where each line is a JSON object.

___

### parseJsonObject

▸ **parseJsonObject**(): `any`

Parse a well-formed JSON output.

#### Returns

`any`

The JSON object.

## Properties

### cmd

• `Optional` `Readonly` **cmd**: `string`

#### Inherited from

[RawExecResult](rawexecresult.md).[cmd](rawexecresult.md#cmd)

___

### killed

• `Optional` `Readonly` **killed**: `boolean`

#### Inherited from

[RawExecResult](rawexecresult.md).[killed](rawexecresult.md#killed)

___

### signal

• `Optional` `Readonly` **signal**: `string`

#### Inherited from

[RawExecResult](rawexecresult.md).[signal](rawexecresult.md#signal)

___

### code

• `Optional` `Readonly` **code**: `number`

#### Inherited from

[RawExecResult](rawexecresult.md).[code](rawexecresult.md#code)

___

### stdout

• `Readonly` **stdout**: `string`

#### Inherited from

[RawExecResult](rawexecresult.md).[stdout](rawexecresult.md#stdout)

___

### stderr

• `Readonly` **stderr**: `string`

#### Inherited from

[RawExecResult](rawexecresult.md).[stderr](rawexecresult.md#stderr)


---

# Interface: ExecResultV0

*Sección: Reference*

## Properties

### cmd

• `Optional` `Readonly` **cmd**: `string`

___

### killed

• `Optional` `Readonly` **killed**: `boolean`

___

### signal

• `Optional` `Readonly` **signal**: `string`

___

### code

• `Optional` `Readonly` **code**: `number`

___

### stdout

• `Readonly` **stdout**: `string`

___

### stderr

• `Readonly` **stderr**: `string`

## Methods

### lines

▸ **lines**(): `string`[]

Split output lines.

#### Returns

`string`[]

The list of lines.

___

### parseJsonLines

▸ **parseJsonLines**(): `any`[]

Parse each output line as a JSON object.

#### Returns

`any`[]

The list of lines where each line is a JSON object.

___

### parseJsonObject

▸ **parseJsonObject**(): `any`

Parse a well-formed JSON output.

#### Returns

`any`

The JSON object.


---

# Interface: ExecStreamOptions

*Sección: Reference*

**`Since`**

0.2.2

## Properties

### onOutput

• `Optional` **onOutput**: (`data`: { `stdout`: `string` ; `stderr?`: `undefined`  } \| { `stdout?`: `undefined` ; `stderr`: `string`  }) => `void`

#### Type declaration

▸ (`data`): `void`

Invoked when receiving output from command execution.
By default, the output is split into chunks at arbitrary boundaries.
If you prefer the output to be split into complete lines, set `splitOutputLines`
to true. The callback is then invoked once for each line.

**`Since`**

0.2.0

##### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `data` | `{ stdout: string; stderr?: undefined } \| { stdout?: undefined; stderr: string }` | Output content. Can include either stdout string, or stderr string, one at a time. |

##### Returns

`void`

___

### onError

• `Optional` **onError**: (`error`: `any`) => `void`

#### Type declaration

▸ (`error`): `void`

Invoked to report error if the executed command errors.

##### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `error` | `any` | The error happening in the executed command |

##### Returns

`void`

___

### onClose

• `Optional` **onClose**: (`exitCode`: `number`) => `void`

#### Type declaration

▸ (`exitCode`): `void`

Invoked when process exits.

##### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `exitCode` | `number` | The process exit code |

##### Returns

`void`

___

### splitOutputLines

• `Optional` `Readonly` **splitOutputLines**: `boolean`

Specifies the behaviour invoking `onOutput(data)`. Raw output by default, splitting output at any position. If set to true, `onOutput` will be invoked once for each line.


---

# Interface: Extension

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### vm

• `Optional` `Readonly` **vm**: [`ExtensionVM`](extensionvm.md)

___

### host

• `Optional` `Readonly` **host**: [`ExtensionHost`](extensionhost.md)

___

### image

• `Readonly` **image**: `string`

**`Since`**

0.3.3


---

# Interface: ExtensionCli

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### exec

• **exec**: [`Exec`](exec.md)


---

# Interface: ExtensionHost

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### cli

• `Readonly` **cli**: [`ExtensionCli`](extensioncli.md)

Executes a command in the host.

For example, execute the shipped binary `kubectl -h` command in the host:

```typescript
await ddClient.extension.host.cli.exec("kubectl", ["-h"]);
```

---

Streams the output of the command executed in the backend container or in the host.

Provided the `kubectl` binary is shipped as part of your extension, you can spawn the `kubectl -h` command in the host:

```typescript
await ddClient.extension.host.cli.exec("kubectl", ["-h"], {
           stream: {
             onOutput(data): void {
                 // As we can receive both `stdout` and `stderr`, we wrap them in a JSON object
                 JSON.stringify(
                   {
                     stdout: data.stdout,
                     stderr: data.stderr,
                   },
                   null,
                   "  "
                 );
             },
             onError(error: any): void {
               console.error(error);
             },
             onClose(exitCode: number): void {
               console.log("onClose with exit code " + exitCode);
             },
           },
         });
```


---

# Interface: ExtensionVM

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### cli

• `Readonly` **cli**: [`ExtensionCli`](extensioncli.md)

Executes a command in the backend container.

Example: Execute the command `ls -l` inside the backend container:

```typescript
await ddClient.extension.vm.cli.exec(
  "ls",
  ["-l"]
);
```

Streams the output of the command executed in the backend container.

When the extension defines its own `compose.yaml` file
with multiple containers, the command is executed on the first container defined.
Change the order in which containers are defined to execute commands on another
container.

Example: Spawn the command `ls -l` inside the backend container:

```typescript
await ddClient.extension.vm.cli.exec("ls", ["-l"], {
           stream: {
             onOutput(data): void {
                 // As we can receive both `stdout` and `stderr`, we wrap them in a JSON object
                 JSON.stringify(
                   {
                     stdout: data.stdout,
                     stderr: data.stderr,
                   },
                   null,
                   "  "
                 );
             },
             onError(error: any): void {
               console.error(error);
             },
             onClose(exitCode: number): void {
               console.log("onClose with exit code " + exitCode);
             },
           },
         });
```

**`Param`**

Command to execute.

**`Param`**

Arguments of the command to execute.

**`Param`**

The callback function where to listen from the command output data and errors.

___

### service

• `Optional` `Readonly` **service**: [`HttpService`](httpservice.md)


---

# Interface: Host

*Sección: Reference*

**`Since`**

0.2.0

## Methods

### openExternal

▸ **openExternal**(`url`): `void`

Opens an external URL with the system default browser.

**`Since`**

0.2.0

```typescript
ddClient.host.openExternal("https://docker.com");
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL the browser will open (must have the protocol `http` or `https`). |

#### Returns

`void`

## Properties

### platform

• **platform**: `string`

Returns a string identifying the operating system platform. See https://nodejs.org/api/os.html#osplatform

**`Since`**

0.2.2

___

### arch

• **arch**: `string`

Returns the operating system CPU architecture. See https://nodejs.org/api/os.html#osarch

**`Since`**

0.2.2

___

### hostname

• **hostname**: `string`

Returns the host name of the operating system. See https://nodejs.org/api/os.html#oshostname

**`Since`**

0.2.2


---

# Interface: HttpService

*Sección: Reference*

**`Since`**

0.2.0

## Methods

### get

▸ **get**(`url`): `Promise`<`unknown`\>

Performs an HTTP GET request to a backend service.

```typescript
ddClient.extension.vm.service
 .get("/some/service")
 .then((value: any) => console.log(value)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

### post

▸ **post**(`url`, `data`): `Promise`<`unknown`\>

Performs an HTTP POST request to a backend service.

```typescript
ddClient.extension.vm.service
 .post("/some/service", { ... })
 .then((value: any) => console.log(value));
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |
| `data` | `any` | The body of the request. |

#### Returns

`Promise`<`unknown`\>

___

### put

▸ **put**(`url`, `data`): `Promise`<`unknown`\>

Performs an HTTP PUT request to a backend service.

```typescript
ddClient.extension.vm.service
 .put("/some/service", { ... })
 .then((value: any) => console.log(value));
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |
| `data` | `any` | The body of the request. |

#### Returns

`Promise`<`unknown`\>

___

### patch

▸ **patch**(`url`, `data`): `Promise`<`unknown`\>

Performs an HTTP PATCH request to a backend service.

```typescript
ddClient.extension.vm.service
 .patch("/some/service", { ... })
 .then((value: any) => console.log(value));
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |
| `data` | `any` | The body of the request. |

#### Returns

`Promise`<`unknown`\>

___

### delete

▸ **delete**(`url`): `Promise`<`unknown`\>

Performs an HTTP DELETE request to a backend service.

```typescript
ddClient.extension.vm.service
 .delete("/some/service")
 .then((value: any) => console.log(value));
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

### head

▸ **head**(`url`): `Promise`<`unknown`\>

Performs an HTTP HEAD request to a backend service.

```typescript
ddClient.extension.vm.service
 .head("/some/service")
 .then((value: any) => console.log(value));
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `url` | `string` | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>

___

### request

▸ **request**(`config`): `Promise`<`unknown`\>

Performs an HTTP request to a backend service.

```typescript
ddClient.extension.vm.service
 .request({ url: "/url", method: "GET", headers: { 'header-key': 'header-value' }, data: { ... }})
 .then((value: any) => console.log(value));
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `config` | [`RequestConfig`](requestconfig.md) | The URL of the backend service. |

#### Returns

`Promise`<`unknown`\>


---

# Interface: NavigationIntents

*Sección: Reference*

**`Since`**

0.2.0

## Container Methods

### viewContainers

▸ **viewContainers**(): `Promise`<`void`\>

Navigate to the **Containers** tab in Docker Desktop.

```typescript
ddClient.desktopUI.navigate.viewContainers()
```

#### Returns

`Promise`<`void`\>

___

### viewContainer

▸ **viewContainer**(`id`): `Promise`<`void`\>

Navigate to the **Container** tab in Docker Desktop.

```typescript
await ddClient.desktopUI.navigate.viewContainer(id)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`void`\>

A promise that fails if the container doesn't exist.

___

### viewContainerLogs

▸ **viewContainerLogs**(`id`): `Promise`<`void`\>

Navigate to the **Container logs** tab in Docker Desktop.

```typescript
await ddClient.desktopUI.navigate.viewContainerLogs(id)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`void`\>

A promise that fails if the container doesn't exist.

___

### viewContainerInspect

▸ **viewContainerInspect**(`id`): `Promise`<`void`\>

Navigate to the **Inspect container** view in Docker Desktop.

```typescript
await ddClient.desktopUI.navigate.viewContainerInspect(id)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`void`\>

A promise that fails if the container doesn't exist.

___

### viewContainerTerminal

▸ **viewContainerTerminal**(`id`): `Promise`<`void`\>

Navigate to the container terminal window in Docker Desktop.

```typescript
await ddClient.desktopUI.navigate.viewContainerTerminal(id)
```

**`Since`**

0.3.4

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`void`\>

A promise that fails if the container doesn't exist.

___

### viewContainerStats

▸ **viewContainerStats**(`id`): `Promise`<`void`\>

Navigate to the container stats to see the CPU, memory, disk read/write and network I/O usage.

```typescript
await ddClient.desktopUI.navigate.viewContainerStats(id)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full container id, e.g. `46b57e400d801762e9e115734bf902a2450d89669d85881058a46136520aca28`. You can use the `--no-trunc` flag as part of the `docker ps` command to display the full container id. |

#### Returns

`Promise`<`void`\>

A promise that fails if the container doesn't exist.

___

## Images Methods

### viewImages

▸ **viewImages**(): `Promise`<`void`\>

Navigate to the **Images** tab in Docker Desktop.

```typescript
await ddClient.desktopUI.navigate.viewImages()
```

#### Returns

`Promise`<`void`\>

___

### viewImage

▸ **viewImage**(`id`, `tag`): `Promise`<`void`\>

Navigate to a specific image referenced by `id` and `tag` in Docker Desktop.
In this navigation route you can find the image layers, commands, created time and size.

```typescript
await ddClient.desktopUI.navigate.viewImage(id, tag)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `id` | `string` | The full image id (including sha), e.g. `sha256:34ab3ae068572f4e85c448b4035e6be5e19cc41f69606535cd4d768a63432673`. |
| `tag` | `string` | The tag of the image, e.g. `latest`, `0.0.1`, etc. |

#### Returns

`Promise`<`void`\>

A promise that fails if the image doesn't exist.

___

## Volume Methods

### viewVolumes

▸ **viewVolumes**(): `Promise`<`void`\>

Navigate to the **Volumes** tab in Docker Desktop.

```typescript
ddClient.desktopUI.navigate.viewVolumes()
```

#### Returns

`Promise`<`void`\>

___

### viewVolume

▸ **viewVolume**(`volume`): `Promise`<`void`\>

Navigate to a specific volume in Docker Desktop.

```typescript
await ddClient.desktopUI.navigate.viewVolume(volume)
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `volume` | `string` | The name of the volume, e.g. `my-volume`. |

#### Returns

`Promise`<`void`\>


---

# Interface: OpenDialogResult

*Sección: Reference*

**`Since`**

0.2.3

## Properties

### canceled

• `Readonly` **canceled**: `boolean`

Whether the dialog was canceled.

___

### filePaths

• `Readonly` **filePaths**: `string`[]

An array of file paths chosen by the user. If the dialog is cancelled this will be an empty array.

___

### bookmarks

• `Optional` `Readonly` **bookmarks**: `string`[]

macOS only. An array matching the `filePaths` array of `base64` encoded strings which contains security scoped bookmark data. `securityScopedBookmarks` must be enabled for this to be populated.


---

# Interface: RawExecResult

*Sección: Reference*

**`Since`**

0.2.0

## Hierarchy

- **`RawExecResult`**

  ↳ [`ExecResult`](execresult.md)

## Properties

### cmd

• `Optional` `Readonly` **cmd**: `string`

___

### killed

• `Optional` `Readonly` **killed**: `boolean`

___

### signal

• `Optional` `Readonly` **signal**: `string`

___

### code

• `Optional` `Readonly` **code**: `number`

___

### stdout

• `Readonly` **stdout**: `string`

___

### stderr

• `Readonly` **stderr**: `string`


---

# Interface: RequestConfig

*Sección: Reference*

**`Since`**

0.2.0

## Properties

### url

• `Readonly` **url**: `string`

___

### method

• `Readonly` **method**: `string`

___

### headers

• `Readonly` **headers**: `Record`<`string`, `string`\>

___

### data

• `Readonly` **data**: `any`


---

# Interface: RequestConfigV0

*Sección: Reference*

## Properties

### url

• `Readonly` **url**: `string`

___

### method

• `Readonly` **method**: `string`

___

### headers

• `Readonly` **headers**: `Record`<`string`, `string`\>

___

### data

• `Readonly` **data**: `any`


---

# Interface: ServiceError

*Sección: Reference*

Error thrown when an HTTP response is received with a status code that falls
out to the range of 2xx.

**`Since`**

0.2.0

## Properties

### name

• **name**: `string`

___

### message

• **message**: `string`

___

### statusCode

• **statusCode**: `number`


---

# Interface: SpawnOptions

*Sección: Reference*

**`Since`**

0.3.0

## Hierarchy

- [`ExecOptions`](execoptions.md)

  ↳ **`SpawnOptions`**

## Properties

### cwd

• `Optional` **cwd**: `string`

#### Inherited from

[ExecOptions](execoptions.md).[cwd](execoptions.md#cwd)

___

### env

• `Optional` **env**: `ProcessEnv`

#### Inherited from

[ExecOptions](execoptions.md).[env](execoptions.md#env)

___

### stream

• **stream**: [`ExecStreamOptions`](execstreamoptions.md)


---

# Interface: Toast

*Sección: Reference*

Toasts provide a brief notification to the user.
They appear temporarily and shouldn't interrupt the user experience.
They also don't require user input to disappear.

**`Since`**

0.2.0

## Methods

### success

▸ **success**(`msg`): `void`

Display a toast message of type success.

```typescript
ddClient.desktopUI.toast.success("message");
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `msg` | `string` | The message to display in the toast. |

#### Returns

`void`

___

### warning

▸ **warning**(`msg`): `void`

Display a toast message of type warning.

```typescript
ddClient.desktopUI.toast.warning("message");
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `msg` | `string` | The message to display in the warning. |

#### Returns

`void`

___

### error

▸ **error**(`msg`): `void`

Display a toast message of type error.

```typescript
ddClient.desktopUI.toast.error("message");
```

#### Parameters

| Name | Type | Description |
| :------ | :------ | :------ |
| `msg` | `string` | The message to display in the toast. |

#### Returns

`void`


---

# Extensions API Reference

*Sección: Reference*

## Dashboard interfaces

- [Host](host.md)
- [NavigationIntents](navigationintents.md)
- [Toast](toast.md)

## Other interfaces

- [ExecResultV0](execresultv0.md)
- [RequestConfigV0](requestconfigv0.md)
- [BackendV0](backendv0.md)
- [OpenDialogResult](opendialogresult.md)
- [Dialog](dialog.md)
- [Docker](docker.md)
- [DockerCommand](dockercommand.md)
- [ExecOptions](execoptions.md)
- [SpawnOptions](spawnoptions.md)
- [Exec](exec.md)
- [ExecProcess](execprocess.md)
- [ExecStreamOptions](execstreamoptions.md)
- [ExecResult](execresult.md)
- [RawExecResult](rawexecresult.md)
- [Extension](extension.md)
- [DesktopUI](desktopui.md)
- [ExtensionVM](extensionvm.md)
- [ExtensionHost](extensionhost.md)
- [ExtensionCli](extensioncli.md)
- [HttpService](httpservice.md)
- [RequestConfig](requestconfig.md)
- [ServiceError](serviceerror.md)
- [DockerDesktopClient](dockerdesktopclient.md)


---

# Docker Hub API

*Sección: Reference*




---

# Docker Hub API changelog

*Sección: Reference*

Here you can learn about the latest changes, new features, bug fixes, and known
issues for Docker Service APIs.

---

## 2026-09-01

### Updates

- Document that [Update org member (role)](/reference/api/hub/latest/#tag/orgs)
  accepts a custom role name in `role`.
- Document the `role` field on
  [Update some details for an organization group](/reference/api/hub/latest/#tag/groups).
- Add `Editor` to `org_member.role` on
  [organization members](/reference/api/hub/latest/#tag/orgs).

---

## 2026-08-27

### Updates

- Document organization access token (OAT) support for
  [repository management](/reference/api/hub/latest/#tag/repositories)
  endpoints, the scope-dependent behavior of
  [List repositories](/reference/api/hub/latest/#tag/repositories/operation/listNamespaceRepositories),
  and legacy paths that are OAT unsupported.

---

## 2025-11-21

### Updates

- Add missing `expires_at` fields on [PAT management](/reference/api/hub/latest/#tag/access-tokens) endpoints.

## 2025-09-25

### Updates

- Fix [Assign repository group](/reference/api/hub/latest/#tag/repositories/operation/CreateRepositoryGroup) endpoints request/response

---

## 2025-09-19

### New

- Add [Create repository](/reference/api/hub/latest/#tag/repositories/operation/CreateRepository) endpoints for a given `namespace`.
- Add [Get repository](/reference/api/hub/latest/#tag/repositories/operation/GetRepository) endpoints for a given `namespace`.
- Add [Check repository](/reference/api/hub/latest/#tag/repositories/operation/CheckRepository) endpoints for a given `namespace`.

### Deprecations

- [Deprecate POST /v2/repositories](/reference/api/hub/deprecated/#deprecate-legacy-createrepository)
- [Deprecate POST /v2/repositories/{namespace}](/reference/api/hub/deprecated/#deprecate-legacy-createrepository)
- [Deprecate GET /v2/repositories/{namespace}/{repository}](/reference/api/hub/deprecated/#deprecate-legacy-getrepository)
- [Deprecate HEAD /v2/repositories/{namespace}/{repository}](/reference/api/hub/deprecated/#deprecate-legacy-getrepository)

---

## 2025-07-29

### New

- Add [Update repository immutable tags settings](/reference/api/hub/latest/#tag/repositories/operation/UpdateRepositoryImmutableTags) endpoints for a given `namespace` and `repository`.
- Add [Verify repository immutable tags](/reference/api/hub/latest/#tag/repositories/operation/VerifyRepositoryImmutableTags) endpoints for a given `namespace` and `repository`.

---

## 2025-06-27

### New

- Add [List repositories](/reference/api/hub/latest/#tag/repositories/operation/listNamespaceRepositories) endpoints for a given `namespace`.

### Deprecations

- [Deprecate /v2/repositories/{namespace}](/reference/api/hub/deprecated/#deprecate-legacy-listnamespacerepositories)

---

## 2025-03-25

### New

- Add [APIs](/reference/api/hub/latest/#tag/org-access-tokens) for organization access token (OATs) management.

---

## 2025-03-18

### New

- Add access to [audit logs](/reference/api/hub/latest/#tag/audit-logs) for org
  access tokens.


---

# Deprecated Docker Hub API endpoints

*Sección: Reference*

This page provides an overview of endpoints that are deprecated in Docker Hub API.

## Endpoint deprecation policy

As changes are made to Docker there may be times when existing endpoints need to be removed or replaced with newer endpoints. Before an existing endpoint is removed it is labeled as "deprecated" within the documentation. After some time it may be removed.

## Deprecated endpoints

The following table provides an overview of the current status of deprecated endpoints:

**Deprecated**: the endpoint is marked "deprecated" and should no longer be used.

The endpoint may be removed, disabled, or change behavior in a future release.

**Removed**: the endpoint was removed, disabled, or hidden.

---

| Status     | Feature                                                                                              | Date       |
|------------|------------------------------------------------------------------------------------------------------|------------|
| Deprecated | [Deprecate undocumented create/get repository](#deprecate-legacy-createrepository-and-getrepository) | 2025-09-19 |
| Deprecated | [Deprecate /v2/repositories/{namespace}](#deprecate-legacy-listnamespacerepositories)                | 2025-06-27 |
|            | [Create deprecation log table](#create-deprecation-log-table)                                        | 2025-06-27 |
| Removed    | [Docker Hub API v1 deprecation](#docker-hub-api-v1-deprecation)                                      | 2022-08-23 |

---

### Deprecate legacy CreateRepository and GetRepository

Deprecate undocumented endpoints :
- `POST /v2/repositories` and `POST /v2/repositories/{namespace}` replaced by [Create repository](/reference/api/hub/latest/#tag/repositories/operation/CreateRepository).
- `GET /v2/repositories/{namespace}/{repository}` replaced by [Get repository](/reference/api/hub/latest/#tag/repositories/operation/GetRepository).
- `HEAD /v2/repositories/{namespace}/{repository}` replaced by [Check repository](/reference/api/hub/latest/#tag/repositories/operation/CheckRepository).

---

### Deprecate legacy ListNamespaceRepositories

Deprecate undocumented endpoint `GET /v2/repositories/{namespace}` replaced by [List repositories](/reference/api/hub/latest/#tag/repositories/operation/listNamespaceRepositories).

---

### Create deprecation log table

Reformat page

---

### Docker Hub API v1 deprecation

Docker Hub API v1 has been deprecated. Use Docker Hub API v2 instead.

The following API routes within the v1 path will no longer work and will return a 410 status code:
* `/v1/repositories/{name}/images`
* `/v1/repositories/{name}/tags`
* `/v1/repositories/{name}/tags/{tag_name}`
* `/v1/repositories/{namespace}/{name}/images`
* `/v1/repositories/{namespace}/{name}/tags`
* `/v1/repositories/{namespace}/{name}/tags/{tag_name}`

If you want to continue using the Docker Hub API in your current applications, update your clients to use v2 endpoints.

| **OLD**                                                                                                                                                              | **NEW**                                                                                                                                   |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
| [/v1/repositories/{name}/tags](https://github.com/moby/moby/blob/v1.8.3/docs/reference/api/registry_api.md#list-repository-tags)                                     | [/v2/namespaces/{namespace}/repositories/{repository}/tags](/reference/api/hub/latest/#tag/repositories/operation/ListRepositoryTags)     |
| [/v1/repositories/{namespace}/{name}/tags](https://github.com/moby/moby/blob/v1.8.3/docs/reference/api/registry_api.md#list-repository-tags)                         | [/v2/namespaces/{namespace}/repositories/{repository}/tags](/reference/api/hub/latest.md/#tag/repositories/operation/ListRepositoryTags)  |
| [/v1/repositories/{namespace}/{name}/tags](https://github.com/moby/moby/blob/v1.8.3/docs/reference/api/registry_api.md#get-image-id-for-a-particular-tag)            | [/v2/namespaces/{namespace}/repositories/{repository}/tags/{tag}](/reference/api/hub/latest/#tag/repositories/operation/GetRepositoryTag) |
| [/v1/repositories/{namespace}/{name}/tags/{tag_name}](https://github.com/moby/moby/blob/v1.8.3/docs/reference/api/registry_api.md#get-image-id-for-a-particular-tag) | [/v2/namespaces/{namespace}/repositories/{repository}/tags/{tag}](/reference/api/hub/latest/#tag/repositories/operation/GetRepositoryTag) |

---


---

# Docker Hub API reference

*Sección: Reference*




---

# Index

*Sección: Reference*

---
title: Registry API
build:
  render: never
---


---

# Registry authentication

*Sección: Reference*

This document outlines the registry authentication scheme:

![v2 registry auth](./images/v2-registry-auth.png)

1. Attempt to begin a push/pull operation with the registry.
2. If the registry requires authorization it will return a `401 Unauthorized`
   HTTP response with information on how to authenticate.
3. The registry client makes a request to the authorization service for a
   Bearer token.
4. The authorization service returns an opaque Bearer token representing the
   client's authorized access.
5. The client retries the original request with the Bearer token embedded in
   the request's Authorization header.
6. The Registry authorizes the client by validating the Bearer token and the
   claim set embedded within it and begins the push/pull session as usual.

## Requirements

- Registry clients which can understand and respond to token auth challenges
  returned by the resource server.
- An authorization server capable of managing access controls to their
  resources hosted by any given service (such as repositories in a Docker
  Registry).
- A Docker Registry capable of trusting the authorization server to sign tokens
  which clients can use for authorization and the ability to verify these
  tokens for single use or for use during a sufficiently short period of time.

## Authorization server endpoint descriptions

The described server is meant to serve as a standalone access control manager
for resources hosted by other services which want to authenticate and manage
authorizations using a separate access control manager.

A service like this is used by the official Docker Registry to authenticate
clients and verify their authorization to Docker image repositories.

As of Docker 1.6, the registry client within the Docker Engine has been updated
to handle such an authorization workflow.

## How to authenticate

Registry V1 clients first contact the index to initiate a push or pull. Under
the Registry V2 workflow, clients should contact the registry first. If the
registry server requires authentication it will return a `401 Unauthorized`
response with a `WWW-Authenticate` header detailing how to authenticate to this
registry.

For example, say I (username `jlhawn`) am attempting to push an image to the
repository `samalba/my-app`. For the registry to authorize this, I will need
`push` access to the `samalba/my-app` repository. The registry will first
return this response:

```text
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"
Date: Thu, 10 Sep 2015 19:32:31 GMT
Content-Length: 235
Strict-Transport-Security: max-age=31536000

{"errors":[{"code":"UNAUTHORIZED","message":"access to the requested resource is not authorized","detail":[{"Type":"repository","Name":"samalba/my-app","Action":"pull"},{"Type":"repository","Name":"samalba/my-app","Action":"push"}]}]}
```

Note the HTTP Response Header indicating the auth challenge:

```text
Www-Authenticate: Bearer realm="https://auth.docker.io/token",service="registry.docker.io",scope="repository:samalba/my-app:pull,push"
```

This format is documented in [Section 3 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-3)

This challenge indicates that the registry requires a token issued by the
specified token server and that the request the client is attempting will
need to include sufficient access entries in its claim set. To respond to this
challenge, the client will need to make a `GET` request to the URL
`https://auth.docker.io/token` using the `service` and `scope` values from the
`WWW-Authenticate` header.

## Requesting a token

Defines getting a bearer and refresh token using the token endpoint.

### Query parameters

#### `service`

The name of the service which hosts the resource.

#### `offline_token`

Whether to return a refresh token along with the bearer token. A refresh token
is capable of getting additional bearer tokens for the same subject with
different scopes. The refresh token does not have an expiration and should be
considered completely opaque to the client.

#### `client_id`

String identifying the client. This `client_id` does not need to be registered
with the authorization server but should be set to a meaningful value in order
to allow auditing keys created by unregistered clients. Accepted syntax is
defined in [RFC6749 Appendix
A.1](https://tools.ietf.org/html/rfc6749#appendix-A.1).

#### `scope`

The resource in question, formatted as one of the space-delimited entries from
the `scope` parameters from the `WWW-Authenticate` header shown previously. This
query parameter should be specified multiple times if there is more than one
`scope` entry from the `WWW-Authenticate` header. The previous example would be
specified as: `scope=repository:samalba/my-app:push`. The scope field may be
empty to request a refresh token without providing any resource permissions to
the returned bearer token.

### Token response fields

#### `token`

An opaque `Bearer` token that clients should supply to subsequent
requests in the `Authorization` header.

#### `access_token`

For compatibility with OAuth 2.0, the `token` under the name `access_token` is
also accepted. At least one of these fields must be specified, but both may
also appear (for compatibility with older clients). When both are specified,
they should be equivalent; if they differ the client's choice is undefined.

#### `expires_in`

(Optional) The duration in seconds since the token was issued that it will
remain valid. When omitted, this defaults to 60 seconds. For compatibility
with older clients, a token should never be returned with less than 60 seconds
to live.

#### `issued_at`

(Optional) The [RFC3339](https://www.ietf.org/rfc/rfc3339.txt)-serialized UTC
standard time at which a given token was issued. If `issued_at` is omitted, the
expiration is from when the token exchange completed.

#### `refresh_token`

(Optional) Token which can be used to get additional access tokens for
the same subject with different scopes. This token should be kept secure
by the client and only sent to the authorization server which issues
bearer tokens. This field will only be set when `offline_token=true` is
provided in the request.

### Example

For this example, the client makes an HTTP GET request to the following URL:

```text
https://auth.docker.io/token?service=registry.docker.io&scope=repository:samalba/my-app:pull,push
```

The token server should first attempt to authenticate the client using any
authentication credentials provided with the request. From Docker 1.11 the
Docker Engine supports both Basic Authentication and OAuth2 for
getting tokens. Docker 1.10 and before, the registry client in the Docker Engine
only supports Basic Authentication. If an attempt to authenticate to the token
server fails, the token server should return a `401 Unauthorized` response
indicating that the provided credentials are invalid.

Whether the token server requires authentication is up to the policy of that
access control provider. Some requests may require authentication to determine
access (such as pushing or pulling a private repository) while others may not
(such as pulling from a public repository).

After authenticating the client (which may simply be an anonymous client if
no attempt was made to authenticate), the token server must next query its
access control list to determine whether the client has the requested scope. In
this example request, if I have authenticated as user `jlhawn`, the token
server will determine what access I have to the repository `samalba/my-app`
hosted by the entity `registry.docker.io`.

Once the token server has determined what access the client has to the
resources requested in the `scope` parameter, it will take the intersection of
the set of requested actions on each resource and the set of actions that the
client has in fact been granted. If the client only has a subset of the
requested access **it must not be considered an error** as it is not the
responsibility of the token server to indicate authorization errors as part of
this workflow.

Continuing with the example request, the token server will find that the
client's set of granted access to the repository is `[pull, push]` which when
intersected with the requested access `[pull, push]` yields an equal set. If
the granted access set was found only to be `[pull]` then the intersected set
would only be `[pull]`. If the client has no access to the repository then the
intersected set would be empty, `[]`.

It is this intersected set of access which is placed in the returned token.

The server then constructs an implementation-specific token with this
intersected set of access, and returns it to the Docker client to use to
authenticate to the audience service (within the indicated window of time):

```text
HTTP/1.1 200 OK
Content-Type: application/json

{"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IlBZWU86VEVXVTpWN0pIOjI2SlY6QVFUWjpMSkMzOlNYVko6WEdIQTozNEYyOjJMQVE6WlJNSzpaN1E2In0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJqbGhhd24iLCJhdWQiOiJyZWdpc3RyeS5kb2NrZXIuY29tIiwiZXhwIjoxNDE1Mzg3MzE1LCJuYmYiOjE0MTUzODcwMTUsImlhdCI6MTQxNTM4NzAxNSwianRpIjoidFlKQ08xYzZjbnl5N2tBbjBjN3JLUGdiVjFIMWJGd3MiLCJhY2Nlc3MiOlt7InR5cGUiOiJyZXBvc2l0b3J5IiwibmFtZSI6InNhbWFsYmEvbXktYXBwIiwiYWN0aW9ucyI6WyJwdXNoIl19XX0.QhflHPfbd6eVF4lM9bwYpFZIV0PfikbyXuLx959ykRTBpe3CYnzs6YBK8FToVb5R47920PVLrh8zuLzdCr9t3w", "expires_in": 3600,"issued_at": "2009-11-10T23:00:00Z"}
```

## Using the Bearer token

Once the client has a token, it will try the registry request again with the
token placed in the HTTP `Authorization` header like so:

```text
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6IkJWM0Q6MkFWWjpVQjVaOktJQVA6SU5QTDo1RU42Ok40SjQ6Nk1XTzpEUktFOkJWUUs6M0ZKTDpQT1RMIn0.eyJpc3MiOiJhdXRoLmRvY2tlci5jb20iLCJzdWIiOiJCQ0NZOk9VNlo6UUVKNTpXTjJDOjJBVkM6WTdZRDpBM0xZOjQ1VVc6NE9HRDpLQUxMOkNOSjU6NUlVTCIsImF1ZCI6InJlZ2lzdHJ5LmRvY2tlci5jb20iLCJleHAiOjE0MTUzODczMTUsIm5iZiI6MTQxNTM4NzAxNSwiaWF0IjoxNDE1Mzg3MDE1LCJqdGkiOiJ0WUpDTzFjNmNueXk3a0FuMGM3cktQZ2JWMUgxYkZ3cyIsInNjb3BlIjoiamxoYXduOnJlcG9zaXRvcnk6c2FtYWxiYS9teS1hcHA6cHVzaCxwdWxsIGpsaGF3bjpuYW1lc3BhY2U6c2FtYWxiYTpwdWxsIn0.Y3zZSwaZPqy4y9oRBVRImZyv3m_S9XDHF1tWwN7mL52C_IiA73SJkWVNsvNqpJIn5h7A2F8biv_S2ppQ1lgkbw
```

This is also described in [Section 2.1 of RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage](https://tools.ietf.org/html/rfc6750#section-2.1)


---

# Supported registry API for Docker Hub

*Sección: Reference*




---

# CLI reference

*Sección: Reference*




---

# Compose file reference

*Sección: Reference*

> **New to Docker Compose?**
>
> Find more information about the [key features and use cases of Docker Compose](../../compose/intro/features-uses.md) or [try the quickstart guide](../../compose/gettingstarted.md).

The Compose Specification is the latest and recommended version of the Compose file format. It helps you define a [Compose file](../../compose/intro/compose-application-model.md) which is used to configure your Docker application’s services, networks, volumes, and more.

Legacy versions 2.x and 3.x of the Compose file format were merged into the Compose Specification. It is implemented in versions 1.27.0 and above (also known as Compose v2) of the Docker Compose CLI.

The Compose Specification on Docker Docs is the Docker Compose implementation. If you wish to implement your own version of the Compose Specification, see the [Compose Specification repository](https://github.com/compose-spec/compose-spec).

Use the following links to navigate key sections of the Compose Specification.

> [!TIP]
>
> Want a better editing experience for Compose files in VS Code?
> Check out the [Docker DX](https://marketplace.visualstudio.com/items?itemName=docker.docker) extension for linting, code navigation, and vulnerability scanning.

{{< grid >}}


---

# Compose Build Specification

*Sección: Reference*

{{% include "compose/build.md" %}}

When `build` is specified as a string, the whole path is used as a
Docker context to execute a Docker build, looking for a canonical
`Dockerfile` at the root of the directory.

When `build` is specified as a detailed structure, build arguments can
be specified, including an alternate `Dockerfile` location.

In both cases, the path can be absolute or relative. If it is relative,
it is resolved from the directory containing your Compose file. If it is
absolute, the path prevents the Compose file from being portable so
Compose displays a warning.

## Using `build` and `image`

When Compose is confronted with both a `build` subsection for a service and an `image` attribute, it follows the rules defined by the [`pull_policy`](services.md#pull_policy) attribute.

If `pull_policy` is missing from the service definition, Compose attempts to pull the image first and then builds from source if the image isn't found in the registry or platform cache.

## Publishing built images

Compose with `build` support offers an option to push built images to a registry. When doing so, it doesn't try to push service images without an `image` attribute. Compose warns you about the missing `image` attribute which prevents images being pushed.

## Illustrative example

The following example illustrates Compose Build Specification concepts with a concrete sample application. The sample is non-normative.

```yaml
services:
  frontend:
    image: example/webapp
    build: ./webapp

  backend:
    image: example/database
    build:
      context: backend
      dockerfile: ../backend.Dockerfile

  custom:
    build: ~/custom
```

When used to build service images from source, the Compose file creates three Docker images:

- `example/webapp`: A Docker image is built using `webapp` sub-directory, within the Compose file's folder, as the Docker build context. Lack of a `Dockerfile` within this folder returns an error.
- `example/database`: A Docker image is built using `backend` sub-directory within the Compose file's folder. `backend.Dockerfile` file is used to define build steps, this file is searched relative to the context path, which means `..` resolves to the Compose file's folder, so `backend.Dockerfile` is a sibling file.
- A Docker image is built using the `custom` directory with the user's `$HOME` as the Docker context. Compose displays a warning about the non-portable path used to build image.

On push, both `example/webapp` and `example/database` Docker images are pushed to the default registry. The `custom` service image is skipped as no `image` attribute is set and Compose displays a warning about this missing attribute.

## Attributes

The `build` subsection defines configuration options that are applied by Compose to build Docker images from source.
`build` can be specified either as a string containing a path to the build context or as a detailed structure:

Using the string syntax, only the build context can be configured as either:

- A relative path to the Compose file's folder. This path must be a directory and must contain a `Dockerfile`

  ```yml
  services:
    webapp:
      build: ./dir
  ```

- A Git repository URL. Git URLs accept context configuration in their fragment section, separated by a colon (`:`).
  The first part represents the reference that Git checks out, and can be either a branch, a tag, or a remote reference.
  The second part represents a subdirectory inside the repository that is used as a build context.

  ```yml
  services:
    webapp:
      build: https://github.com/mycompany/example.git#branch_or_tag:subdirectory
  ```

Alternatively `build` can be an object with fields defined as follows:

### `additional_contexts`

{{< summary-bar feature_name="Build additional contexts" >}}

`additional_contexts` defines a list of named contexts the image builder should use during image build.

`additional_contexts` can be a mapping or a list:

```yml
build:
  context: .
  additional_contexts:
    - resources=/path/to/resources
    - app=docker-image://my-app:latest
    - source=https://github.com/myuser/project.git
```

```yml
build:
  context: .
  additional_contexts:
    resources: /path/to/resources
    app: docker-image://my-app:latest
    source: https://github.com/myuser/project.git
```

When used as a list, the syntax follows the `NAME=VALUE` format, where `VALUE` is a string. Validation beyond that
is the responsibility of the image builder (and is builder specific). Compose supports at least
absolute and relative paths to a directory and Git repository URLs, like [context](#context) does. Other context flavours
must be prefixed to avoid ambiguity with a `type://` prefix.

Compose warns you if the image builder does not support additional contexts and may list
the unused contexts.

Refer to the reference documentation for [`docker buildx build --build-context`](https://github.com/docker/buildx/blob/master/docs/reference/buildx_build.md#-additional-build-contexts---build-context)
for example usage.

`additional_contexts` can also refer to an image built by another service.
This allows a service image to be built using another service image as a base image, and to share
layers between service images.

```yaml
services:
  base:
    build:
      context: .
      dockerfile_inline: |
        FROM alpine
        RUN ...
  my-service:
    build:
      context: .
      dockerfile_inline: |
        FROM base # image built for service base
        RUN ...
      additional_contexts:
        base: service:base
```

### `args`

`args` define build arguments, that is Dockerfile `ARG` values.

Using the following Dockerfile as an example:

```Dockerfile
ARG GIT_COMMIT
RUN echo "Based on commit: $GIT_COMMIT"
```

`args` can be set in the Compose file under the `build` key to define `GIT_COMMIT`. `args` can be set as a mapping or a list:

```yml
build:
  context: .
  args:
    GIT_COMMIT: cdc3b19
```

```yml
build:
  context: .
  args:
    - GIT_COMMIT=cdc3b19
```

Values can be omitted when specifying a build argument, in which case its value at build time must be obtained by user interaction,
otherwise the build argument won't be set when building the Docker image.

```yml
args:
  - GIT_COMMIT
```

### `cache_from`

`cache_from` defines a list of sources the image builder should use for cache resolution.

Cache location syntax follows the global format `[NAME|type=TYPE[,KEY=VALUE]]`. Simple `NAME` is actually a shortcut notation for `type=registry,ref=NAME`.

Compose Build implementations may support custom types, the Compose Specification defines canonical types which must be supported:

- `registry` to retrieve build cache from an OCI image set by key `ref`

```yml
build:
  context: .
  cache_from:
    - alpine:latest
    - type=local,src=path/to/cache
    - type=gha
```

Unsupported caches are ignored and don't prevent you from building images.

### `cache_to`

`cache_to` defines a list of export locations to be used to share build cache with future builds.

```yml
build:
  context: .
  cache_to:
    - user/app:cache
    - type=local,dest=path/to/cache
```

Cache target is defined using the same `type=TYPE[,KEY=VALUE]` syntax defined by [`cache_from`](#cache_from).

Unsupported caches are ignored and don't prevent you from building images.

### `context`

`context` defines either a path to a directory containing a Dockerfile, or a URL to a Git repository.

When the value supplied is a relative path, it is interpreted as relative to the project directory.
Compose warns you about the absolute path used to define the build context as those prevent the Compose file
from being portable.

```yml
build:
  context: ./dir
```

```yml
services:
  webapp:
    build: https://github.com/mycompany/webapp.git
```

If not set explicitly, `context` defaults to project directory (`.`).

### `dockerfile`

`dockerfile` sets an alternate Dockerfile. A relative path is resolved from the build context.
Compose warns you about the absolute path used to define the Dockerfile as it prevents Compose files
from being portable.

When set, `dockerfile_inline` attribute is not allowed and Compose
rejects any Compose file having both set.

```yml
build:
  context: .
  dockerfile: webapp.Dockerfile
```

### `dockerfile_inline`

{{< summary-bar feature_name="Build dockerfile inline" >}}

`dockerfile_inline` defines the Dockerfile content as an inlined string in a Compose file. When set, the `dockerfile`
attribute is not allowed and Compose rejects any Compose file having both set.

Use of YAML multi-line string syntax is recommended to define the Dockerfile content:

```yml
build:
  context: .
  dockerfile_inline: |
    FROM baseimage
    RUN some command
```

### `entitlements`

{{< summary-bar feature_name="Build entitlements" >}}

`entitlements` defines extra privileged entitlements to be allowed during the build.

```yaml
entitlements:
  - network.host
  - security.insecure
```

### `extra_hosts`

`extra_hosts` adds hostname mappings at build-time. Use the same syntax as [`extra_hosts`](services.md#extra_hosts).

```yml
extra_hosts:
  - "somehost=162.242.195.82"
  - "otherhost=50.31.209.229"
  - "myhostv6=::1"
```

IPv6 addresses can be enclosed in square brackets, for example:

```yml
extra_hosts:
  - "myhostv6=[::1]"
```

The separator `=` is preferred, but `:` can also be used. Introduced in Docker Compose version [2.24.1](https://github.com/docker/compose/releases/tag/v2.24.1). For example:

```yml
extra_hosts:
  - "somehost:162.242.195.82"
  - "myhostv6:::1"
```

Compose creates matching entry with the IP address and hostname in the container's network
configuration, which means for Linux `/etc/hosts` will get extra lines:

```text
162.242.195.82  somehost
50.31.209.229   otherhost
::1             myhostv6
```

### `isolation`

`isolation` specifies a build’s container isolation technology. Like [isolation](services.md#isolation), supported values
are platform specific.

### `labels`

`labels` add metadata to the resulting image. `labels` can be set either as an array or a map.

It's recommended that you use reverse-DNS notation to prevent your labels from conflicting with other software.

```yml
build:
  context: .
  labels:
    com.example.description: "Accounting webapp"
    com.example.department: "Finance"
    com.example.label-with-empty-value: ""
```

```yml
build:
  context: .
  labels:
    - "com.example.description=Accounting webapp"
    - "com.example.department=Finance"
    - "com.example.label-with-empty-value"
```

### `network`

Set the networking mode for `RUN` instructions during the build. This is
the same as [`docker build --network`](/reference/cli/docker/buildx/build/#network).
It is not a Compose network from the top-level [`networks`](networks.md) key.

The value is a mode (`default`, `none`, or `host`), not a network name:

```yaml
build:
  context: .
  network: host
```

Use `none` to disable networking during the build:

```yaml
build:
  context: .
  network: none
```

### `no_cache`

`no_cache` disables image builder cache and enforces a full rebuild from source for all image layers. This only
applies to layers declared in the Dockerfile, referenced images can be retrieved from local image store whenever tag
has been updated on registry (see [pull](#pull)).

### `platforms`

`platforms` defines a list of target [platforms](services.md#platform).

```yml
build:
  context: "."
  platforms:
    - "linux/amd64"
    - "linux/arm64"
```

When the `platforms` attribute is omitted, Compose includes the service's platform
in the list of the default build target platforms.

When the `platforms` attribute is defined, Compose includes the service's
platform, otherwise users won't be able to run images they built.

Composes reports an error in the following cases:

- When the list contains multiple platforms but the implementation is incapable of storing multi-platform images.
- When the list contains an unsupported platform.

  ```yml
  build:
    context: "."
    platforms:
      - "linux/amd64"
      - "unsupported/unsupported"
  ```

- When the list is non-empty and does not contain the service's platform.

  ```yml
  services:
    frontend:
      platform: "linux/amd64"
      build:
        context: "."
        platforms:
          - "linux/arm64"
  ```

### `privileged`

{{< summary-bar feature_name="Build privileged" >}}

`privileged` configures the service image to build with elevated privileges. Support and actual impacts are platform specific.

```yml
build:
  context: .
  privileged: true
```

### `provenance`

{{< summary-bar feature_name="Compose provenance" >}}

`provenance` configures the builder to add a [provenance attestation](https://slsa.dev/provenance/v0.2#schema) to the published image.

The value can be either a boolean to enable/disable provenance attestation, or a key=value string to set provenance configuration. You can
use this to select the level of detail to be included in the provenance attestation by setting the `mode` parameter.

```yaml
build:
  context: .
  provenance: true
```

```yaml
build:
  context: .
  provenance: mode=max
```

### `pull`

`pull` requires the image builder to pull referenced images (`FROM` Dockerfile directive), even if those are already
available in the local image store.

### `sbom`

{{< summary-bar feature_name="Compose sbom" >}}

`sbom` configures the builder to add a [provenance attestation](https://slsa.dev/provenance/v0.2#schema) to the published image.
The value can be either a boolean to enable/disable sbom attestation, or a key=value string to set SBOM generator configuration. This let you
select an alternative SBOM generator image (see https://github.com/moby/buildkit/blob/master/docs/attestations/sbom-protocol.md)

```yaml
build:
  context: .
  sbom: true
```

```yaml
build:
  context: .
  sbom: generator=docker/scout-sbom-indexer:latest # Use an alternative SBOM generator
```

### `secrets`

`secrets` grants access to sensitive data defined by [secrets](services.md#secrets) on a per-service build basis. Two
different syntax variants are supported: the short syntax and the long syntax.

Compose reports an error if the secret isn't defined in the
[`secrets`](secrets.md) section of this Compose file.

#### Short syntax

The short syntax variant only specifies the secret name. This grants the
container access to the secret and mounts it as read-only to `/run/secrets/<secret_name>`
within the container. The source name and destination mountpoint are both set
to the secret name.

The following example uses the short syntax to grant the build of the `frontend` service
access to the `server-certificate` secret. The value of `server-certificate` is set
to the contents of the file `./server.cert`.

```yml
services:
  frontend:
    build:
      context: .
      secrets:
        - server-certificate
secrets:
  server-certificate:
    file: ./server.cert
```

#### Long syntax

The long syntax provides more granularity in how the secret is created within
the service's containers.

- `source`: The name of the secret as it exists on the platform.
- `target`: The ID of the secret as declared in the Dockerfile. Defaults to `source` if not specified.
- `uid` and `gid`: The numeric uid or gid that owns the file within
  `/run/secrets/` in the service's task containers. Default value is `USER`.
- `mode`: The [permissions](https://wintelguy.com/permissions-calc.pl) for the file to be mounted in `/run/secrets/`
  in the service's task containers, in octal notation.
  Default value is world-readable permissions (mode `0444`).
  The writable bit must be ignored if set. The executable bit may be set.

The following example sets the name of the `server-certificate` secret file to `server.crt`
within the container, sets the mode to `0440` (group-readable) and sets the user and group
to `103`. The value of `server-certificate` secret is provided by the platform through a lookup and
the secret lifecycle not directly managed by Compose.

```yml
services:
  frontend:
    build:
      context: .
      secrets:
        - source: server-certificate
          target: cert # secret ID in Dockerfile
          uid: "103"
          gid: "103"
          mode: 0440
secrets:
  server-certificate:
    external: true
```

```dockerfile
# Dockerfile
FROM nginx
RUN --mount=type=secret,id=cert,required=true,target=/root/cert ...
```

Service builds may be granted access to multiple secrets. Long and short syntax for secrets may be used in the
same Compose file. Defining a secret in the top-level `secrets` must not imply granting any service build access to it.
Such grant must be explicit within service specification as [secrets](services.md#secrets) service element.

### `ssh`

`ssh` defines SSH authentications that the image builder should use during image build (e.g., cloning private repository).

`ssh` property syntax can be either:

- `default`: Let the builder connect to the SSH-agent.
- `ID=path`: A key/value definition of an ID and the associated path. It can be either a [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) file, or path to ssh-agent socket.

```yaml
build:
  context: .
  ssh:
    - default # mount the default SSH agent
```

or

```yaml
build:
  context: .
  ssh: ["default"] # mount the default SSH agent
```

Using a custom id `myproject` with path to a local SSH key:

```yaml
build:
  context: .
  ssh:
    - myproject=~/.ssh/myproject.pem
```

The image builder can then rely on this to mount the SSH key during build.

For illustration, [SSH mounts](https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/reference.md#run---mounttypessh) can be used to mount the SSH key set by ID and access a secured resource:

```console
RUN --mount=type=ssh,id=myproject git clone ...
```

### `shm_size`

`shm_size` sets the size of the shared memory (`/dev/shm` partition on Linux) allocated for building Docker images. Specify
as an integer value representing the number of bytes or as a string expressing a [byte value](extension.md#specifying-byte-values).

```yml
build:
  context: .
  shm_size: "2gb"
```

```yaml
build:
  context: .
  shm_size: 10000000
```

### `tags`

`tags` defines a list of tag mappings that must be associated to the build image. This list comes in addition to
the `image` [property defined in the service section](services.md#image)

```yml
tags:
  - "myimage:mytag"
  - "registry/username/myrepos:my-other-tag"
```

### `target`

`target` defines the stage to build as defined inside a multi-stage `Dockerfile`.

```yml
build:
  context: .
  target: prod
```

### `ulimits`

{{< summary-bar feature_name="Build ulimits" >}}

`ulimits` overrides the default `ulimits` for a container. It's specified either as an integer for a single limit
or as mapping for soft/hard limits.

```yml
services:
  frontend:
    build:
      context: .
      ulimits:
        nproc: 65535
        nofile:
          soft: 20000
          hard: 40000
```


---

# Configs top-level element

*Sección: Reference*

{{% include "compose/configs.md" %}}

Services can only access configs when explicitly granted by a [`configs`](services.md#configs) attribute within the `services` top-level element.

By default, the config:
- Is owned by the user running the container command but can be overridden by service configuration.
- Has world-readable permissions (mode 0444), unless the service is configured to override this.

The top-level `configs` declaration defines or references configuration data that is granted to services in your Compose application. The source of the config is either `file`, `environment`, `content`, or `external`.

- `file`: The config is created with the contents of the file at the specified path.
- `environment`: The config content is created with the value of an environment variable. Introduced in Docker Compose version [2.23.1](https://github.com/docker/compose/releases/tag/v2.23.1).
- `content`: The content is created with the inlined value. Introduced in Docker Compose version [2.23.1](https://github.com/docker/compose/releases/tag/v2.23.1).
- `external`: If set to true, `external` specifies that this config has already been created. Compose does not
  attempt to create it, and if it does not exist, an error occurs.
- `name`: The name of the config object in the container engine to look up. This field can be used to
  reference configs that contain special characters. The name is used as is
  and will **not** be scoped with the project name.

## Example 1

`<project_name>_http_config` is created when the application is deployed,
by registering the content of the `httpd.conf` as the configuration data.

```yml
configs:
  http_config:
    file: ./httpd.conf
```

Alternatively, `http_config` can be declared as external. Compose looks up `http_config` to expose the configuration data to relevant services.

```yml
configs:
  http_config:
    external: true
```

## Example 2

External configs lookup can also use a distinct key by specifying a `name`.

The following
example modifies the previous one to look up a config using the parameter `HTTP_CONFIG_KEY`. The actual lookup key is set at deployment time by the [interpolation](interpolation.md) of
variables, but exposed to containers as hard-coded ID `http_config`.

```yml
configs:
  http_config:
    external: true
    name: "${HTTP_CONFIG_KEY}"
```

## Example 3

`<project_name>_app_config` is created when the application is deployed,
by registering the inlined content as the configuration data. This means Compose infers variables when creating the config, which allows you to
adjust content according to service configuration:

```yml
configs:
  app_config:
    content: |
      debug=${DEBUG}
      spring.application.admin.enabled=${DEBUG}
      spring.application.name=${COMPOSE_PROJECT_NAME}
```

## Example 4

`<project_name>_simple_config` is created when the application is deployed,
using the value of an environment variable as the configuration data. This is useful for simple configuration values that don’t require interpolation:

```yml
configs:
  simple_config:
    environment: "SIMPLE_CONFIG_VALUE"
```

If `external` is set to `true`, all other attributes apart from `name` are irrelevant. If Compose detects any other attribute, it rejects the Compose file as invalid.


---

# Compose Deploy Specification

*Sección: Reference*

{{% include "compose/deploy.md" %}}

## Attributes

### `endpoint_mode`

`endpoint_mode` specifies a service discovery method for external clients connecting to a service. The Compose Deploy Specification defines two canonical values:

* `endpoint_mode: vip`: Assigns the service a virtual IP (VIP) that acts as the front end for clients to reach the service
  on a network. Platform routes requests between the client and nodes running the service, without client knowledge of how
  many nodes are participating in the service or their IP addresses or ports.

* `endpoint_mode: dnsrr`: Platform sets up DNS entries for the service such that a DNS query for the service name returns a
  list of IP addresses (DNS round-robin), and the client connects directly to one of these.

```yml
services:
  frontend:
    image: example/webapp
    ports:
      - "8080:80"
    deploy:
      mode: replicated
      replicas: 2
      endpoint_mode: vip
```

### `labels`

`labels` specifies metadata for the service. These labels are only set on the service and not on any containers for the service.
This assumes the platform has some native concept of "service" that can match the Compose application model.

```yml
services:
  frontend:
    image: example/webapp
    deploy:
      labels:
        com.example.description: "This label will appear on the web service"
```

### `mode`

`mode` defines the replication model used to run a service or job. Options include:

- `global`: Ensures exactly one task continuously runs per physical node until stopped.
- `replicated`: Continuously runs a specified number of tasks across nodes until stopped (default).
- `replicated-job`: Executes a defined number of tasks until a completion state (exits with code 0)'.
   - Total tasks are determined by `replicas`. 
   - Concurrency can be limited using the `max-concurrent` option (CLI only).
- `global-job`: Executes one task per physical node with a completion state (exits with code 0).
   - Automatically runs on new nodes as they are added.

```yml
services:
  frontend:
    image: example/webapp
    deploy:
      mode: global

  batch-job:
    image: example/processor
    deploy:
      mode: replicated-job
      replicas: 5

  maintenance:
    image: example/updater
    deploy:
      mode: global-job
```

> [!NOTE] 
> - Job modes (`replicated-job` and `global-job`) are designed for tasks that complete and exit with code 0.
> - Completed tasks remain until explicitly removed.
> - Options like `max-concurrent` for controlling concurrency are supported only via the CLI and are not available in Compose.

For more detailed information about job options and behavior, see the [Docker CLI documentation](/reference/cli/docker/service/create/#running-as-a-job)

### `placement`

`placement` specifies constraints and preferences for the platform to select a physical node to run service containers.

#### `constraints`

`constraints` defines a required property the platform's node must fulfill to run the service container. For a further example, see the [CLI reference docs](/reference/cli/docker/service/create/#constraint).

```yml
deploy:
  placement:
    constraints:
      - node.labels.disktype==ssd
```

#### `preferences`

`preferences` defines a strategy (currently `spread` is the only supported strategy) to spread tasks evenly 
over the values of the datacenter node label. For a further example, see the [CLI reference docs](/reference/cli/docker/service/create/#placement-pref)

```yml
deploy:
  placement:
    preferences:
      - spread: node.labels.zone
```

### `replicas`

If the service is `replicated` (which is the default), `replicas` specifies the number of containers that should be
running at any given time.

```yml
services:
  frontend:
    image: example/webapp
    deploy:
      mode: replicated
      replicas: 6
```

### `resources`

`resources` configures physical resource constraints for container to run on platform. Those constraints can be configured
as:

- `limits`: The platform must prevent the container from allocating more resources.
- `reservations`: The platform must guarantee the container can allocate at least the configured amount.

```yml
services:
  frontend:
    image: example/webapp
    deploy:
      resources:
        limits:
          cpus: '0.50'
          memory: 50M
          pids: 1
        reservations:
          cpus: '0.25'
          memory: 20M
```

#### `cpus`

`cpus` configures a limit or reservation for how much of the available CPU resources, as number of cores, a container can use.

#### `memory`

`memory` configures a limit or reservation on the amount of memory a container can allocate, set as a string expressing a [byte value](extension.md#specifying-byte-values).

#### `pids`

`pids` tunes a container’s PIDs limit, set as an integer.

#### `devices`

`devices` configures reservations of the devices a container can use. It contains a list of reservations, each set as an object with the following parameters: `capabilities`, `driver`, `count`, `device_ids` and `options`.

Devices are reserved using a list of capabilities, making `capabilities` the only required field. A device must satisfy all the requested capabilities for a successful reservation.

##### `capabilities`

`capabilities` are set as a list of strings, expressing both generic and driver specific capabilities.
The following generic capabilities are recognized today:

- `gpu`: Graphics accelerator
- `tpu`: AI accelerator

To avoid name clashes, driver specific capabilities must be prefixed with the driver name.
For example, reserving an NVIDIA CUDA-enabled accelerator might look like this:

```yml
deploy:
  resources:
    reservations:
      devices:
        - capabilities: ["nvidia-compute"]
```

##### `driver`

A different driver for the reserved device(s) can be requested using `driver` field. The value is specified as a string.

```yml
deploy:
  resources:
    reservations:
      devices:
        - capabilities: ["nvidia-compute"]
          driver: nvidia
```

##### `count`

If `count` is set to `all` or not specified, Compose reserves all devices that satisfy the requested capabilities. Otherwise, Compose reserves at least the number of devices specified. The value is specified as an integer.

```yml
deploy:
  resources:
    reservations:
      devices:
        - capabilities: ["tpu"]
          count: 2
```

`count` and `device_ids` fields are exclusive. Compose returns an error if both are specified.

##### `device_ids`

If `device_ids` is set, Compose reserves devices with the specified IDs provided they satisfy the requested capabilities. The value is specified as a list of strings.

```yml
deploy:
  resources:
    reservations:
      devices:
        - capabilities: ["gpu"]
          device_ids: ["GPU-f123d1c9-26bb-df9b-1c23-4a731f61d8c7"]
```

`count` and `device_ids` fields are exclusive. Compose returns an error if both are specified.

##### `options`

Driver specific options can be set with `options` as key-value pairs.

```yml
deploy:
  resources:
    reservations:
      devices:
        - capabilities: ["gpu"]
          driver: gpuvendor
          options:
            virtualization: false
```

### `restart_policy`

`restart_policy` configures if and how to restart containers when they exit. If `restart_policy` is not set, Compose considers the `restart` field set by the service configuration.

- `condition`. When set to:
  - `none`, containers are not automatically restarted regardless of the exit status.
  - `on-failure`, the container is restarted if it exits due to an error, which manifests as a non-zero exit code.
  - `any` (default), containers are restarted regardless of the exit status. 
- `delay`: How long to wait between restart attempts, specified as a [duration](extension.md#specifying-durations). The default is 0, meaning restart attempts can occur immediately.
- `max_attempts`: The maximum number of failed restart attempts allowed before giving up. (Default: unlimited retries.)
A failed attempt only counts toward `max_attempts` if the container does not successfully restart within the time defined by `window`.
For example, if `max_attempts` is set to `2` and the container fails to restart within the window on the first try, Compose continues retrying until two such failed attempts occur, even if that means trying more than twice.
- `window`: The amount of time to wait after a restart to determine whether it was successful, specified as a [duration](extension.md#specifying-durations) (default: the result is evaluated immediately after the restart).

```yml
deploy:
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
    window: 120s
```

### `rollback_config`

`rollback_config` configures how the service should be rolled back in case of a failing update.

- `parallelism`: The number of containers to rollback at a time. If set to 0, all containers rollback simultaneously.
- `delay`: The time to wait between each container group's rollback (default 0s).
- `failure_action`: What to do if a rollback fails. One of `continue` or `pause` (default `pause`)
- `monitor`: Duration after each task update to monitor for failure `(ns|us|ms|s|m|h)` (default 0s).
- `max_failure_ratio`: Failure rate to tolerate during a rollback (default 0).
- `order`: Order of operations during rollbacks. One of `stop-first` (old task is stopped before starting new one),
   or `start-first` (new task is started first, and the running tasks briefly overlap) (default `stop-first`).

### `update_config`

`update_config` configures how the service should be updated. Useful for configuring rolling updates.

- `parallelism`: The number of containers to update at a time.
- `delay`: The time to wait between updating a group of containers.
- `failure_action`: What to do if an update fails. One of `continue`, `rollback`, or `pause` (default: `pause`).
- `monitor`: Duration after each task update to monitor for failure `(ns|us|ms|s|m|h)` (default 0s).
- `max_failure_ratio`: Failure rate to tolerate during an update.
- `order`: Order of operations during updates. One of `stop-first` (old task is stopped before starting new one),
   or `start-first` (new task is started first, and the running tasks briefly overlap) (default `stop-first`).

```yml
deploy:
  update_config:
    parallelism: 2
    delay: 10s
    order: stop-first
```


---

# Compose Develop Specification

*Sección: Reference*

> [!NOTE] 
>
> Develop is an optional part of the Compose Specification. It is available with Docker Compose version 2.22.0 and later.

{{% include "compose/services-develop.md" %}}

This page defines how Compose behaves to efficiently assist you and defines the development constraints and workflows set by Compose. Only a subset of Compose file services may require a `develop` subsection.

## Illustrative example

```yaml
services:
  frontend:
    image: example/webapp
    build: ./webapp
    develop:
      watch: 
        # sync static content
        - path: ./webapp/html
          action: sync
          target: /var/www
          ignore:
            - node_modules/

  backend:
    image: example/backend
    build: ./backend
    develop:
      watch: 
        # rebuild image and recreate service
        - path: ./backend/src
          action: rebuild
```

## Attributes

The `develop` subsection defines configuration options that are applied by Compose to assist you during development of a service with optimized workflows.

### `watch`

The `watch` attribute defines a list of rules that control automatic service updates based on local file changes. `watch` is a sequence, each individual item in the sequence defines a rule to be applied by 
Compose to monitor source code for changes. For more information, see [Use Compose Watch](../../compose/how-tos/file-watch.md).

#### `action`

`action` defines the action to take when changes are detected. If `action` is set to:

- `rebuild`: Compose rebuilds the service image based on the `build` section and recreates the service with the updated image.
- `restart`: Compose restarts the service container. Available with Docker Compose version 2.32.0 and later.
- `sync`: Compose keeps the existing service container(s) running, but synchronizes source files with container content according to the `target` attribute.
- `sync+restart`: Compose synchronizes source files with container content according to the `target` attribute, and then restarts the container. Available with Docker Compose version 2.23.0 and later.
- `sync+exec`: Compose synchronizes source files with container content according to the `target` attribute, and then executes a command inside the container. Available with Docker Compose version 2.32.0 and later.

#### `exec`

{{< summary-bar feature_name="Compose exec" >}}

`exec` is only relevant when `action` is set to `sync+exec`. Like [service hooks](services.md#post_start), `exec` is used to define the command to be run inside the container once it has started.

- `command`: Specifies the command to run once the container starts. This attribute is required, and you can choose to use either the shell form or the exec form.
- `user`: The user to run the command. If not set, the command is run with the same user as the main service command.
- `privileged`: Lets the command run with privileged access.
- `working_dir`: The working directory in which to run the command. If not set, it is run in the same working directory as the main service command.
- `environment`: Sets the environment variables to run the command. While the command inherits the environment variables defined for the service’s main command, this section lets you add new variables or override existing ones.

```yaml
services:
  frontend:
    image: ...
    develop:
      watch: 
        # sync content then run command to reload service without interruption
        - path: ./etc/config
          action: sync+exec
          target: /etc/config/
          exec:
            command: app reload
```

#### `ignore`

The `ignore` attribute is used to define a list of patterns for paths to be ignored. Any updated file
that matches a pattern, or belongs to a folder that matches a pattern, won't trigger services to be re-created. 
The syntax is the same as `.dockerignore` file: 

- `*` matches 0 or more characters in a filename. 
- `?` matches a single character in filename. 
- `*/*` matches two nested folders with arbitrary names
- `**` matches an arbitrary number of nested folders

If the build context includes a `.dockerignore` file, the patterns in this file is loaded as implicit content
for the `ignores` file, and values set in the Compose model are appended.

#### `include`

It is sometimes easier to select files to be watched instead of declaring those that shouldn't be watched with `ignore`.

The `include` attribute is used to define a pattern, or a list of patterns, for paths to be considered for watching.
Only files that match these patterns will be considered when applying a watch rule. The syntax is the same as `ignore`.

```yaml
services:
  backend:
    image: example/backend
    develop:
      watch: 
        # rebuild image and recreate service
        - path: ./src
          include: "*.go"  
          action: rebuild
```

> [!NOTE]
> 
> In many cases `include` patterns start with a wildcard (`*`) character. This has special meaning in YAML syntax
> to define an [alias node](https://yaml.org/spec/1.2.2/#alias-nodes) so you have to wrap pattern expression with quotes.

#### `initial_sync`

When using `sync+x` actions, it can be useful to ensure that files inside containers are up to date at the start of a new watch session.

The `initial_sync` attribute instructs the Compose runtime, if containers for the service already exist, to check that the files from the path attribute are in sync within the service containers.

#### `path`

`path` attribute defines the path to source code (relative to the project directory) to monitor for changes. Updates to any file
inside the path, which doesn't match any `ignore` rule, triggers the configured action.

#### `target`

`target` attribute only applies when `action` is configured for `sync`. Files within `path` that have changes are synchronized with the container's filesystem, so that the latter is always running with up-to-date content.


---

# Extensions

*Sección: Reference*

{{% include "compose/extension.md" %}}

Extensions can also be used with [anchors and aliases](fragments.md).

They also can be used within any structure in a Compose file where user-defined keys are not expected. 
Compose uses those to enable experimental features, the same way browsers add support for [custom CSS features](https://www.w3.org/TR/2011/REC-CSS2-20110607/syndata.html#vendor-keywords)

## Example 1

```yml
x-custom:
  foo:
    - bar
    - zot

services:
  webapp:
    image: example/webapp
    x-foo: bar
```

```yml
service:
  backend:
    deploy:
      placement:
        x-aws-role: "arn:aws:iam::XXXXXXXXXXXX:role/foo"
        x-aws-region: "eu-west-3"
        x-azure-region: "france-central"
```

## Example 2

```yml
x-env: &env
  environment:
    - CONFIG_KEY
    - EXAMPLE_KEY
 
services:
  first:
    <<: *env
    image: my-image:latest
  second:
    <<: *env
    image: another-image:latest
```

In this example, the environment variables do not belong to either of the services. They’ve been lifted out completely into the `x-env` extension field.
This defines a new node which contains the environment field. The `&env` YAML anchor is used so both services can reference the extension field’s value as `*env`.

## Example 3

```yml
x-function: &function
 labels:
   function: "true"
 depends_on:
   - gateway
 networks:
   - functions
 deploy:
   placement:
     constraints:
       - 'node.platform.os == linux'
services:
 # Node.js gives OS info about the node (Host)
 nodeinfo:
   <<: *function
   image: functions/nodeinfo:latest
   environment:
     no_proxy: "gateway"
     https_proxy: $https_proxy
 # Uses `cat` to echo back response, fastest function to execute.
 echoit:
   <<: *function
   image: functions/alpine:health
   environment:
     fprocess: "cat"
     no_proxy: "gateway"
     https_proxy: $https_proxy
```

The `nodeinfo` and `echoit` services both include the `x-function` extension via the `&function` anchor, then set their specific image and environment. 

## Example 4 

Using [YAML merge](https://yaml.org/type/merge.html) it is also possible to use multiple extensions and share
and override additional attributes for specific needs:

```yml
x-environment: &default-environment
  FOO: BAR
  ZOT: QUIX
x-keys: &keys
  KEY: VALUE
services:
  frontend:
    image: example/webapp
    environment: 
      << : [*default-environment, *keys]
      YET_ANOTHER: VARIABLE
```

> [!NOTE]
>
> [YAML merge](https://yaml.org/type/merge.html) only applies to mappings, and can't be used with sequences. 
>
> In the example above, the environment variables are declared using the `FOO: BAR` mapping syntax, while the sequence syntax `- FOO=BAR` is only valid when no fragments are involved.

## Informative historical notes

This section is informative. At the time of writing, the following prefixes are known to exist:

| Prefix     | Vendor/Organization |
| ---------- | ------------------- |
| docker     | Docker              |
| kubernetes | Kubernetes          |

## Specifying byte values

Values express a byte value as a string in `{amount}{byte unit}` format:
The supported units are `b` (bytes), `k` or `kb` (kilo bytes), `m` or `mb` (mega bytes) and `g` or `gb` (giga bytes).

```text
    2b
    1024kb
    2048k
    300m
    1gb
```

## Specifying durations

Values express a duration as a string in the form of `{value}{unit}`.
The supported units are `us` (microseconds), `ms` (milliseconds), `s` (seconds), `m` (minutes) and `h` (hours).
Values can combine multiple values without separator.

```text
  10ms
  40s
  1m30s
  1h5m30s20ms
```


---

# Fragments

*Sección: Reference*

{{% include "compose/fragments.md" %}}

Anchors are created using the `&` sign. The sign is followed by an alias name. You can use this alias with the `*` sign later to reference the value following the anchor. Make sure there is no space between the `&` and the `*` characters and the following alias name. 

You can use more than one anchor and alias in a single Compose file.

## Example 1

```yml
volumes:
  db-data: &default-volume
    driver: default
  metrics: *default-volume
```

In the example above, a `default-volume` anchor is created based on the `db-data` volume. It is later reused by the alias `*default-volume` to define the `metrics` volume. 

Anchor resolution takes place before [variables interpolation](interpolation.md), so variables can't be used to set anchors or aliases.

## Example 2

```yml
services:
  first:
    image: my-image:latest
    environment: &env
      - CONFIG_KEY
      - EXAMPLE_KEY
      - DEMO_VAR
  second:
    image: another-image:latest
    environment: *env
```

If you have an anchor that you want to use in more than one service, use it in conjunction with an [extension](extension.md) to make your Compose file easier to maintain.

## Example 3

You may want to partially override values. Compose follows the rule outlined by [YAML merge type](https://yaml.org/type/merge.html). 

In the following example, `metrics` volume specification uses alias
to avoid repetition but overrides `name` attribute:

```yml
services:
  backend:
    image: example/database
    volumes:
      - db-data
      - metrics
volumes:
  db-data: &default-volume
    driver: default
    name: "data"
  metrics:
    <<: *default-volume
    name: "metrics"
```

## Example 4

You can also extend the anchor to add additional values.

```yml
services:
  first:
    image: my-image:latest
    environment: &env
      FOO: BAR
      ZOT: QUIX
  second:
    image: another-image:latest
    environment:
      <<: *env
      YET_ANOTHER: VARIABLE
```

> [!NOTE]
>
> [YAML merge](https://yaml.org/type/merge.html) only applies to mappings, and can't be used with sequences. 

In example above, the environment variables must be declared using the `FOO: BAR` mapping syntax, while the sequence syntax `- FOO=BAR` is only valid when no fragments are involved.


---

# Use include to modularize Compose files

*Sección: Reference*

{{< summary-bar feature_name="Composefile include" >}}

You can reuse and modularize Docker Compose configurations by including other Compose files. This is useful if:
- You want to reuse other Compose files.
- You need to factor out parts of your application model into separate Compose files so they can be managed separately or shared with others.
- Teams need to maintain a Compose file with only necessary complexity for the limited amount of resources it has to declare for its own sub-domain within a larger deployment.

The `include` top-level section is used to define the dependency on another Compose application, or sub-domain.
Each path listed in the `include` section is loaded as an individual Compose application model, with its own project directory, in order to resolve relative paths.

Once the included Compose application is loaded, all resource definitions are copied into the
current Compose application model. Compose displays a warning if resource names conflict and doesn't
try to merge them. To enforce this, `include` is evaluated after the Compose file(s) selected
to define the Compose application model have been parsed and merged, so that conflicts
between Compose files are detected.

`include` applies recursively so an included Compose file which declares its own `include` section triggers those other files to be included as well.

Any volumes, networks, or other resources pulled in from the included Compose file can be used by the current Compose application for cross-service references. For example:

```yaml
include:
  - my-compose-include.yaml  #with serviceB declared
services:
  serviceA:
    build: .
    depends_on:
      - serviceB #use serviceB directly as if it was declared in this Compose file
```

Compose also supports the use of interpolated variables with `include`. It's recommended that you [specify mandatory variables](interpolation.md). For example:

```text
include:
  -${INCLUDE_PATH:?FOO}/compose.yaml
```

## Short syntax

The short syntax only defines paths to other Compose files. The file is loaded with the parent
folder as the project directory, and an optional `.env` file that is loaded to define any variables' default values
by interpolation. The local project's environment can override those values.

```yaml
include:
  - ../commons/compose.yaml
  - ../another_domain/compose.yaml

services:
  webapp:
    depends_on:
      - included-service # defined by another_domain
```

In the previous example, both `../commons/compose.yaml` and
`../another_domain/compose.yaml` are loaded as individual Compose projects. Relative paths
in Compose files being referred by `include` are resolved relative to their own Compose
file path, not based on the local project's directory. Variables are interpolated using values set in the optional
`.env` file in same folder and are overridden by the local project's environment.

## Long syntax

The long syntax offers more control over the sub-project parsing:

```yaml
include:
   - path: ../commons/compose.yaml
     project_directory: ..
     env_file: ../another/.env
```

### `path`

`path` is required and defines the location of the Compose file(s) to be parsed and included into the
local Compose model.

`path` can be set as:

- A string: When using a single Compose file.
- A list of strings: When multiple Compose files need to be [merged together](merge.md) to define the Compose model for the local application.

```yaml
include:
   - path:
       - ../commons/compose.yaml
       - ./commons-override.yaml
```

### `project_directory`

`project_directory` defines a base path to resolve relative paths set in the Compose file. It defaults to
the directory of the included Compose file.

### `env_file`

`env_file` defines an environment file(s) to use to define default values when interpolating variables
in the Compose file being parsed. It defaults to `.env` file in the `project_directory` for the Compose
file being parsed.

`env_file` can be set to either a string or a list of strings when multiple environment files need to be merged
to define a project environment.

```yaml
include:
   - path: ../another/compose.yaml
     env_file:
       - ../another/.env
       - ../another/dev.env
```

The local project's environment has precedence over the values set by the Compose file, so that the local project can
override values for customization.

## Additional resources

For more information on using `include`, see [Working with multiple Compose files](../../compose/how-tos/multiple-compose-files/index.md)


---

# Interpolation

*Sección: Reference*

{{% include "compose/interpolation.md" %}}

For braced expressions, the following formats are supported:
- Direct substitution
  - `${VAR}` -> value of `VAR`
- Default value
  - `${VAR:-default}` -> value of `VAR` if set and non-empty, otherwise `default`
  - `${VAR-default}` -> value of `VAR` if set, otherwise `default`
- Required value
  - `${VAR:?error}` -> value of `VAR` if set and non-empty, otherwise exit with error
  - `${VAR?error}` -> value of `VAR` if set, otherwise exit with error
- Alternative value
  - `${VAR:+replacement}` -> `replacement` if `VAR` is set and non-empty, otherwise empty
  - `${VAR+replacement}` -> `replacement` if `VAR` is set, otherwise empty

Interpolation can also be nested:

- `${VARIABLE:-${FOO}}`
- `${VARIABLE?$FOO}`
- `${VARIABLE:-${FOO:-default}}`

Other extended shell-style features, such as `${VARIABLE/foo/bar}`, are not
supported by Compose.

Compose processes any string following a `$` sign as long as it makes it
a valid variable definition - either an alphanumeric name (`[_a-zA-Z][_a-zA-Z0-9]*`)
or a braced string starting with `${`. In other circumstances, it will be preserved without attempting to interpolate a value.

You can use a `$$` (double-dollar sign) when your configuration needs a literal
dollar sign. This also prevents Compose from interpolating a value, so a `$$`
allows you to refer to environment variables that you don't want processed by
Compose.

```yml
web:
  build: .
  command: "$$VAR_NOT_INTERPOLATED_BY_COMPOSE"
```

If Compose can't resolve a substituted variable and no default value is defined, it displays a warning and substitutes the variable with an empty string.

As any values in a Compose file can be interpolated with variable substitution, including compact string notation
for complex elements, interpolation is applied before a merge on a per-file basis.

Interpolation applies only to YAML values, not to keys. For the few places where keys are actually arbitrary
user-defined strings, such as [labels](services.md#labels) or [environment](services.md#environment), an alternate equal sign syntax
must be used for interpolation to apply. For example:

```yml
services:
  foo:
    labels:
      "$VAR_NOT_INTERPOLATED_BY_COMPOSE": "BAR"
```

```yml
services:
  foo:
    labels:
      - "$VAR_INTERPOLATED_BY_COMPOSE=BAR"
```


---

# Legacy versions

*Sección: Reference*

The legacy versions of the Compose file reference has moved to the [V1 branch of the Compose repository](https://github.com/docker/compose/tree/v1/docs). They are no longer being actively maintained. 

The latest and recommended version of the Compose file format is defined by the [Compose Specification](index.md). This format merges the 2.x and 3.x versions and is implemented by **Compose 1.27.0+**. For more information, see the[History and development of Docker Compose](../../compose/intro/history.md).


---

# Merge Compose files

*Sección: Reference*

{{% include "compose/merge.md" %}}

These rules are outlined below. 

## Mapping

A YAML `mapping` gets merged by adding missing entries and merging the conflicting ones.

Merging the following example YAML trees:

```yaml
services:
  foo:
    key1: value1
    key2: value2
```

```yaml
services:
  foo:
    key2: VALUE
    key3: value3
```

Results in a Compose application model equivalent to the YAML tree:

```yaml
services:
  foo:
    key1: value1
    key2: VALUE
    key3: value3
```

## Sequence

A YAML `sequence` is merged by appending values from the overriding Compose file to the previous one.

Merging the following example YAML trees:

```yaml
services:
  foo:
    DNS:
      - 1.1.1.1
```

```yaml
services:
  foo:
    DNS: 
      - 8.8.8.8
```

Results in a Compose application model equivalent to the YAML tree:

```yaml
services:
  foo:
    DNS:
      - 1.1.1.1
      - 8.8.8.8
```

## Exceptions

### Shell commands

When merging Compose files that use the services attributes [command](services.md#command), [entrypoint](services.md#entrypoint) and [healthcheck: `test`](services.md#healthcheck), the value is overridden by the latest Compose file, and not appended.

Merging the following example YAML trees:

```yaml
services:
  foo:
    command: ["echo", "foo"]
```

```yaml
services:
  foo:
    command: ["echo", "bar"]
```

Results in a Compose application model equivalent to the YAML tree:

```yaml
services:
  foo:
    command: ["echo", "bar"]
```

### Unique resources

Applies to the [ports](services.md#ports), [volumes](services.md#volumes), [secrets](services.md#secrets) and [configs](services.md#configs) services attributes.
While these types are modeled in a Compose file as a sequence, they have special uniqueness requirements:

| Attribute   | Unique key               |
|-------------|--------------------------|
| volumes     |  target                  |
| secrets     |  target                  |
| configs     |  target                  |
| ports       |  {ip, target, published, protocol}   |

When merging Compose files, Compose appends new entries that do not violate a uniqueness constraint and merge entries that share a unique key.

Merging the following example YAML trees:

```yaml
services:
  foo:
    volumes:
      - foo:/work
```

```yaml
services:
  foo:
    volumes:
      - bar:/work
```

Results in a Compose application model equivalent to the YAML tree:

```yaml
services:
  foo:
    volumes:
      - bar:/work
```

### Reset value

In addition to the previously described mechanism, an override Compose file can also be used to remove elements from your application model.
For this purpose, the custom [YAML tag](https://yaml.org/spec/1.2.2/#24-tags) `!reset` can be set to
override a value set by the overridden Compose file. A valid value for attribute must be provided,
but will be ignored and target attribute will be set with type's default value or `null`. 

For readability, it is recommended to explicitly set the attribute value to the null (`null`) or empty
array `[]` (with `!reset null` or `!reset []`) so that it is clear that resulting attribute will be
cleared.

A base `compose.yaml` file:

```yaml
services:
  app:
    image: myapp
    ports:
      - "8080:80" 
    environment:
      FOO: BAR           
```

And a `compose.override.yaml` file:

```yaml
services:
  app:
    image: myapp
    ports: !reset []
    environment:
      FOO: !reset null
```

Results in:

```yaml
services:
  app:
    image: myapp
```

### Replace value

{{< summary-bar feature_name="Compose replace file" >}}

While `!reset` can be used to remove a declaration from a Compose file using an override file, `!override` allows you
to fully replace an attribute, bypassing the standard merge rules. A typical example is to fully replace a resource definition, to rely on a distinct model but using the same name.

A base `compose.yaml` file:

```yaml
services:
  app:
    image: myapp
    ports:
      - "8080:80"
```

To remove the original port, but expose a new one, the following override file is used:

```yaml
services:
  app:
    ports: !override
      - "8443:443" 
```

This results in: 

```yaml
services:
  app:
    image: myapp
    ports:
      - "8443:443" 
```

If `!override` had not been used, both `8080:80` and `8443:443` would be exposed as per the [merging rules outlined above](#sequence). 

## Additional resources

For more information on how merge can be used to create a composite Compose file, see [Working with multiple Compose files](../../compose/how-tos/multiple-compose-files/index.md)


---

# Models

*Sección: Reference*

{{< summary-bar feature_name="Compose models" >}}

The top-level `models` section declares AI models that are used by your Compose application. These models are typically pulled as OCI artifacts, run by a model runner, and exposed as an API that your service containers can consume.

Services can only access models when explicitly granted by a [`models` attribute](services.md#models) within the `services` top-level element.

## Examples

### Example 1

```yaml
services:
  app:
    image: app
    models:
      - ai_model


models:
  ai_model:
    model: ai/model
```

In this basic example:

 - The app service uses the `ai_model`.
 - The `ai_model` is defined as an OCI artifact (`ai/model`) that is pulled and served by the model runner.
 - Docker Compose injects connection info, for example `AI_MODEL_URL`, into the container. 

### Example 2

```yaml
services:
  app:
    image: app
    models:
      my_model:
        endpoint_var: MODEL_URL

models:
  my_model:
    model: ai/model
    context_size: 1024
    runtime_flags: 
      - "--a-flag"
      - "--another-flag=42"
```

In this advanced setup:

 - The service app references `my_model` using the long syntax.
 - Compose injects the model runner's URL as the environment variable `MODEL_URL`.

## Attributes

- `model` (required): The OCI artifact identifier for the model. This is what Compose pulls and runs via the model runner. 
- `context_size`: Defines the maximum token context size for the model.
- `runtime_flags`: A list of raw command-line flags passed to the inference engine when the model is started.

## Additional resources

For more examples and information on using `model`, see [Use AI models in Compose](../../ai/compose/models-and-compose.md)


---

# Define and manage networks in Docker Compose

*Sección: Reference*

{{% include "compose/networks.md" %}}

To use a network across multiple services, you must explicitly grant each service access by using the [networks](services.md) attribute within the `services` top-level element. The `networks` top-level element has additional syntax that provides more granular control.

## Examples

### Basic example

In the following example, at runtime, networks `front-tier` and `back-tier` are created and the `frontend` service
is connected to `front-tier` and `back-tier` networks.

```yml
services:
  frontend:
    image: example/webapp
    networks:
      - front-tier
      - back-tier

networks:
  front-tier:
  back-tier:
```

### Advanced example

```yml
services:
  proxy:
    build: ./proxy
    networks:
      - frontend
  app:
    build: ./app
    networks:
      - frontend
      - backend
  db:
    image: postgres:18
    networks:
      - backend

networks:
  frontend:
    # Specify driver options
    driver: bridge
    driver_opts:
      com.docker.network.bridge.host_binding_ipv4: "127.0.0.1"
  backend:
    # Use a custom driver
    driver: custom-driver
```

This example shows a Compose file which defines two custom networks. The `proxy` service is isolated from the `db` service, because they do not share a network in common. Only `app` can talk to both.

## The default network

When a Compose file doesn't declare explicit networks, Compose uses an implicit `default` network. Services without an explicit [`networks`](services.md#networks) declaration are connected by Compose to this `default` network:


```yml
services:
  some-service:
    image: foo
```
This example is actually equivalent to:

```yml
services:
  some-service:
    image: foo
    networks:
      default: {}  
networks:
  default: {}      
```

You can customize the `default` network with an explicit declaration:

```yml
networks:
  default: 
    name: a_network # Use a custom name
    driver_opts:    # pass options to driver for network creation
      com.docker.network.bridge.host_binding_ipv4: 127.0.0.1
```

For options, see the [Docker Engine docs](https://docs.docker.com/engine/network/drivers/bridge/#options).

## Attributes

### `attachable`

If `attachable` is set to `true`, then standalone containers should be able to attach to this network, in addition to services.
If a standalone container attaches to the network, it can communicate with services and other standalone containers
that are also attached to the network.

```yml
networks:
  mynet1:
    driver: overlay
    attachable: true
```

### `driver`

`driver` specifies which driver should be used for this network. Compose returns an error if the
driver is not available on the platform.

```yml
networks:
  db-data:
    driver: bridge
```

For more information on drivers and available options, see [Network drivers](../../engine/network/drivers/index.md).

### `driver_opts`

`driver_opts` specifies a list of options as key-value pairs to pass to the driver. These options are
driver-dependent.

```yml
networks:
  frontend:
    driver: bridge
    driver_opts:
      com.docker.network.bridge.host_binding_ipv4: "127.0.0.1"
```

Consult the [network drivers documentation](../../engine/network/index.md) for more information.

### `enable_ipv4`

{{< summary-bar feature_name="Compose enable ipv4" >}}

`enable_ipv4` can be used to disable IPv4 address assignment.

```yml
  networks:
    ip6net:
      enable_ipv4: false
      enable_ipv6: true
```

### `enable_ipv6`

`enable_ipv6` enables IPv6 address assignment.

```yml
  networks:
    ip6net:
      enable_ipv6: true
```

### `external`

If set to `true`:
 - `external` specifies that this network’s lifecycle is maintained outside of that of the application.
Compose doesn't attempt to create these networks, and returns an error if one doesn't exist.
 - All other attributes apart from name are irrelevant. If Compose detects any other attribute, it rejects the Compose file as invalid.

In the following example, `proxy` is the gateway to the outside world. Instead of attempting to create a network, Compose
queries the platform for an existing network called `outside` and connects the
`proxy` service's containers to it.

```yml
services:
  proxy:
    image: example/proxy
    networks:
      - outside
      - default
  app:
    image: example/app
    networks:
      - default

networks:
  outside:
    external: true
```

### `ipam`

`ipam` specifies a custom IPAM configuration. This is an object with several properties, each of which is optional:

- `driver`: Custom IPAM driver, instead of the default.
- `config`: A list with zero or more configuration elements, each containing a:
  - `subnet`: Subnet in CIDR format that represents a network segment
  - `ip_range`: Range of IPs from which to allocate container IPs
  - `gateway`: IPv4 or IPv6 gateway for the master subnet
  - `aux_addresses`: Auxiliary IPv4 or IPv6 addresses used by Network driver, as a mapping from hostname to IP
- `options`: Driver-specific options as a key-value mapping.

```yml
networks:
  mynet1:
    ipam:
      driver: default
      config:
        - subnet: 172.28.0.0/16
          ip_range: 172.28.5.0/24
          gateway: 172.28.5.254
          aux_addresses:
            host1: 172.28.1.5
            host2: 172.28.1.6
            host3: 172.28.1.7
      options:
        foo: bar
        baz: "0"
```

### `internal`

By default, Compose provides external connectivity to networks. `internal`, when set to `true`, lets you
create an externally isolated network.

### `labels`

Add metadata to containers using `labels`. You can use either an array or a dictionary.

It is recommended that you use reverse-DNS notation to prevent labels from conflicting with those used by other software.

```yml
networks:
  mynet1:
    labels:
      com.example.description: "Financial transaction network"
      com.example.department: "Finance"
      com.example.label-with-empty-value: ""
```

```yml
networks:
  mynet1:
    labels:
      - "com.example.description=Financial transaction network"
      - "com.example.department=Finance"
      - "com.example.label-with-empty-value"
```

Compose sets `com.docker.compose.project` and `com.docker.compose.network` labels.

### `name`

`name` sets a custom name for the network. The name field can be used to reference networks which contain special characters.
The name is used as is and is not scoped with the project name.

```yml
networks:
  network1:
    name: my-app-net
```

It can also be used in conjunction with the `external` property to define the platform network that Compose
should retrieve, typically by using a parameter so the Compose file doesn't need to hard-code runtime specific values:

```yml
networks:
  network1:
    external: true
    name: "${NETWORK_ID}"
```

## Additional resources

For more examples, see [Networking in Compose](../../compose/how-tos/networking.md).


---

# Learn how to use profiles in Docker Compose

*Sección: Reference*

With profiles you can define a set of active profiles so your Compose application model is adjusted for various usages and environments.

The [services](services.md) top-level element supports a `profiles` attribute to define a list of named profiles. 
Services without a `profiles` attribute are always enabled. 

A service is ignored by Compose when none of the listed `profiles` match the active ones, unless the service is
explicitly targeted by a command. In that case its profile is added to the set of active profiles.

> [!NOTE]
>
> All other top-level elements are not affected by `profiles` and are always active.

References to other services (by `links`, `extends` or shared resource syntax `service:xxx`) do not
automatically enable a component that would otherwise have been ignored by active profiles. Instead
Compose returns an error.

## Illustrative example

```yaml
services:
  web:
    image: web_image

  test_lib:
    image: test_lib_image
    profiles:
      - test

  coverage_lib:
    image: coverage_lib_image
    depends_on:
      - test_lib
    profiles:
      - test

  debug_lib:
    image: debug_lib_image
    depends_on:
      - test_lib
    profiles:
      - debug
```

In the above example:

- If the Compose application model is parsed when no profile is enabled, it only contains the `web` service.
- If the profile `test` is enabled, the model contains the services `test_lib` and `coverage_lib`, and service `web`, which is always enabled.
- If the profile `debug` is enabled, the model contains both `web` and `debug_lib` services, but not `test_lib` and `coverage_lib`,
  and as such the model is invalid regarding the `depends_on` constraint of `debug_lib`.
- If the profiles `debug` and `test` are enabled, the model contains all services; `web`, `test_lib`, `coverage_lib` and `debug_lib`.
- If Compose is executed with `test_lib` as the explicit service to run, `test_lib` and the `test` profile
  are active even if `test` profile is not enabled.
- If Compose is executed with `coverage_lib` as the explicit service to run, the service `coverage_lib` and the
  profile `test` are active and `test_lib` is pulled in by the `depends_on` constraint.
- If Compose is executed with `debug_lib` as the explicit service to run, again the model is
  invalid regarding the `depends_on` constraint of `debug_lib`, since `debug_lib` and `test_lib` have no common `profiles`
  listed.
- If Compose is executed with `debug_lib` as the explicit service to run and profile `test` is enabled,
  profile `debug` is automatically enabled and service `test_lib` is pulled in as a dependency starting both
  services `debug_lib` and `test_lib`.

Learn how to use `profiles` in [Docker Compose](../../compose/how-tos/profiles.md).


---

# Secrets

*Sección: Reference*

Secrets are a flavor of [Configs](configs.md) focusing on sensitive data, with specific constraint for this usage.

Services can only access secrets when explicitly granted by a [`secrets` attribute](services.md#secrets) within the `services` top-level element.

The top-level `secrets` declaration defines or references sensitive data that is granted to the services in your Compose
application. The source of the secret is either `file` or `environment`.

- `file`: The secret is created with the contents of the file at the specified path.
- `environment`: The secret is created with the value of an environment variable on the host. This is only supported by Docker Compose. It is not supported when deploying with [`docker stack deploy`](../../engine/swarm/stack-deploy.md).
 

## Example 1

`server-certificate` secret is created as `<project_name>_server-certificate` when the application is deployed,
by registering content of the `server.cert` as a platform secret.

```yml
secrets:
  server-certificate:
    file: ./server.cert
```

## Example 2

`token` secret is created as `<project_name>_token` when the application is deployed,
by registering the content of the `OAUTH_TOKEN` environment variable as a platform secret.

```yml
secrets:
  token:
    environment: "OAUTH_TOKEN"
```

> [!NOTE]
> `environment` secrets are not supported when deploying with `docker stack deploy`.
> Use `file` or `external` as the secret source instead.

## Additional resources

For more information, see [How to use secrets in Compose](../../compose/how-tos/use-secrets.md).


---

# Define services in Docker Compose

*Sección: Reference*

{{% include "compose/services.md" %}}

A Compose file must declare a `services` top-level element as a map whose keys are string representations of service names,
and whose values are service definitions. A service definition contains the configuration that is applied to each
service container.

Each service may also include a `build` section, which defines how to create the Docker image for the service.
Compose supports building Docker images using this service definition. If not used, the `build` section is ignored and the Compose file is still considered valid. Build support is an optional aspect of the Compose Specification, and is
described in detail in the [Compose Build Specification](build.md) documentation.

Each service defines runtime constraints and requirements to run its containers. The `deploy` section groups
these constraints and lets the platform adjust the deployment strategy to best match containers' needs with
available resources. Deploy support is an optional aspect of the Compose Specification, and is
described in detail in the [Compose Deploy Specification](deploy.md) documentation.
If not implemented the `deploy` section is ignored and the Compose file is still considered valid.

## Examples

### Simple example

The following example demonstrates how to define two simple services, set their images, map ports, and configure basic environment variables using Docker Compose.

```yaml
services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"

  db:
    image: postgres:18
    environment:
      POSTGRES_USER: example
      POSTGRES_DB: exampledb
```

### Advanced example

In the following example, the `proxy` service uses the Nginx image, mounts a local Nginx configuration file into the container, exposes port `80` and depends on the `backend` service.

The `backend` service builds an image from the Dockerfile located in the `backend` directory that is set to build at stage `builder`.

```yaml
services:
  proxy:
    image: nginx
    volumes:
      - type: bind
        source: ./proxy/nginx.conf
        target: /etc/nginx/conf.d/default.conf
        read_only: true
    ports:
      - 80:80
    depends_on:
      - backend

  backend:
    build:
      context: backend
      target: builder
```

For more example Compose files, explore the [Awesome Compose samples](https://github.com/docker/awesome-compose).

## Attributes

<!-- vale off(Docker.HeadingSentenceCase.yml) -->

### `annotations`

`annotations` defines annotations for the container. `annotations` can use either an array or a map.

```yml
annotations:
  com.example.foo: bar
```

```yml
annotations:
  - com.example.foo=bar
```

### `attach`

{{< summary-bar feature_name="Compose attach" >}}

When `attach` is defined and set to `false` Compose does not collect service logs,
until you explicitly request it to.

The default service configuration is `attach: true`.

### `build`

`build` specifies the build configuration for creating a container image from source, as defined in the [Compose Build Specification](build.md).

### `blkio_config`

`blkio_config` defines a set of configuration options to set block I/O limits for a service.

```yml
services:
  foo:
    image: busybox
    blkio_config:
       weight: 300
       weight_device:
         - path: /dev/sda
           weight: 400
       device_read_bps:
         - path: /dev/sdb
           rate: '12mb'
       device_read_iops:
         - path: /dev/sdb
           rate: 120
       device_write_bps:
         - path: /dev/sdb
           rate: '1024k'
       device_write_iops:
         - path: /dev/sdb
           rate: 30
```

#### `device_read_bps`, `device_write_bps`

Set a limit in bytes per second for read / write operations on a given device.
Each item in the list must have two keys:

- `path`: Defines the symbolic path to the affected device.
- `rate`: Either as an integer value representing the number of bytes or as a string expressing a byte value.

#### `device_read_iops`, `device_write_iops`

Set a limit in operations per second for read / write operations on a given device.
Each item in the list must have two keys:

- `path`: Defines the symbolic path to the affected device.
- `rate`: As an integer value representing the permitted number of operations per second.

#### `weight`

Modify the proportion of bandwidth allocated to a service relative to other services.
Takes an integer value between 10 and 1000, with 500 being the default.

#### `weight_device`

Fine-tune bandwidth allocation by device. Each item in the list must have two keys:

- `path`: Defines the symbolic path to the affected device.
- `weight`: An integer value between 10 and 1000.

### `cpu_count`

`cpu_count` defines the number of usable CPUs for service container.

### `cpu_percent`

`cpu_percent` defines the usable percentage of the available CPUs.

### `cpu_shares`

`cpu_shares` defines, as integer value, a service container's relative CPU weight versus other containers.

### `cpu_period`

`cpu_period` configures CPU CFS (Completely Fair Scheduler) period when a platform is based
on Linux kernel.

### `cpu_quota`

`cpu_quota` configures CPU CFS (Completely Fair Scheduler) quota when a platform is based
on Linux kernel.

### `cpu_rt_runtime`

`cpu_rt_runtime` configures CPU allocation parameters for platforms with support for real-time scheduler. It can be either
an integer value using microseconds as unit or a [duration](extension.md#specifying-durations).

```yml
 cpu_rt_runtime: '400ms'
 cpu_rt_runtime: '95000'
```

### `cpu_rt_period`

`cpu_rt_period` configures CPU allocation parameters for platforms with support for real-time scheduler. It can be either
an integer value using microseconds as unit or a [duration](extension.md#specifying-durations).

```yml
 cpu_rt_period: '1400us'
 cpu_rt_period: '11000'
```

### `cpus`

`cpus` define the number of (potentially virtual) CPUs to allocate to service containers. This is a fractional number.
`0.000` means no limit.

When set, `cpus` must be consistent with the `cpus` attribute in the [Deploy Specification](deploy.md#cpus).

### `cpuset`

`cpuset` defines the explicit CPUs in which to permit execution. Can be a range `0-3` or a list `0,1`

### `cap_add`

`cap_add` specifies additional container [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html)
as strings.

```yaml
cap_add:
  - ALL
```

### `cap_drop`

`cap_drop` specifies container [capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) to drop
as strings.

```yaml
cap_drop:
  - NET_ADMIN
  - SYS_ADMIN
```

### `cgroup`

{{< summary-bar feature_name="Compose cgroup" >}}

`cgroup` specifies the cgroup namespace to join. When unset, it is the container runtime's decision to
select which cgroup namespace to use, if supported.

- `host`: Runs the container in the Container runtime cgroup namespace.
- `private`: Runs the container in its own private cgroup namespace.

### `cgroup_parent`

`cgroup_parent` specifies an optional parent [cgroup](https://man7.org/linux/man-pages/man7/cgroups.7.html) for the container.

```yaml
cgroup_parent: m-executor-abcd
```

### `command`

`command` overrides the default command declared by the container image, for example by Dockerfile's `CMD`.

```yaml
command: bundle exec thin -p 3000
```

If the value is `null`, the default command from the image is used.

If the value is `[]` (empty list) or `''` (empty string), the default command declared by the image is ignored, or in other words overridden to be empty.

> [!NOTE]
>
> Unlike the `CMD` instruction in a Dockerfile, the `command` field doesn't automatically run within the context of the [`SHELL`](../../build/concepts/dockerfile.md#shell-form) instruction defined in the image. If your `command` relies on shell-specific features, such as environment variable expansion, you need to explicitly run it within a shell. For example:
>
> ```yaml
> command: /bin/sh -c 'echo "hello $$HOSTNAME"'
> ```

The value can also be a list, similar to the [exec-form syntax](../../build/concepts/dockerfile.md#exec-form)
used by the [Dockerfile](../../build/concepts/dockerfile.md#exec-form).

### `configs`

`configs` let services adapt their behaviour without the need to rebuild a Docker image.
Services can only access configs when explicitly granted by the `configs` attribute. Two different syntax variants are supported.

Compose reports an error if `config` doesn't exist on the platform or isn't defined in the
[`configs` top-level element](configs.md) in the Compose file.

There are two syntaxes defined for configs: a short syntax and a long syntax.

You can grant a service access to multiple configs, and you can mix long and short syntax.

#### Short syntax

The short syntax variant only specifies the config name. This grants the
container access to the config and mounts it as files into a service’s container’s filesystem. The location of the mount point within the container defaults to `/<config_name>` in Linux containers, and `C:\<config-name>` in Windows containers.

The following example uses the short syntax to grant the `redis` service
access to the `my_config` and `my_other_config` configs. The value of
`my_config` is set to the contents of the file `./my_config.txt`, and
`my_other_config` is defined as an external resource, which means that it has
already been defined in the platform. If the external config does not exist,
the deployment fails.

```yml
services:
  redis:
    image: redis:latest
    configs:
      - my_config
      - my_other_config
configs:
  my_config:
    file: ./my_config.txt
  my_other_config:
    external: true
```

#### Long syntax

The long syntax provides more granularity in how the config is created within the service's task containers.

- `source`: The name of the config as it exists in the platform.
- `target`: The path and name of the file to be mounted in the service's
  task containers. Defaults to `/<source>` if not specified.
- `uid` and `gid`: The numeric uid or gid that owns the mounted config file
  within the service's task containers.
- `mode`: The [permissions](https://wintelguy.com/permissions-calc.pl) for the file that is mounted within the service's
  task containers, in octal notation. Default value is world-readable (`0444`).
  Writable bit must be ignored. The executable bit can be set.

The following example sets the name of `my_config` to `redis_config` within the
container, sets the mode to `0440` (group-readable) and sets the user and group
to `103`. The `redis` service does not have access to the `my_other_config`
config.

```yml
services:
  redis:
    image: redis:latest
    configs:
      - source: my_config
        target: /redis_config
        uid: "103"
        gid: "103"
        mode: 0440
configs:
  my_config:
    external: true
  my_other_config:
    external: true
```

### `container_name`

`container_name` is a string that specifies a custom container name, rather than a name generated by default.

```yml
container_name: my-web-container
```

Compose does not scale a service beyond one container if the Compose file specifies a
`container_name`. Attempting to do so results in an error.

`container_name` follows the regex format of `[a-zA-Z0-9][a-zA-Z0-9_.-]+`

### `credential_spec`

`credential_spec` configures the credential spec for a managed service account.

If you have services that use Windows containers, you can use `file:` and
`registry:` protocols for `credential_spec`. Compose also supports additional
protocols for custom use-cases.

The `credential_spec` must be in the format `file://<filename>` or `registry://<value-name>`.

```yml
credential_spec:
  file: my-credential-spec.json
```

When using `registry:`, the credential spec is read from the Windows registry on
the daemon's host. A registry value with the given name must be located in:

```bash
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\Containers\CredentialSpecs
```

The following example loads the credential spec from a value named `my-credential-spec`
in the registry:

```yml
credential_spec:
  registry: my-credential-spec
```

#### Example gMSA configuration

When configuring a gMSA credential spec for a service, you only need
to specify a credential spec with `config`, as shown in the following example:

```yml
services:
  myservice:
    image: myimage:latest
    credential_spec:
      config: my_credential_spec

configs:
  my_credentials_spec:
    file: ./my-credential-spec.json
```

### `depends_on`

{{% include "compose/services-depends-on.md" %}}

#### Short syntax

The short syntax variant only specifies service names of the dependencies.
Service dependencies cause the following behaviors:

- Compose creates services in dependency order. In the following
  example, `db` and `redis` are created before `web`.

- Compose removes services in dependency order. In the following
  example, `web` is removed before `db` and `redis`.

Simple example:

```yml
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres:18
```

Compose guarantees dependency services have been started before
starting a dependent service.
With short syntax, Compose does not wait for dependency services to be "healthy" before
starting a dependent service.

#### Long syntax

The long form syntax enables the configuration of additional fields that can't be
expressed in the short form.

- `restart`: When set to `true` Compose restarts this service after it updates the dependency service.
  This applies to an explicit restart controlled by a Compose operation, and excludes automated restart by the container runtime
  after the container dies. Introduced in Docker Compose version [2.17.0](https://github.com/docker/compose/releases/tag/v2.17.0).

- `condition`: Sets the condition under which dependency is considered satisfied
  - `service_started`: An equivalent of the short syntax described previously
  - `service_healthy`: Specifies that a dependency is expected to be "healthy"
    (as indicated by [`healthcheck`](#healthcheck)) before starting a dependent
    service.
  - `service_completed_successfully`: Specifies that a dependency is expected to run
    to successful completion before starting a dependent service.
- `required`: When set to `false` Compose only warns you when the dependency service isn't started or available. If it's not defined
    the default value of `required` is `true`. Introduced in Docker Compose version [2.20.0](https://github.com/docker/compose/releases/tag/v2.20.0).

Service dependencies cause the following behaviors:

- Compose creates services in dependency order. In the following
  example, `db` and `redis` are created before `web`.

- Compose waits for healthchecks to pass on dependencies
  marked with `service_healthy`. In the following example, `db` is expected to
  be "healthy" before `web` is created.

- Compose removes services in dependency order. In the following
  example, `web` is removed before `db` and `redis`.

```yml
services:
  web:
    build: .
    depends_on:
      db:
        condition: service_healthy
        restart: true
      redis:
        condition: service_started
  redis:
    image: redis
  db:
    image: postgres:18
```

Compose guarantees dependency services are started before
starting a dependent service.
Compose guarantees dependency services marked with
`service_healthy` are "healthy" before starting a dependent service.

### `deploy`

`deploy` specifies the configuration for the deployment and lifecycle of services, as defined [in the Compose Deploy Specification](deploy.md).

### `develop`

{{< summary-bar feature_name="Compose develop" >}}

`develop` specifies the development configuration for maintaining a container in sync with source, as defined in the [Development Section](develop.md).

### `device_cgroup_rules`

`device_cgroup_rules` defines a list of device cgroup rules for this container.
The format is the same format the Linux kernel specifies in the [Control Groups
Device Whitelist Controller](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html).

```yml
device_cgroup_rules:
  - 'c 1:3 mr'
  - 'a 7:* rmw'
```

### `devices`

`devices` defines a list of device mappings for created containers in the form of
`HOST_PATH:CONTAINER_PATH[:CGROUP_PERMISSIONS]`.

```yml
devices:
  - "/dev/ttyUSB0:/dev/ttyUSB0"
  - "/dev/sda:/dev/xvda:rwm"
```

`devices` can also rely on the [CDI](https://github.com/cncf-tags/container-device-interface) syntax to let the container runtime select a device:

```yml
devices:
  - "vendor1.com/device=gpu"
```

### `dns`

`dns` defines custom DNS servers to set on the container network interface configuration. It can be a single value or a list.

```yml
dns: 8.8.8.8
```

```yml
dns:
  - 8.8.8.8
  - 9.9.9.9
```

### `dns_opt`

`dns_opt` list custom DNS options to be passed to the container’s DNS resolver (`/etc/resolv.conf` file on Linux).

```yml
dns_opt:
  - use-vc
  - no-tld-query
```

### `dns_search`

`dns_search` defines custom DNS search domains to set on container network interface configuration. It can be a single value or a list.

```yml
dns_search: example.com
```

```yml
dns_search:
  - dc1.example.com
  - dc2.example.com
```

### `domainname`

`domainname` declares a custom domain name to use for the service container. It must be a valid RFC 1123 hostname.

### `driver_opts`

{{< summary-bar feature_name="Compose driver opts" >}}

`driver_opts` specifies a list of options as key-value pairs to pass to the driver. These options are
driver-dependent.

```yml
services:
  app:
    networks:
      app_net:
        driver_opts:
          com.docker.network.bridge.host_binding_ipv4: "127.0.0.1"
```

Consult the [network drivers documentation](../../engine/network/index.md) for more information.

### `entrypoint`

`entrypoint` declares the default entrypoint for the service container.
This overrides the `ENTRYPOINT` instruction from the service's Dockerfile.

If `entrypoint` is non-null, Compose ignores any default command from the image, for example the `CMD`
instruction in the Dockerfile.

See also [`command`](#command) to set or override the default command to be executed by the entrypoint process.

In its short form, the value can be defined as a string:
```yml
entrypoint: /code/entrypoint.sh
```

Alternatively, the value can also be a list, in a manner similar to the
[Dockerfile](https://docs.docker.com/reference/dockerfile/#cmd):

```yml
entrypoint:
  - php
  - -d
  - zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
  - -d
  - memory_limit=-1
  - vendor/bin/phpunit
```

If the value is `null`, the default entrypoint from the image is used.

If the value is `[]` (empty list) or `''` (empty string), the default entrypoint declared by the image is ignored, or in other words, overridden to be empty.

### `env_file`

{{% include "compose/services-env-file.md" %}}

```yml
env_file: .env
```

Relative paths are resolved from the Compose file's parent folder. As absolute paths prevent the Compose
file from being portable, Compose warns you when such a path is used to set `env_file`.

Environment variables declared in the [`environment`](#environment) section override these values. This holds true even if those values are
empty or undefined.

`env_file` can also be a list. The files in the list are processed from the top down. For the same variable
specified in two environment files, the value from the last file in the list stands.

```yml
env_file:
  - ./a.env
  - ./b.env
```

List elements can also be declared as a mapping, which then lets you set additional
attributes.

#### `required`

{{< summary-bar feature_name="Compose required" >}}

The `required` attribute defaults to `true`. When `required` is set to `false` and the `.env` file is missing, Compose silently ignores the entry.

```yml
env_file:
  - path: ./default.env
    required: true # default
  - path: ./override.env
    required: false
```

#### `format`

{{< summary-bar feature_name="Compose format" >}}

The `format` attribute lets you use an alternative file format for the `env_file`. When not set, `env_file` is parsed according to the Compose rules outlined in [`Env_file` format](#env_file-format).

`raw` format lets you use an `env_file` with key=value items, but without any attempt from Compose to parse the value for interpolation.
This let you pass values as-is, including quotes and `$` signs.

```yml
env_file:
  - path: ./default.env
    format: raw
```

#### `Env_file` format

Each line in an `.env` file must be in `VAR[=[VAL]]` format. The following syntax rules apply:

- Lines beginning with `#` are processed as comments and ignored.
- Blank lines are ignored.
- Unquoted and double-quoted (`"`) values have [Interpolation](interpolation.md) applied.
- Each line represents a key-value pair. Values can optionally be quoted.
- Delimiter separating key and value can be either `=` or `:`.
- Spaces before and after value are ignored.
  - `VAR=VAL` -> `VAL`
  - `VAR="VAL"` -> `VAL`
  - `VAR='VAL'` -> `VAL`
  - `VAR: VAL` -> `VAL`
  - `VAR = VAL  ` -> `VAL` <!-- markdownlint-disable-line no-space-in-code -->
- Inline comments for unquoted values must be preceded with a space.
  - `VAR=VAL # comment` -> `VAL`
  - `VAR=VAL# not a comment` -> `VAL# not a comment`
- Inline comments for quoted values must follow the closing quote.
  - `VAR="VAL # not a comment"` -> `VAL # not a comment`
  - `VAR="VAL" # comment` -> `VAL`
- Single-quoted (`'`) values are used literally.
  - `VAR='$OTHER'` -> `$OTHER`
  - `VAR='${OTHER}'` -> `${OTHER}`
- Quotes can be escaped with `\`.
  - `VAR='Let\'s go!'` -> `Let's go!`
  - `VAR="{\"hello\": \"json\"}"` -> `{"hello": "json"}`
- Common shell escape sequences including `\n`, `\r`, `\t`, and `\\` are supported in double-quoted values.
  - `VAR="some\tvalue"` -> `some  value`
  - `VAR='some\tvalue'` -> `some\tvalue`
  - `VAR=some\tvalue` -> `some\tvalue`

`VAL` may be omitted, in such cases the variable value is an empty string.
`=VAL` may be omitted, in such cases the variable is unset.

```bash
# Set Rails/Rack environment
RACK_ENV=development
VAR="quoted"
```

### `environment`

{{% include "compose/services-environment.md" %}}

Environment variables can be declared by a single key (no value to equals sign). In this case Compose
relies on you to resolve the value. If the value is not resolved, the variable
is unset and is removed from the service container environment.

Map syntax:

```yml
environment:
  RACK_ENV: development
  SHOW: "true"
  USER_INPUT:
```

Array syntax:

```yml
environment:
  - RACK_ENV=development
  - SHOW=true
  - USER_INPUT
```

When both `env_file` and `environment` are set for a service, values set by `environment` have precedence.

### `expose`

`expose` defines the (incoming) port or a range of ports that Compose exposes from the container. These ports must be
accessible to linked services and should not be published to the host machine. Only the internal container
ports can be specified.

Syntax is `<portnum>/[<proto>]` or `<startport-endport>/[<proto>]` for a port range.
When not explicitly set, `tcp` protocol is used.

```yml
expose:
  - "3000"
  - "8000"
  - "8080-8085/tcp"
```

> [!NOTE]
>
> If the Dockerfile for the image already exposes ports, it is visible to other containers on the network even if `expose` is not set in your Compose file.

### `extends`

`extends` lets you share common configurations among different files, or even different projects entirely. With `extends` you can define a common set of service options in one place and refer to it from anywhere. You can refer to another Compose file and select a service you want to also use in your own application, with the ability to override some attributes for your own needs.

You can use `extends` on any service together with other configuration keys. The `extends` value must be a mapping
defined with a required `service` and an optional `file` key.

```yaml
extends:
  file: common.yml
  service: webapp
```

- `service`: Defines the name of the service being referenced as a base, for example `web` or `database`.
- `file`: The location of a Compose configuration file defining that service.

`extends` is not supported when deploying with `docker stack deploy`.

#### Restrictions

When a service is referenced using `extends`, it can declare dependencies on other resources. These dependencies may be explicitly defined through attributes like `volumes`, `networks`, `configs`, `secrets`, `links`, `volumes_from`, or `depends_on`. Alternatively, dependencies can reference another service using the `service:{name}` syntax in namespace declarations such as `ipc`, `pid`, or `network_mode`.

Compose does not automatically import these referenced resources into the extended model. It is your responsibility to ensure all required resources are explicitly declared in the model that relies on extends.

Circular references with `extends` are not supported, Compose returns an error when one is detected.

#### Finding referenced service

`file` value can be:

- Not present.
  This indicates that another service within the same Compose file is being referenced.
- File path, which can be either:
  - Relative path. This path is considered as relative to the location of the main Compose
    file.
  - Absolute path.

A service denoted by `service` must be present in the identified referenced Compose file.
Compose returns an error if:

- The service denoted by `service` is not found.
- The Compose file denoted by `file` is not found.

#### Merging service definitions

Two service definitions, the main one in the current Compose file and the referenced one
specified by `extends`, are merged in the following way:

- Mappings: Keys in mappings of the main service definition override keys in mappings
  of the referenced service definition. Keys that aren't overridden are included as is.
- Sequences: Items are combined together into a new sequence. The order of elements is
  preserved with the referenced items coming first and main items after.
- Scalars: Keys in the main service definition take precedence over keys in the
  referenced one.

##### Mappings

The following keys should be treated as mappings: `annotations`, `build.args`, `build.labels`,
`build.extra_hosts`, `deploy.labels`, `deploy.update_config`, `deploy.rollback_config`,
`deploy.restart_policy`, `deploy.resources.limits`, `environment`, `healthcheck`,
`labels`, `logging.options`, `sysctls`, `storage_opt`, `extra_hosts`, `ulimits`.

One exception that applies to `healthcheck` is that the main mapping cannot specify
`disable: true` unless the referenced mapping also specifies `disable: true`. Compose returns an error in this case.
For example, the following input:

```yaml
services:
  common:
    image: busybox
    environment:
      TZ: utc
      PORT: 80
  cli:
    extends:
      service: common
    environment:
      PORT: 8080
```

Produces the following configuration for the `cli` service. The same output is
produced if array syntax is used.

```yaml
environment:
  PORT: 8080
  TZ: utc
image: busybox
```

Items under `blkio_config.device_read_bps`, `blkio_config.device_read_iops`,
`blkio_config.device_write_bps`, `blkio_config.device_write_iops`, `devices` and
`volumes` are also treated as mappings where key is the target path inside the
container.

For example, the following input:

```yaml
services:
  common:
    image: busybox
    volumes:
      - common-volume:/var/lib/backup/data:rw
  cli:
    extends:
      service: common
    volumes:
      - cli-volume:/var/lib/backup/data:ro
```

Produces the following configuration for the `cli` service. Note that the mounted path
now points to the new volume name and `ro` flag was applied.

```yaml
image: busybox
volumes:
- cli-volume:/var/lib/backup/data:ro
```

If the referenced service definition contains `extends` mapping, the items under it
are simply copied into the new merged definition. The merging process is then kicked
off again until no `extends` keys are remaining.

For example, the following input:

```yaml
services:
  base:
    image: busybox
    user: root
  common:
    image: busybox
    extends:
      service: base
  cli:
    extends:
      service: common
```

Produces the following configuration for the `cli` service. Here, `cli` services
gets `user` key from `common` service, which in turn gets this key from `base`
service.

```yaml
image: busybox
user: root
```

##### Sequences

The following keys should be treated as sequences: `cap_add`, `cap_drop`, `configs`,
`deploy.placement.constraints`, `deploy.placement.preferences`,
`deploy.reservations.generic_resources`, `device_cgroup_rules`, `expose`,
`external_links`, `ports`, `secrets`, `security_opt`.
Any duplicates resulting from the merge are removed so that the sequence only
contains unique elements.

For example, the following input:

```yaml
services:
  common:
    image: busybox
    security_opt:
      - label=role:ROLE
  cli:
    extends:
      service: common
    security_opt:
      - label=user:USER
```

Produces the following configuration for the `cli` service.

```yaml
image: busybox
security_opt:
- label=role:ROLE
- label=user:USER
```

In case list syntax is used, the following keys should also be treated as sequences:
`dns`, `dns_search`, `env_file`, `tmpfs`. Unlike sequence fields mentioned previously,
duplicates resulting from the merge are not removed.

##### Scalars

Any other allowed keys in the service definition should be treated as scalars.

### `external_links`

`external_links` link service containers to services managed outside of your Compose application.
`external_links` define the name of an existing service to retrieve using the platform lookup mechanism.
An alias of the form `SERVICE:ALIAS` can be specified.

```yml
external_links:
  - redis
  - database:mysql
  - database:postgresql
```

### `extra_hosts`

`extra_hosts` adds hostname mappings to the container network interface configuration (`/etc/hosts` for Linux).

#### Short syntax

Short syntax uses plain strings in a list. Values must set hostname and IP address for additional hosts in the form of `HOSTNAME=IP`.

```yml
extra_hosts:
  - "somehost=162.242.195.82"
  - "otherhost=50.31.209.229"
  - "myhostv6=::1"
```

IPv6 addresses can be enclosed in square brackets, for example:

```yml
extra_hosts:
  - "myhostv6=[::1]"
```

The separator `=` is preferred, but `:` can also be used. Introduced in Docker Compose version [2.24.1](https://github.com/docker/compose/releases/tag/v2.24.1). For example:

```yml
extra_hosts:
  - "somehost:162.242.195.82"
  - "myhostv6:::1"
```

#### Long syntax

Alternatively, `extra_hosts` can be set as a mapping between hostname(s) and IP(s)

```yml
extra_hosts:
  somehost: "162.242.195.82"
  otherhost: "50.31.209.229"
  myhostv6: "::1"
```

Compose creates a matching entry with the IP address and hostname in the container's network
configuration, which means for Linux `/etc/hosts` get extra lines:

```console
162.242.195.82  somehost
50.31.209.229   otherhost
::1             myhostv6
```

### `gpus`

{{< summary-bar feature_name="Compose gpus" >}}

`gpus` specifies GPU devices to be allocated for container usage. This is equivalent to a [device request](deploy.md#devices) with
an implicit `gpu` capability.

```yaml
services:
  model:
    gpus:
      - driver: 3dfx
        count: 2
```

`gpus` also can be set as string `all` to allocate all available GPU devices to the container.

```yaml
services:
  model:
    gpus: all
```

### `group_add`

`group_add` specifies additional groups, by name or number, which the user inside the container must be a member of.

An example of where this is useful is when multiple containers (running as different users) need to all read or write
the same file on a shared volume. That file can be owned by a group shared by all the containers, and specified in
`group_add`.

```yml
services:
  myservice:
    image: alpine
    group_add:
      - mail
```

Running `id` inside the created container must show that the user belongs to the `mail` group, which would not have
been the case if `group_add` were not declared.

### `healthcheck`

{{% include "compose/services-healthcheck.md" %}}

For more information on `HEALTHCHECK`, see the [Dockerfile reference](../../build/concepts/dockerfile.md#healthcheck).

```yml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost"]
  interval: 1m30s
  timeout: 10s
  retries: 3
  start_period: 40s
  start_interval: 5s
```

`interval`, `timeout`, `start_period`, and `start_interval` are [specified as durations](extension.md#specifying-durations). Introduced in Docker Compose version [2.20.2](https://github.com/docker/compose/releases/tag/v2.20.2)

`test` defines the command Compose runs to check container health. It can be
either a string or a list. If it's a list, the first item must be either `NONE`, `CMD` or `CMD-SHELL`.
If it's a string, it's equivalent to specifying `CMD-SHELL` followed by that string.

```yml
# Hit the local web app
test: ["CMD", "curl", "-f", "http://localhost"]
```

Using `CMD-SHELL` runs the command configured as a string using the container's default shell
(`/bin/sh` for Linux). Both of the following forms are equivalent:

```yml
test: ["CMD-SHELL", "curl -f http://localhost || exit 1"]
```

```yml
test: curl -f https://localhost || exit 1
```

`NONE` disables the healthcheck, and is mostly useful to disable the Healthcheck Dockerfile instruction set by the service's Docker image. Alternatively,
the healthcheck set by the image can be disabled by setting `disable: true`:

```yml
healthcheck:
  disable: true
```

### `hostname`

`hostname` declares a custom host name to use for the service container. It must be a valid RFC 1123 hostname.

### `image`

`image` specifies the image to start the container from. `image` must follow the Open Container Specification
[addressable image format](https://github.com/opencontainers/org/blob/master/docs/docs/introduction/digests.md),
as `[<registry>/][<project>/]<image>[:<tag>|@<digest>]`.

```yml
    image: redis
    image: redis:5
    image: redis@sha256:0ed5d5928d4737458944eb604cc8509e245c3e19d02ad83935398bc4b991aac7
    image: library/redis
    image: docker.io/library/redis
    image: my_private.registry:5000/redis
```

If the image does not exist on the platform, Compose attempts to pull it based on the `pull_policy`.
If you are also using the [Compose Build Specification](build.md), there are alternative options for controlling the precedence of
pull over building the image from source, however pulling the image is the default behavior.

`image` may be omitted from a Compose file as long as a `build` section is declared. If you are not using the Compose Build Specification, Compose won't work if `image` is missing from the Compose file.

### `init`

`init` runs an init process (PID 1) inside the container that forwards signals and reaps processes.
Set this option to `true` to enable this feature for the service.

```yml
services:
  web:
    image: alpine:latest
    init: true
```

The init binary that is used is platform specific.

### `ipc`

`ipc` configures the IPC isolation mode set by the service container.

- `shareable`: Gives the container its own private IPC namespace, with a
  possibility to share it with other containers.
- `service:{name}`: Makes the container join another container's
  (`shareable`) IPC namespace.

```yml
    ipc: "shareable"
    ipc: "service:[service name]"
```

### `isolation`

`isolation` specifies a container’s isolation technology. Supported values are platform specific.

### `labels`

`labels` add metadata to containers. You can use either an array or a map.

It's recommended that you use reverse-DNS notation to prevent your labels from conflicting with
those used by other software.

```yml
labels:
  com.example.description: "Accounting webapp"
  com.example.department: "Finance"
  com.example.label-with-empty-value: ""
```

```yml
labels:
  - "com.example.description=Accounting webapp"
  - "com.example.department=Finance"
  - "com.example.label-with-empty-value"
```

Compose creates containers with canonical labels:

- `com.docker.compose.project` set on all resources created by Compose to the user project name
- `com.docker.compose.service` set on service containers with service name as defined in the Compose file

The `com.docker.compose` label prefix is reserved. Specifying labels with this prefix in the Compose file
results in a runtime error.

### `label_file`

{{< summary-bar feature_name="Compose label file" >}}

The `label_file` attribute lets you load labels for a service from an external file or a list of files. This provides a convenient way to manage multiple labels without cluttering the Compose file.

The file uses a key-value format, similar to `env_file`. You can specify multiple files as a list. When using multiple files, they are processed in the order they appear in the list. If the same label is defined in multiple files, the value from the last file in the list overrides earlier ones.

```yaml
services:
  one:
    label_file: ./app.labels

  two:
    label_file:
      - ./app.labels
      - ./additional.labels
```

If a label is defined in both the `label_file` and the `labels` attribute, the value in [labels](#labels) takes precedence.

### `links`

`links` defines a network link to containers in another service. Either specify both the service name and
a link alias (`SERVICE:ALIAS`), or just the service name.

```yml
web:
  links:
    - db
    - db:database
    - redis
```

Containers for the linked service are reachable at a hostname identical to the alias, or the service name
if no alias is specified.

Links are not required to enable services to communicate. When no specific network configuration is set,
any service is able to reach any other service at that service’s name on the `default` network.
If services specify the networks they are attached to, `links` does not override the network configuration. Services that are not connected to a shared network are not be able to communicate with each other. Compose doesn't warn you about a configuration mismatch.

Links also express implicit dependency between services in the same way as
[`depends_on`](#depends_on), so they determine the order of service startup.

### `logging`

`logging` defines the logging configuration for the service.

```yml
logging:
  driver: syslog
  options:
    syslog-address: "tcp://192.168.0.42:123"
```

The `driver` name specifies a logging driver for the service's containers. The default and available values
are platform specific. Driver specific options can be set with `options` as key-value pairs.

### `mac_address`

> Available with Docker Compose version 2.24.0 and later.

`mac_address` sets a Mac address for the service container.

> [!NOTE]
> Container runtimes might reject this value, for example Docker Engine >= v25.0. In that case, you should use [networks.mac_address](#mac_address) instead.

### `mem_limit`

`mem_limit` configures a limit on the amount of memory a container can allocate, set as a string expressing a [byte value](extension.md#specifying-byte-values).

When set, `mem_limit` must be consistent with the `limits.memory` attribute in the [Deploy Specification](deploy.md#memory).

### `mem_reservation`

`mem_reservation` configures a reservation on the amount of memory a container can allocate, set as a string expressing a [byte value](extension.md#specifying-byte-values).

When set, `mem_reservation` must be consistent with the `reservations.memory` attribute in the [Deploy Specification](deploy.md#memory).

### `mem_swappiness`

`mem_swappiness` defines as a percentage, a value between 0 and 100, for the host kernel to swap out
anonymous memory pages used by a container.

- `0`: Turns off anonymous page swapping.
- `100`: Sets all anonymous pages as swappable.

The default value is platform specific.

### `memswap_limit`

`memswap_limit` defines the amount of memory the container is allowed to swap to disk. This is a modifier
attribute that only has meaning if [`memory`](deploy.md#memory) is also set. Using swap lets the container write excess
memory requirements to disk when the container has exhausted all the memory that is available to it.
There is a performance penalty for applications that swap memory to disk often.

- If `memswap_limit` is set to a positive integer, then both `memory` and `memswap_limit` must be set. `memswap_limit` represents the total amount of memory and swap that can be used, and `memory` controls the amount used by non-swap memory. So if `memory`="300m" and `memswap_limit`="1g", the container can use 300m of memory and 700m (1g - 300m) swap.
- If `memswap_limit` is set to 0, the setting is ignored, and the value is treated as unset.
- If `memswap_limit` is set to the same value as `memory`, and `memory` is set to a positive integer, the container does not have access to swap.
- If `memswap_limit` is unset, and `memory` is set, the container can use as much swap as the `memory` setting, if the host has swap memory configured. For instance, if `memory`="300m" and `memswap_limit` is not set, the container can use 600m in total of memory and swap.
- If `memswap_limit` is explicitly set to -1, the container is allowed to use unlimited swap, up to the amount available on the host system.

### `models`

{{< summary-bar feature_name="Compose models" >}}

`models` defines which AI models the service should use at runtime. Each referenced model must be defined under the [`models` top-level element](models.md).

```yaml
services:
  short_syntax:
    image: app
    models:
      - my_model
  long_syntax:
    image: app
    models:
      my_model:
        endpoint_var: MODEL_URL
        model_var: MODEL
```

When a service is linked to a model, Docker Compose injects environment variables to pass connection details and model identifiers to the container. This allows the application to locate and communicate with the model dynamically at runtime, without hard-coding values.

#### Long syntax

The long syntax gives you more control over the environment variable names.

- `endpoint_var` sets the name of the environment variable that holds the model runner’s URL.
- `model_var` sets the name of the environment variable that holds the model identifier.

If either is omitted, Compose automatically generates the environment variable names based on the model key using the following rules:

 - Convert the model key to uppercase
 - Replace any '-' characters with '_'
 - Append `_URL` for the endpoint variable

### `network_mode`

`network_mode` sets a service container's network mode.

- `bridge`: Connects the container to Docker's default bridge network instead of
  a project-specific network. Containers on the default bridge network cannot
  resolve each other by service name . Instead, use a user-defined network for DNS resolution.
- `none`: Turns off all container networking.
- `host`: Gives the container raw access to the host's network interface.
- `service:{name}`: Gives the container access to the specified container by referring to its service name.
- `container:{name}`: Gives the container access to the specified container by referring to its container ID.

For more information container networks, see the [Docker Engine documentation](../../engine/network/index.md#container-networks).

```yml
    network_mode: "bridge"
    network_mode: "host"
    network_mode: "none"
    network_mode: "service:[service name]"
```

When set, the [`networks`](#networks) attribute is not allowed and Compose rejects any
Compose file containing both attributes.

### `networks`

{{% include "compose/services-networks.md" %}}

```yml
services:
  some-service:
    networks:
      - some-network
      - other-network
```
For more information about the `networks` top-level element, see [Networks](networks.md).

#### Implicit default network

If `networks` is empty or absent from the Compose file, Compose considers an implicit definition for the service to be
connected to the `default` network:

```yml
services:
  some-service:
    image: foo
```
This example is actually equivalent to:

```yml
services:
  some-service:
    image: foo
    networks:
      default: {}
```

If you want the service to not be connected a network, you must set [`network_mode: none`](#network_mode).

#### `aliases`

`aliases` declares alternative hostnames for the service on the network. Other containers on the same
network can use either the service name or an alias to connect to one of the service's containers.

Since `aliases` are network-scoped, the same service can have different aliases on different networks.

> [!NOTE]
> A network-wide alias can be shared by multiple containers, and even by multiple services.
> If it is, then exactly which container the name resolves to is not guaranteed.

```yml
services:
  some-service:
    networks:
      some-network:
        aliases:
          - alias1
          - alias3
      other-network:
        aliases:
          - alias2
```

In the following example, service `frontend` is able to reach the `backend` service at
the hostname `backend` or `database` on the `back-tier` network. The service `monitoring`
is able to reach same `backend` service at `backend` or `mysql` on the `admin` network.

```yml
services:
  frontend:
    image: example/webapp
    networks:
      - front-tier
      - back-tier

  monitoring:
    image: example/monitoring
    networks:
      - admin

  backend:
    image: example/backend
    networks:
      back-tier:
        aliases:
          - database
      admin:
        aliases:
          - mysql

networks:
  front-tier: {}
  back-tier: {}
  admin: {}
```

#### `interface_name`

{{< summary-bar feature_name="Compose interface-name" >}}

`interface_name` lets you specify the name of the network interface used to connect a service to a given network. This ensures consistent and predictable interface naming across services and networks.

```yaml
services:
  backend:
    image: alpine
    command: ip link show
    networks:
      back-tier:
        interface_name: eth0
```

Running the example Compose application shows:

```console
backend-1  | 11: eth0@if64: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
```

#### `ipv4_address`, `ipv6_address`

Specify a static IP address for a service container when joining the network.

The corresponding network configuration in the [top-level networks section](networks.md) must have an
`ipam` attribute with subnet configurations covering each static address.

```yml
services:
  frontend:
    image: example/webapp
    networks:
      front-tier:
        ipv4_address: 172.16.238.10
        ipv6_address: 2001:3984:3989::10

networks:
  front-tier:
    ipam:
      driver: default
      config:
        - subnet: "172.16.238.0/24"
        - subnet: "2001:3984:3989::/64"
```

#### `link_local_ips`

`link_local_ips` specifies a list of link-local IPs. Link-local IPs are special IPs which belong to a well
known subnet and are purely managed by the operator, usually dependent on the architecture where they are
deployed.

Example:

```yaml
services:
  app:
    image: busybox
    command: top
    networks:
      app_net:
        link_local_ips:
          - 57.123.22.11
          - 57.123.22.13
networks:
  app_net:
    driver: bridge
```

#### `mac_address`

{{< summary-bar feature_name="Compose mac address" >}}

`mac_address` sets the Mac address used by the service container when connecting to this particular network.

#### `driver_opts`

`driver_opts` specifies a list of options as key-value pairs to pass to the driver. These options are
driver-dependent. Consult the driver's documentation for more information.

```yml
services:
  app:
    networks:
      app_net:
        driver_opts:
          foo: "bar"
          baz: 1
```

#### `gw_priority`

{{< summary-bar feature_name="Compose gw priority" >}}

The network with the highest `gw_priority` is selected as the default gateway for the service container.
If unspecified, the default value is 0.

In the following example, `app_net_2` will be selected as the default gateway.

```yaml
services:
  app:
    image: busybox
    command: top
    networks:
      app_net_1:
      app_net_2:
        gw_priority: 1
      app_net_3:
networks:
  app_net_1:
  app_net_2:
  app_net_3:
```

#### `priority`

`priority` indicates in which order Compose connects the service’s containers to its
networks. If unspecified, the default value is 0.

If the container runtime accepts a `mac_address` attribute at service level, it is
applied to the network with the highest `priority`. In other cases, use attribute
`networks.mac_address`.

`priority` does not affect which network is selected as the default gateway. Use the
[`gw_priority`](#gw_priority) attribute instead.

`priority` does not control the order in which networks connections are added to
the container, it cannot be used to determine the device name (`eth0` etc.) in the
container.

```yaml
services:
  app:
    image: busybox
    command: top
    networks:
      app_net_1:
        priority: 1000
      app_net_2:

      app_net_3:
        priority: 100
networks:
  app_net_1:
  app_net_2:
  app_net_3:
```

### `oom_kill_disable`

If `oom_kill_disable` is set, Compose configures the platform so it won't kill the container in case
of memory starvation.

### `oom_score_adj`

`oom_score_adj` tunes the preference for containers to be killed by platform in case of memory starvation. Value must
be within -1000,1000 range.

### `pid`

`pid` sets the PID mode for container created by Compose.
Supported values are platform specific.

### `pids_limit`

`pids_limit` tunes a container’s PIDs limit. Set to -1 for unlimited PIDs.

```yml
pids_limit: 10
```

When set, `pids_limit` must be consistent with the `pids` attribute in the [Deploy Specification](deploy.md#pids).

### `platform`

`platform` defines the target platform the containers for the service run on. It uses the `os[/arch[/variant]]` syntax.

The values of `os`, `arch`, and `variant` must conform to the convention used by the [OCI Image Spec](https://github.com/opencontainers/image-spec/blob/v1.0.2/image-index.md).

Compose uses this attribute to determine which version of the image is pulled
and/or on which platform the service’s build is performed.

```yml
platform: darwin
platform: windows/amd64
platform: linux/arm64/v8
```

### `ports`

{{% include "compose/services-ports.md" %}}

> [!NOTE]
>
> Port mapping must not be used with `network_mode: host`. Doing so causes a runtime error because `network_mode: host` already exposes container ports directly to the host network, so port mapping isn’t needed.

#### Short syntax

The short syntax is a colon-separated string to set the host IP, host port, and container port
in the form:

`[HOST:]CONTAINER[/PROTOCOL]` where:

- `HOST` is `[IP:](port | range)` (optional). If it is not set, it binds to all network interfaces (`0.0.0.0`).
- `CONTAINER` is `port | range`.
- `PROTOCOL` restricts ports to a specified protocol either `tcp` or `udp`(optional). Default is `tcp`.

> [!WARNING]
>
> If you do not specify a host IP (such as `127.0.0.1`), Docker binds to all interfaces (`0.0.0.0`), bypassing host firewall rules. This can expose the container directly to the internet if the host has a public IP address. For more information, see [Port publishing and mapping](../../engine/network/port-publishing.md).

Ports can be either a single value or a range. `HOST` and `CONTAINER` must use equivalent ranges.

You can either specify both ports (`HOST:CONTAINER`), or just the container port. In the latter case,
the container runtime automatically allocates any unassigned port of the host.

`HOST:CONTAINER` should always be specified as a (quoted) string, to avoid conflicts
with [YAML base-60 float](https://yaml.org/type/float.html).



IPv6 addresses can be enclosed in square brackets.

Examples:

```yml
ports:
  - "3000"
  - "3000-3005"
  - "8000:8000"
  - "9090-9091:8080-8081"
  - "49100:22"
  - "8000-9000:80"
  - "127.0.0.1:8001:8001"
  - "127.0.0.1:5000-5010:5000-5010"
  - "::1:6000:6000"
  - "[::1]:6001:6001"
  - "6060:6060/udp"
```

> [!NOTE]
>
> If host IP mapping is not supported by a container engine, Compose rejects
> the Compose file and ignores the specified host IP.

#### Long syntax

The long form syntax lets you configure additional fields that can't be
expressed in the short form.

- `target`: The container port.
- `published`: The publicly exposed port. It is defined as a string and can be set as a range using syntax `start-end`. It means the actual port is assigned a remaining available port, within the set range.
- `host_ip`: The host IP mapping. If it is not set, it binds to all network interfaces (`0.0.0.0`).
- `protocol`: The port protocol (`tcp` or `udp`). Defaults to `tcp`.
- `app_protocol`: The application protocol (TCP/IP level 4 / OSI level 7) this port is used for. This is optional and can be used as a hint for Compose to offer richer behavior for protocols that it understands. Introduced in Docker Compose version [2.26.0](https://github.com/docker/compose/releases/tag/v2.26.0).
- `mode`: Specifies how the port is published in a Swarm setup. If set to `host`, it publishes the port on every node in Swarm. If set to `ingress`, it allows load balancing across the nodes in Swarm. Defaults to `ingress`.
- `name`: A human-readable name for the port, used to document its usage within the service.

```yml
ports:
  - name: web
    target: 80
    host_ip: 127.0.0.1
    published: "8080"
    protocol: tcp
    app_protocol: http
    mode: host

  - name: web-secured
    target: 443
    host_ip: 127.0.0.1
    published: "8083-9000"
    protocol: tcp
    app_protocol: https
    mode: host
```

### `post_start`

{{< summary-bar feature_name="Compose post start" >}}

`post_start` defines a sequence of lifecycle hooks to run after a container has started. The exact timing of when the command is run is not guaranteed.

- `command`: Specifies the command to run once the container starts. This attribute is required, and you can choose to use either the shell form or the exec form.
- `user`: The user to run the command. If not set, the command is run with the same user as the main service command.
- `privileged`: Lets the `post_start` command run with privileged access.
- `working_dir`: The working directory in which to run the command. If not set, it is run in the same working directory as the main service command.
- `environment`: Sets environment variables specifically for the `post_start` command. While the command inherits the environment variables defined for the service’s main command, this section lets you add new variables or override existing ones.

```yaml
services:
  test:
    post_start:
      - command: ./do_something_on_startup.sh
        user: root
        privileged: true
        environment:
          - FOO=BAR
```

For more information, see [Use lifecycle hooks](../../compose/how-tos/lifecycle.md).

### pre_start

{{< summary-bar feature_name="Compose pre_start" >}}

`pre_start` defines a sequence of init containers to run before the service container is started. Each step runs to completion, in declared order, and the service container only starts once every step has exited `0`. A non-zero exit fails the bring-up of the service and its dependents.

Unlike `post_start` and `pre_stop`, which run a command inside the running service container, each `pre_start` step runs in its own ephemeral container, created after the service container is created but before it is started. Possible values are:

- `command`: The command to run. Optional when the chosen image's entrypoint already runs the intended command.
- `image`: The image used for the ephemeral container. If omitted, the parent service's image is used.
- `user`: The user to run the command. If not set, defaults to the user declared in `image` (or to the main service command's user when `image` is omitted).
- `privileged`: Lets the `pre_start` command run with privileged access.
- `working_dir`: The working directory in which to run the command. If not set, it is run in the same working directory as the main service command.
- `environment`: Sets the environment variables to run the `pre_start` command. The command inherits the `environment` set for the service's main command, and this section lets you append or override values.
- `per_replica: false`: Whether the step runs once for the service as a whole before any replica starts.

`pre_start` steps only run once the service's `depends_on` conditions have been satisfied, so a step can rely on those dependencies the same way the main service command does. A`pre_start` container joins the same networks as the service, so it can reach services declared in `depends_on`, and shares the service's declared volume mounts so files it produces in a shared volume are visible to the service. 

With `per_replica: false` and a scaled service, only mounts that are shared across replicas (named volumes, bind mounts) are usable. Per-instance mounts (`tmpfs`, anonymous volumes) cannot be addressed by a single run. This is not an error. The steps run without access to per-instance mounts. Data a `per_replica: false` step must share with the service belongs in a named volume or bind mount.

A `pre_start` step that has already succeeded for its current definition is not re-run on a subsequent `up`, nor when the service container restarts under its `restart` policy. A step runs again when its definition changes, when the previous run did not succeed, or when the service is recreated. For example, after a change to the service configuration or an explicit forced recreation.

```yaml
services:
  app:
    image: myapp:latest
    depends_on:
      db:
        condition: service_healthy
    pre_start:
      - command: ["./manage.py", "migrate"]
      - image: busybox
        command: sh -c 'chown -R 1000:1000 /data'
    volumes:
      - data:/data

  db:
    image: postgres:16

volumes:
  data:
```

### `pre_stop`

{{< summary-bar feature_name="Compose pre stop" >}}

`pre_stop` defines a sequence of lifecycle hooks to run before the container is stopped. These hooks won't run if the container stops by itself or is terminated suddenly.

Configuration is equivalent to [`post_start`](#post_start).

### `privileged`

`privileged` configures the service container to run with elevated privileges. Support and actual impacts are platform specific.

### `profiles`

`profiles` defines a list of named profiles for the service to be enabled under. If unassigned, the service is always started but if assigned, it is only started if the profile is activated.

If present, `profiles` follow the regex format of `[a-zA-Z0-9][a-zA-Z0-9_.-]+`.

```yaml
services:
  frontend:
    image: frontend
    profiles: ["frontend"]

  phpmyadmin:
    image: phpmyadmin
    depends_on:
      - db
    profiles:
      - debug
```

### `provider`

{{< summary-bar feature_name="Compose provider services" >}}

`provider` can be used to define a service that Compose won't manage directly. Compose delegated the service lifecycle to a dedicated or third-party component.

```yaml
  database:
    provider:
      type: awesomecloud
      options:
        type: mysql
        foo: bar
  app:
    image: myapp
    depends_on:
       - database
```

As Compose runs the application, the `awesomecloud` binary is used to manage the `database` service setup.
Dependent service `app` receives additional environment variables prefixed by the service name so it can access the resource.

For illustration, assuming `awesomecloud` execution produced variables `URL` and `API_KEY`, the `app` service
runs with environment variables `DATABASE_URL` and `DATABASE_API_KEY`.

As Compose stops the application, the `awesomecloud` binary is used to manage the `database` service tear down.

The mechanism used by Compose to delegate the service lifecycle to an external binary is described in the [Compose extensibility documentation](https://github.com/docker/compose/tree/main/docs/extension.md).

For more information on using the `provider` attribute, see [Use provider services](../../compose/how-tos/provider-services.md).

#### `type`

`type` attribute is required. It defines the external component used by Compose to manage setup and tear down lifecycle
events.

#### `options`

`options` are specific to the selected provider and not validated by the compose specification

### `pull_policy`

`pull_policy` defines the decisions Compose makes when it starts to pull images. Possible values are:

- `always`: Compose always pulls the image from the registry.
- `never`: Compose doesn't pull the image from a registry and relies on the platform cached image.
   If there is no cached image, a failure is reported.
- `missing`: Compose pulls the image only if it's not available in the platform cache.
   This is the default option if you are not also using the [Compose Build Specification](build.md).
  `if_not_present` is considered an alias for this value for backward compatibility. The `latest` tag is always pulled even when the `missing` pull policy is used.
- `build`: Compose builds the image. Compose rebuilds the image if it's already present.
- `daily`: Compose checks the registry for image updates if the last pull took place more than 24 hours ago.
- `weekly`: Compose checks the registry for image updates if the last pull took place more than 7 days ago.
- `every_<duration>`: Compose checks the registry for image updates if the last pull took place before `<duration>`. Duration can be expressed in weeks (`w`), days (`d`), hours (`h`), minutes (`m`), seconds (`s`) or a combination of these.

```yaml
services:
  test:
    image: nginx
    pull_policy: every_12h
```

### `read_only`

`read_only` configures the service container to be created with a read-only filesystem.

### `restart`

`restart` defines the policy that the platform applies on container termination.

- `no`: The default restart policy. It does not restart the container under any circumstances.
- `always`: The policy always restarts the container until its removal.
- `on-failure[:max-retries]`: The policy restarts the container if the exit code indicates an error.
Optionally, limit the number of restart retries the Docker daemon attempts.
- `unless-stopped`: The policy restarts the container irrespective of the exit code but stops
  restarting when the service is stopped or removed.

```yml
    restart: "no"
    restart: always
    restart: on-failure
    restart: on-failure:3
    restart: unless-stopped
```

You can find more detailed information on restart policies in the
[Restart Policies (--restart)](/reference/cli/docker/container/run/#restart)
section of the Docker run reference page.

### `runtime`

`runtime` specifies which runtime to use for the service’s containers.

For example, `runtime` can be the name of [an implementation of OCI Runtime Spec](https://github.com/opencontainers/runtime-spec/blob/master/implementations.md), such as "runc".

```yml
web:
  image: busybox:latest
  command: true
  runtime: runc
```

The default is `runc`. To use a different runtime, see [Alternative runtimes](../../engine/daemon/alternative-runtimes.md).

### `scale`

`scale` specifies the default number of containers to deploy for this service.
When both are set, `scale` must be consistent with the `replicas` attribute in the [Deploy Specification](deploy.md#replicas).

### `secrets`

{{% include "compose/services-secrets.md" %}}

Two different syntax variants are supported; the short syntax and the long syntax. Long and short syntax for secrets may be used in the same Compose file.

Compose reports an error if the secret doesn't exist on the platform or isn't defined in the
[`secrets` top-level section](secrets.md) of the Compose file.

Defining a secret in the top-level `secrets` must not imply granting any service access to it.
Such grant must be explicit within service specification as [secrets](secrets.md) service element.

#### Short syntax

The short syntax variant only specifies the secret name. This grants the
container access to the secret and mounts it as read-only to `/run/secrets/<secret_name>`
within the container. The source name and destination mountpoint are both set
to the secret name.

The following example uses the short syntax to grant the `frontend` service
access to the `server-certificate` secret. The value of `server-certificate` is set
to the contents of the file `./server.cert`.

```yml
services:
  frontend:
    image: example/webapp
    secrets:
      - server-certificate
secrets:
  server-certificate:
    file: ./server.cert
```

#### Long syntax

The long syntax provides more granularity in how the secret is created within
the service's containers.

- `source`: The name of the secret as it exists on the platform.
- `target`: The name of the file to be mounted in `/run/secrets/` in the
  service's task container, or absolute path of the file if an alternate location is required. Defaults to `source` if not specified.
- `uid` and `gid`: The numeric uid or gid that owns the file within
  `/run/secrets/` in the service's task containers.
- `mode`: The [permissions](https://wintelguy.com/permissions-calc.pl) for the file to be mounted in `/run/secrets/`
  in the service's task containers, in octal notation.
  The default value is world-readable permissions (mode `0444`).
  The writable bit must be ignored if set. The executable bit may be set.

Note that support for `uid`, `gid`, and `mode` attributes are only implemented in Docker Compose when the source of the secret is [`environment`](secrets.md). When the source is a [`file`](secrets.md), Compose uses a bind-mount under the hood which doesn't allow `uid` remapping, and these attributes are silently ignored.

The following example sets the name of the `my-token` secret file within the container,
sets the mode to `0440` (group-readable), and sets the user and group to `103`.
The value of `my-token` is read from the `MY_TOKEN` environment variable.

```yml
services:
  frontend:
    image: example/webapp
    secrets:
      - source: my-token
        uid: "103"
        gid: "103"
        mode: 0o440
secrets:
  my-token:
    environment: "MY_TOKEN"
```

### `security_opt`

`security_opt` overrides the default labeling scheme for each container.

Options accept either `option=value` or `option:value` syntax. For boolean options
such as `no-new-privileges`, the value may be omitted entirely, in which case the
option is treated as enabled. The following syntaxes are all equivalent:

```yml
security_opt:
  - no-new-privileges
  - no-new-privileges=true
  - no-new-privileges:true
```

```yml
security_opt:
  - label=user:USER
  - label=role:ROLE
```

For further default labeling schemes you can override, see [Security configuration](/reference/cli/docker/container/run/#security-opt).

### `shm_size`

`shm_size` configures the size of the shared memory (`/dev/shm` partition on Linux) allowed by the service container.
It's specified as a [byte value](extension.md#specifying-byte-values).

### `stdin_open`

`stdin_open` configures a service's container to run with an allocated stdin. This is the same as running a container with the
`-i` flag. For more information, see [Keep stdin open](/reference/cli/docker/container/run/#interactive).

Supported values are `true` or `false`.

### `stop_grace_period`

`stop_grace_period` specifies how long Compose must wait when attempting to stop a container if it doesn't
handle SIGTERM (or whichever stop signal has been specified with
[`stop_signal`](#stop_signal)), before sending SIGKILL. It's specified
as a [duration](extension.md#specifying-durations).

```yml
    stop_grace_period: 1s
    stop_grace_period: 1m30s
```

Default value is 10 seconds for the container to exit before sending SIGKILL.

### `stop_signal`

`stop_signal` defines the signal that Compose uses to stop the service containers.
If unset containers are stopped by Compose by sending `SIGTERM`.

```yml
stop_signal: SIGUSR1
```

### `storage_opt`

`storage_opt` defines storage driver options for a service.

```yml
storage_opt:
  size: '1G'
```

### `sysctls`

`sysctls` defines kernel parameters to set in the container. `sysctls` can use either an array or a map.

```yml
sysctls:
  net.core.somaxconn: 1024
  net.ipv4.tcp_syncookies: 0
```

```yml
sysctls:
  - net.core.somaxconn=1024
  - net.ipv4.tcp_syncookies=0
```

You can only use sysctls that are namespaced in the kernel. Docker does not
support changing sysctls inside a container that also modify the host system.
For an overview of supported sysctls, refer to [configure namespaced kernel
parameters (sysctls) at runtime](/reference/cli/docker/container/run/#sysctl).

### `tmpfs`

`tmpfs` mounts a temporary file system inside the container. It can be a single value or a list.

```yml
tmpfs:
 - <path>
 - <path>:<options>
```

- `path`: The path inside the container where the tmpfs will be mounted.
- `options`: Comma-separated list of options for the tmpfs mount.

Available options:

- `mode`: Sets the file system permissions.
- `uid`: Sets the user ID that owns the mounted tmpfs.
- `gid`: Sets the group ID that owns the mounted tmpfs.

```yml
services:
  app:
    tmpfs:
      - /data:mode=755,uid=1009,gid=1009
      - /run
```

### `tty`

`tty` configures a service's container to run with a TTY. This is the same as running a container with the
`-t` or `--tty` flag. For more information, see [Allocate a pseudo-TTY](/reference/cli/docker/container/run/#tty).

Supported values are `true` or `false`.

### `ulimits`

`ulimits` overrides the default `ulimits` for a container. It's specified either as an integer for a single limit
or as mapping for soft/hard limits.

```yml
ulimits:
  nproc: 65535
  nofile:
    soft: 20000
    hard: 40000
```

### `use_api_socket`

When `use_api_socket` is set, the container is able to interact with the underlying container engine through the API socket.
Your credentials are mounted inside the container so the container acts as a pure delegate for your commands relating to the container engine.
Typically, commands ran by container can `pull` and `push` to your registry.

### `user`

`user` overrides the user used to run the container process. The default is set by the image, for example Dockerfile `USER`. If it's not set, then `root`.

### `userns_mode`

`userns_mode` sets the user namespace for the service. Supported values are platform specific and may depend
on platform configuration.

```yml
userns_mode: "host"
```

### `uts`

{{< summary-bar feature_name="Compose uts" >}}

`uts` configures the UTS namespace mode set for the service container. When unspecified
it is the runtime's decision to assign a UTS namespace, if supported. Available values are:

- `'host'`: Results in the container using the same UTS namespace as the host.

```yml
    uts: "host"
```

### `volumes`

{{% include "compose/services-volumes.md" %}}

The following example shows a named volume (`db-data`) being used by the `backend` service,
and a bind mount defined for a single service.

```yml
services:
  backend:
    image: example/backend
    volumes:
      - type: volume
        source: db-data
        target: /data
        volume:
          nocopy: true
          subpath: sub
      - type: bind
        source: /var/run/postgres/postgres.sock
        target: /var/run/postgres/postgres.sock

volumes:
  db-data:
```

For more information about the `volumes` top-level element, see [Volumes](volumes.md).

#### Short syntax

The short syntax uses a single string with colon-separated values to specify a volume mount
(`VOLUME:CONTAINER_PATH`), or an access mode (`VOLUME:CONTAINER_PATH:ACCESS_MODE`).

- `VOLUME`: Can be either a host path on the platform hosting containers (bind mount) or a volume name.
- `CONTAINER_PATH`: The path in the container where the volume is mounted.
- `ACCESS_MODE`: A comma-separated `,` list of options:
  - `rw`: Read and write access. This is the default if none is specified.
  - `ro`: Read-only access.
  - `z`: SELinux option indicating that the bind mount host content is shared among multiple containers.
  - `Z`: SELinux option indicating that the bind mount host content is private and unshared for other containers.

> [!NOTE]
>
> The SELinux re-labeling bind mount option is ignored on platforms without SELinux.

> [!NOTE]
> Relative host paths are only supported by Compose that deploy to a
> local container runtime. This is because the relative path is resolved from the Compose file’s parent
> directory which is only applicable in the local case. When Compose deploys to a non-local
> platform it rejects Compose files which use relative host paths with an error. To avoid ambiguities
> with named volumes, relative paths should always begin with `.` or `..`.

> [!NOTE]
>
> For bind mounts, the short syntax creates a directory at the source path on the host if it doesn't exist. This is for backward compatibility with `docker-compose` legacy.
> It can be prevented by using long syntax and setting `create_host_path` to `false`.

#### Long syntax

The long form syntax lets you configure additional fields that can't be
expressed in the short form.

- `type`: The mount type. Either `volume`, `bind`, `tmpfs`, `image`, `npipe`, or `cluster`
- `source`: The source of the mount, a path on the host for a bind mount, a Docker image reference for an image mount, or the
  name of a volume defined in the
  [top-level `volumes` key](volumes.md). Not applicable for a tmpfs mount.
- `target`: The path in the container where the volume is mounted.
- `read_only`: Flag to set the volume as read-only.
- `bind`: Used to configure additional bind options:
  - `propagation`: The propagation mode used for the bind.
  - `create_host_path`: Creates a directory at the source path on host if there is nothing present. Defaults to `true`.
  - `selinux`: The SELinux re-labeling option `z` (shared) or `Z` (private)
- `volume`: Configures additional volume options:
  - `nocopy`: Flag to disable copying of data from a container when a volume is created.
  - `subpath`: Path inside a volume to mount instead of the volume root.
- `tmpfs`: Configures additional tmpfs options:
  - `size`: The size for the tmpfs mount in bytes (either numeric or as bytes unit).
  - `mode`: The file mode for the tmpfs mount as Unix permission bits as an octal number. Introduced in Docker Compose version [2.14.0](https://github.com/docker/compose/releases/tag/v2.14.0).
- `image`: Configures additional image options:
  - `subpath`: Path inside the source image to mount instead of the image root. Available in [Docker Compose version 2.35.0](https://github.com/docker/compose/releases/tag/v2.35.0)
- `consistency`: The consistency requirements of the mount. Available values are platform specific.

> [!TIP]
>
> Working with large repositories or monorepos, or with virtual file systems that are no longer scaling with your codebase?
> Compose now takes advantage of [Synchronized file shares](../../desktop/features/synchronized-file-sharing.md) and automatically creates file shares for bind mounts.
> Ensure you're signed in to Docker with a paid subscription and have enabled both **Access experimental features** and **Manage Synchronized file shares with Compose** in Docker Desktop's settings.

### `volumes_from`

`volumes_from` mounts all of the volumes from another service or container. You can optionally specify
read-only access `ro` or read-write `rw`. If no access level is specified, then read-write access is used.

You can also mount volumes from a container that is not managed by Compose by using the `container:` prefix.

```yaml
volumes_from:
  - service_name
  - service_name:ro
  - container:container_name
  - container:container_name:rw
```

### `working_dir`

`working_dir` overrides the container's working directory which is specified by the image, for example Dockerfile's `WORKDIR`.


---

# Version and name top-level elements

*Sección: Reference*

## Version top-level element (obsolete)

> [!IMPORTANT]
>
> The top-level `version` property is defined by the Compose Specification for backward compatibility. It is only informative and you'll receive a warning message that it is obsolete if used. 

Compose always uses the most recent schema to validate the Compose file, regardless of the `version` field.

Compose validates whether it can fully parse the Compose file. If some fields are unknown, typically
because the Compose file was written with fields defined by a newer version of the Specification, you'll receive a warning message. 

## Name top-level element

The top-level `name` property is defined by the Compose Specification as the project name to be used if you don't set one explicitly.

Compose offers a way for you to override this name, and sets a
default project name to be used if the top-level `name` element is not set.

Whenever a project name is defined by top-level `name` or by some custom mechanism, it is exposed for
[interpolation](interpolation.md) and environment variable resolution as `COMPOSE_PROJECT_NAME`

```yml
name: myapp

services:
  foo:
    image: busybox
    command: echo "I'm running ${COMPOSE_PROJECT_NAME}"
```

For more information on other ways to name Compose projects, see [Specify a project name](../../compose/how-tos/project-name.md).


---

# Define and manage volumes in Docker Compose

*Sección: Reference*

{{% include "compose/volumes.md" %}}

To use a volume across multiple services, you must explicitly grant each service access by using the [volumes](services.md#volumes) attribute within the `services` top-level element. The `volumes` attribute has additional syntax that provides more granular control.

> [!TIP]
>
> Working with large repositories or monorepos, or with virtual file systems that are no longer scaling with your codebase? 
> Compose now takes advantage of [Synchronized file shares](../../desktop/features/synchronized-file-sharing.md) and automatically creates file shares for bind mounts. 
> Ensure you're signed in to Docker with a paid subscription and have enabled both **Access experimental features** and **Manage Synchronized file shares with Compose** in Docker Desktop's settings.

## Example

The following example shows a two-service setup where a database's data directory is shared with another service as a volume, named
`db-data`, so that it can be periodically backed up.

```yml
services:
  backend:
    image: example/database
    volumes:
      - db-data:/etc/data

  backup:
    image: backup-service
    volumes:
      - db-data:/var/lib/backup/data

volumes:
  db-data:
```

The `db-data` volume is mounted at the `/var/lib/backup/data` and `/etc/data` container paths for backup and backend respectively.

Running `docker compose up` creates the volume if it doesn't already exist. Otherwise, the existing volume is used and is recreated if it's manually deleted outside of Compose.

## Attributes

An entry under the top-level `volumes` section can be empty, in which case it uses the container engine's default configuration for
creating a volume. Optionally, you can configure it with the following keys:

### `driver`

Specifies which volume driver should be used. If the driver is not available, Compose returns an error and doesn't deploy the application.

```yml
volumes:
  db-data:
    driver: foobar
```

### `driver_opts`

`driver_opts` specifies a list of options as key-value pairs to pass to the driver for this volume. The options are driver-dependent.

```yml
volumes:
  example:
    driver_opts:
      type: "nfs"
      o: "addr=10.40.0.199,nolock,soft,rw"
      device: ":/docker/example"
```

If you want a named bind mount, use the `local` driver with `driver_opts`. This pattern gives a Compose volume a stable name while mapping it to a specific host path:

```yaml
volumes:
  app-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /srv/app-data # must be the absolute host path and already exist
```

The `type`, `o`, and `device` keys are passed through to the local driver. For a one-off host-path mount on a single service, see [bind mounts](../../engine/storage/bind-mounts.md).

### `external`

If set to `true`:
 - `external` specifies that this volume already exists on the platform and its lifecycle is managed outside
of that of the application. Compose then doesn't create the volume and returns an error if the volume doesn't exist.
 - All other attributes apart from `name` are irrelevant. If Compose detects any other attribute, it rejects the Compose file as invalid.

In the following example, instead of attempting to create a volume called
`{project_name}_db-data`, Compose looks for an existing volume simply
called `db-data` and mounts it into the `backend` service's containers.

```yml
services:
  backend:
    image: example/database
    volumes:
      - db-data:/etc/data

volumes:
  db-data:
    external: true
```

### `labels`

`labels` are used to add metadata to volumes. You can use either an array or a dictionary.

It's recommended that you use reverse-DNS notation to prevent your labels from conflicting with those used by other software.

```yml
volumes:
  db-data:
    labels:
      com.example.description: "Database volume"
      com.example.department: "IT/Ops"
      com.example.label-with-empty-value: ""
```

```yml
volumes:
  db-data:
    labels:
      - "com.example.description=Database volume"
      - "com.example.department=IT/Ops"
      - "com.example.label-with-empty-value"
```

Compose sets `com.docker.compose.project` and `com.docker.compose.volume` labels.

> [!NOTE]
>
> Labels defined here apply to named volumes only. They’re stored on the volume resource and visible via `docker volume inspect`. They do not apply to bind mounts and do not change mount semantics.

### `name`

`name` sets a custom name for a volume. The name field can be used to reference volumes that contain special
characters. The name is used as is and is not scoped with the stack name.

```yml
volumes:
  db-data:
    name: "my-app-data"
```

This makes it possible to make this lookup name a parameter of the Compose file, so that the model ID for the volume is hard-coded but the actual volume ID on the platform is set at runtime during deployment. 

For example, if `DATABASE_VOLUME=my_volume_001` is in your `.env` file:

```yml
volumes:
  db-data:
    name: ${DATABASE_VOLUME}
```

Running `docker compose up` uses the volume called `my_volume_001`. 

It can also be used in conjunction with the `external` property. This means the name used to look up the actual volume on the platform is set separately from the name used to refer to the volume within the Compose file:

```yml
volumes:
  db-data:
    external: true
    name: actual-name-of-volume
```


---

# Glossary

*Sección: Reference*

<!--
To edit/add/remove glossary entries, visit the YAML file at:
https://github.com/docker/docs/blob/main/data/glossary.yaml
-->


---

# Samples overview

*Sección: Reference*

Learn how to containerize different types of services by walking through Official Docker samples.

## Databases

[MariaDB](mariadb.md) \| [MongoDB](mongodb.md) \| [MS-SQL](ms-sql.md) \| [MySQL](mysql.md) \| [PostgreSQL](postgres.md) \| [Redis](redis.md)

## Frameworks

[.NET](dotnet.md) \| [Angular](angular.md) \| [Django](django.md) \| [Express](express.md) \|[FastAPI](fastapi.md) \| [Flask](flask.md) \| [Node.js](nodejs.md) \| [React](react.md) \| [Rails](rails.md) \| [Spark](spark.md) \| [Spring Boot](spring.md) \| [Vue.js](vuejs.md)

## Languages

[Go](go.md) \| [Java](java.md) \| [JavaScript](javascript.md) \| [PHP](php.md) \| [Python](python.md) \| [Ruby](ruby.md) \| [Rust](rust.md) \| [TypeScript](typescript.md)

## Platforms

[Gitea](gitea.md) \| [Nextcloud](nextcloud.md) \| [Portainer](portainer.md) \|  [Prometheus](prometheus.md) \| [WordPress](wordpress.md)

## Other samples

[Agentic AI](agentic-ai.md) \| [AI/ML](ai-ml.md) \| [Cloudflared](cloudflared.md) \| [Elasticsearch / Logstash / Kibana](elasticsearch.md) \| [Minecraft](minecraft.md) \| [NGINX](nginx.md) \| [Pi-hole](pi-hole.md) \| [Plex](plex.md) \| [Traefik](traefik.md) \| [WireGuard](wireguard.md)


---

# Agentic AI samples

*Sección: Reference*




---

# AI/ML samples

*Sección: Reference*




---

# Angular samples

*Sección: Reference*




---

# Cloudflared samples

*Sección: Reference*




---

# Django samples

*Sección: Reference*




---

# .NET samples

*Sección: Reference*




---

# Elasticsearch / Logstash / Kibana samples

*Sección: Reference*




---

# Express samples

*Sección: Reference*




---

# FastAPI samples

*Sección: Reference*




---

# Flask samples

*Sección: Reference*




---

# Gitea samples

*Sección: Reference*




---

# Go samples

*Sección: Reference*




---

# Java samples

*Sección: Reference*




---

# JavaScript samples

*Sección: Reference*




---

# MariaDB samples

*Sección: Reference*




---

# Minecraft samples

*Sección: Reference*




---

# MongoDB samples

*Sección: Reference*




---

# MS-SQL samples

*Sección: Reference*




---

# MySQL samples

*Sección: Reference*




---

# Nextcloud samples

*Sección: Reference*




---

# NGINX samples

*Sección: Reference*




---

# Node.js samples

*Sección: Reference*




---

# PHP samples

*Sección: Reference*




---

# Pi-hole samples

*Sección: Reference*




---

# Plex samples

*Sección: Reference*




---

# Portainer samples

*Sección: Reference*




---

# PostgreSQL samples

*Sección: Reference*




---

# Prometheus samples

*Sección: Reference*




---

# Python samples

*Sección: Reference*




---

# Rails samples

*Sección: Reference*




---

# React samples

*Sección: Reference*




---

# Redis samples

*Sección: Reference*




---

# Ruby samples

*Sección: Reference*




---

# Rust samples

*Sección: Reference*




---

# Spark samples

*Sección: Reference*




---

# Spring Boot samples

*Sección: Reference*




---

# Traefik samples

*Sección: Reference*




---

# TypeScript samples

*Sección: Reference*




---

# Vue.js samples

*Sección: Reference*




---

# WireGuard samples

*Sección: Reference*




---

# WordPress samples

*Sección: Reference*




---

# Docker Scout

*Sección: Scout*

Container images consist of layers and software packages, which are susceptible to vulnerabilities.
These vulnerabilities can compromise the security of containers and applications.

Docker Scout is a solution for proactively enhancing your software supply chain security.
By analyzing your images, Docker Scout compiles an inventory of components, also known as a Software Bill of Materials (SBOM).
The SBOM is matched against a continuously updated vulnerability database to pinpoint security weaknesses.

Docker Scout is a standalone service and platform that you can interact with
using Docker Hub, the Docker CLI, and the Docker Scout Dashboard.

{{< grid >}}


---

# Deep dive

*Sección: Scout*




---

# Advisory database sources and matching service

*Sección: Scout*

Reliable information sources are key for Docker Scout's ability to
surface relevant and accurate assessments of your software artifacts.
Given the diversity of sources and methodologies in the industry,
discrepancies in vulnerability assessment results can and do happen.
This page describes how the Docker Scout advisory database
and its CVE-to-package matching approach works to deal with these discrepancies.

## Advisory database sources

Docker Scout aggregates vulnerability data from multiple sources.
The data is continuously updated to ensure that your security posture
is represented using the latest available information, in real-time.

Docker Scout uses the following package repositories and security trackers:

<!-- vale off -->

- [AlmaLinux Security Advisory](https://errata.almalinux.org/)
- [Alpine secdb](https://secdb.alpinelinux.org/)
- [Amazon Linux Security Center](https://alas.aws.amazon.com/)
- [Bitnami Vulnerability Database](https://github.com/bitnami/vulndb)
- [CISA Known Exploited Vulnerability Catalog](https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
- [CISA Vulnrichment](https://github.com/cisagov/vulnrichment)
- [Chainguard Security Feed](https://packages.cgr.dev/chainguard/osv/all.json)
- [Debian Security Bug Tracker](https://security-tracker.debian.org/tracker/)
- [Exploit Prediction Scoring System (EPSS)](https://api.first.org/epss/)
- [GitHub Advisory Database](https://github.com/advisories/)
- [GitLab Advisory Database](https://gitlab.com/gitlab-org/advisories-community/)
- [Golang VulnDB](https://github.com/golang/vulndb)
- [National Vulnerability Database](https://nvd.nist.gov/)
- [Oracle Linux Security](https://linux.oracle.com/security/)
- [Photon OS 3.0 Security Advisories](https://github.com/vmware/photon/wiki/Security-Updates-3)
- [Python Packaging Advisory Database](https://github.com/pypa/advisory-database)
- [RedHat Security Data](https://www.redhat.com/security/data/metrics/)
- [Rocky Linux Security Advisory](https://errata.rockylinux.org/)
- [RustSec Advisory Database](https://github.com/rustsec/advisory-db)
- [SUSE Security CVRF](http://ftp.suse.com/pub/projects/security/cvrf/)
- [Ubuntu CVE Tracker](https://people.canonical.com/~ubuntu-security/cve/)
- [Wolfi Security Feed](https://packages.wolfi.dev/os/security.json)
- [inTheWild, a community-driven open database of vulnerability exploitation](https://github.com/gmatuz/inthewilddb)

<!-- vale on -->

When you enable Docker Scout for your Docker organization,
a new database instance is provisioned on the Docker Scout platform.
The database stores the Software Bill of Materials (SBOM) and other metadata about your images.
When a security advisory has new information about a vulnerability,
your SBOM is cross-referenced with the CVE information to detect how it affects you.

For more details on how image analysis works, see the [image analysis page](../explore/analysis.md).

## Severity and scoring priority

Docker Scout uses two main principles when determining severity and scoring for
CVEs:

   - Source priority
   - CVSS version preference

For source priority, Docker Scout follows this order:

  1. Vendor advisories: Scout always uses the severity and scoring data from the
     source that matches the package and version. For example, Debian data for
     Debian packages.

  2. NIST scoring data: If the vendor doesn't provide scoring data for a CVE,
     Scout falls back to NIST scoring data.

For CVSS version preference, once Scout has selected a source, it prefers CVSS
v4 over v3 when both are available, as v4 is the more modern and precise scoring
model.

## Vulnerability matching

Traditional tools often rely on broad [Common Product Enumeration (CPE)](https://en.wikipedia.org/wiki/Common_Platform_Enumeration) matching,
which can lead to many false-positive results.

Docker Scout uses [Package URLs (PURLs)](https://github.com/package-url/purl-spec)
to match packages against CVEs, which yields more precise identification of vulnerabilities.
PURLs significantly reduce the chances of false positives, focusing only on genuinely affected packages.

## Supported package ecosystems

Docker Scout supports the following package ecosystems:

- .NET
- GitHub packages
- Go
- Java
- JavaScript
- PHP
- Python
- RPM
- Ruby
- `alpm` (Arch Linux)
- `apk` (Alpine Linux)
- `deb` (Debian Linux and derivatives)


---

# Data collection and storage in Docker Scout

*Sección: Scout*

Docker Scout's image analysis works by collecting metadata from the container
images that you analyze. This metadata is stored on the Docker Scout platform.

## Data transmission

This section describes the data that Docker Scout collects and sends to the
platform.

### Image metadata

Docker Scout collects the following image metadata:

- Image creation timestamp
- Image digest
- Ports exposed by the image
- Environment variable names and values
- Name and value of image labels
- Order of image layers
- Hardware architecture
- Operating system type and version
- Registry URL and type

Image digests are created for each layer of an image when the image is built
and pushed to a registry. They are SHA256 digests of the contents of a layer.
Docker Scout doesn't create the digests; they're read from the image manifest.

The digests are matched against your own private images and Docker's database
of public images to identify images that share the same layers. The image that
shares most of the layers is considered a base image match for the image that's
currently being analyzed.

### SBOM metadata

Software Bill of Material (SBOM) metadata is used to match package types
and versions with vulnerability data to infer whether an image is affected.
When the Docker Scout platform receives information from security advisories
about new CVEs or other risk factors, such as leaked secrets, it cross-references
this information with the SBOM. If there's a match, Docker Scout displays the
results in the user interfaces where Docker Scout data is surfaced,
such as the Docker Scout Dashboard and in Docker Desktop.

Docker Scout collects the following SBOM metadata:

- Package URLs (PURL)
- Package author and description
- License IDs
- Package name and namespace
- Package scheme and size
- Package type and version
- Filepath within the image
- The type of direct dependency
- Total package count

The PURLs in Docker Scout follow the
[purl-spec](https://github.com/package-url/purl-spec) specification. Package
information is derived from the contents of image, including OS-level programs
and packages, and application-level packages such as maven, npm, and so on.

### Environment metadata

If you integrate Docker Scout with your runtime environment via the
[CLI integration](../integrations/environment/cli.md),
Docker Scout collects the following data points about your deployments:

- Kubernetes namespace
- Workload name
- Workload type (for example, DaemonSet)

### Local analysis

For images analyzed locally on a developer's machine, Docker Scout only
transmits PURLs and layer digests. This data isn't persistently stored on the
Docker Scout platform; it's only used to run the analysis.

### Provenance

For images with [provenance attestations](../../build/metadata/attestations/slsa-provenance.md),
Docker Scout stores the following data in addition to the SBOM:

- Materials
- Base image
- VCS information
- Dockerfile

## Data storage

For the purposes of providing the Docker Scout service, data is stored using:

- Amazon Web Services (AWS) on servers located in US East
- Google Cloud Platform (GCP) on servers located in US East

Data is used according to the processes described at
[docker.com/legal](https://www.docker.com/legal/) to provide the key
capabilities of Docker Scout.


---

# Explore

*Sección: Scout*




---

# Docker Scout image analysis

*Sección: Scout*

When you activate image analysis for a repository,
Docker Scout automatically analyzes new images that you push to that repository.

Image analysis extracts the Software Bill of Material (SBOM)
and other image metadata,and evaluates it against vulnerability data from
[security advisories](../deep-dive/advisory-db-sources.md).

If you run image analysis as a one-off task using the CLI or Docker Desktop,
Docker Scout won't store any data about your image.
If you enable Docker Scout for your container image repositories however,
Docker Scout saves a metadata snapshot of your images after the analysis.
As new vulnerability data becomes available, Docker Scout recalibrates the analysis using the metadata snapshot, which means your security status for images is updated in real-time.
This dynamic evaluation means there's no need to re-analyze images when new CVE information is disclosed.

Docker Scout image analysis is available by default for Docker Hub repositories.
You can also integrate third-party registries and other services. To learn more,
see [Integrating Docker Scout with other systems](../integrations/index.md).

## Activate Docker Scout on a repository

See [Subscriptions and features](https://www.docker.com/pricing?ref=Docs&refAction=DocsScoutAnalysis)
to learn how many Scout-enabled repositories come with each subscription tier.

Before you can activate image analysis on a repository in a third-party registry,
the registry must be integrated with Docker Scout for your Docker organization.
Docker Hub is integrated by default. For more information, see
See [Container registry integrations](../integrations/index.md#container-registries)

> [!NOTE]
>
> You must have the **Editor** or **Owner** role in the Docker organization to
> activate image analysis on a repository.

To activate image analysis:

1. Go to [Repository settings](https://scout.docker.com/settings/repos) in the Docker Scout Dashboard.
2. Select the repositories that you want to enable.
3. Select **Enable image analysis**.

If your repositories already contain images,
Docker Scout pulls and analyzes the latest images automatically.

## Analyze registry images

To trigger image analysis for an image in a registry, push the image to a
registry that's integrated with Docker Scout, to a repository where image
analysis is activated.

> [!NOTE]
>
> Image analysis on the Docker Scout platform has a maximum image file size
> limit of 10 GB, unless the image has an SBOM attestation.
> See [Maximum image size](#maximum-image-size).

1. Sign in with your Docker ID, either using the `docker login` command or the
   **Sign in** button in Docker Desktop.
2. Build and push the image that you want to analyze.

   ```console
   $ docker build --push --tag <org>/<image:tag> --provenance=true --sbom=true .
   ```

   Building with the `--provenance=true` and `--sbom=true` flags attaches
   [build attestations](../../build/metadata/attestations/index.md) to the image. Docker
   Scout uses attestations to provide more fine-grained analysis results.

   > [!NOTE]
   >
   > The default `docker` driver only supports build attestations if you use the
   > [containerd image store](../../desktop/features/containerd.md).

3. Go to the [Images page](https://scout.docker.com/reports/images) in the Docker Scout Dashboard.

   The image appears in the list shortly after you push it to the registry.
   It may take a few minutes for the analysis results to appear.

## Analyze images locally

You can analyze local images with Docker Scout using Docker Desktop or the
`docker scout` commands for the Docker CLI.

### Docker Desktop

> [!NOTE]
>
> Docker Desktop background indexing supports images up to 10 GB in size.
> See [Maximum image size](#maximum-image-size).

To analyze an image locally using the Docker Desktop GUI:

1. Pull or build the image that you want to analyze.
2. Go to the **Images** view in the Docker Dashboard.
3. Select one of your local images in the list.

   This opens the [Image details view](image-details-view.md), showing a
   breakdown of packages and vulnerabilities found by the Docker Scout analysis
   for the image you selected.

### CLI

The `docker scout` CLI commands provide a command line interface for using Docker
Scout from your terminal.

- `docker scout quickview`: summary of the specified image, see [Quickview](#quickview)
- `docker scout cves`: local analysis of the specified image, see [CVEs](#cves)
- `docker scout compare`: analyzes and compares two images

By default, the results are printed to standard output.
You can also export results to a file in a structured format,
such as Static Analysis Results Interchange Format (SARIF).

#### Quickview

The `docker scout quickview` command provides an overview of the
vulnerabilities found in a given image and its base image.

```console
$ docker scout quickview traefik:latest
    ✓ SBOM of image already cached, 311 packages indexed

  Your image  traefik:latest  │    0C     2H     8M     1L
  Base image  alpine:3        │    0C     0H     0M     0L
```

If your the base image is out of date, the `quickview` command also shows how
updating your base image would change the vulnerability exposure of your image.

```console
$ docker scout quickview postgres:13.1
    ✓ Pulled
    ✓ Image stored for indexing
    ✓ Indexed 187 packages

  Your image  postgres:13.1                 │   17C    32H    35M    33L
  Base image  debian:buster-slim            │    9C    14H     9M    23L
  Refreshed base image  debian:buster-slim  │    0C     1H     6M    29L
                                            │    -9    -13     -3     +6
  Updated base image  debian:stable-slim    │    0C     0H     0M    17L
                                            │    -9    -14     -9     -6
```

#### CVEs

The `docker scout cves` command gives you a complete view of all the
vulnerabilities in the image. This command supports several flags that lets you
specify more precisely which vulnerabilities you're interested in, for example,
by severity or package type:

```console
$ docker scout cves --format only-packages --only-vuln-packages \
  --only-severity critical postgres:13.1
    ✓ SBOM of image already cached, 187 packages indexed
    ✗ Detected 10 vulnerable packages with a total of 17 vulnerabilities

     Name            Version         Type        Vulnerabilities
───────────────────────────────────────────────────────────────────────────
  dpkg        1.19.7                 deb      1C     0H     0M     0L
  glibc       2.28-10                deb      4C     0H     0M     0L
  gnutls28    3.6.7-4+deb10u6        deb      2C     0H     0M     0L
  libbsd      0.9.1-2                deb      1C     0H     0M     0L
  libksba     1.3.5-2                deb      2C     0H     0M     0L
  libtasn1-6  4.13-3                 deb      1C     0H     0M     0L
  lz4         1.8.3-1                deb      1C     0H     0M     0L
  openldap    2.4.47+dfsg-3+deb10u5  deb      1C     0H     0M     0L
  openssl     1.1.1d-0+deb10u4       deb      3C     0H     0M     0L
  zlib        1:1.2.11.dfsg-1        deb      1C     0H     0M     0L
```

For more information about these commands and how to use them, refer to the CLI
reference documentation:

- [`docker scout quickview`](/reference/cli/docker/scout/quickview/)
- [`docker scout cves`](/reference/cli/docker/scout/cves/)

## Vulnerability severity assessment

Docker Scout assigns a severity rating to vulnerabilities based on
vulnerability data from [advisory sources](../deep-dive/advisory-db-sources.md).
Advisories are ranked and prioritized depending on the type of package that's
affected by a vulnerability. For example, if a vulnerability affects an OS
package, the severity level assigned by the distribution maintainer is
prioritized.

If the preferred advisory source has assigned a severity rating to a CVE, but
not a CVSS score, Docker Scout falls back to displaying a CVSS score from
another source. The severity rating from the preferred advisory and the CVSS
score from the fallback advisory are displayed together. This means a
vulnerability can have a severity rating of `LOW` with a CVSS score of 9.8, if
the preferred advisory assigns a `LOW` rating but no CVSS score, and a fallback
advisory assigns a CVSS score of 9.8.

Vulnerabilities that haven't been assigned a CVSS score in any source are
categorized as **Unspecified** (U).

Docker Scout doesn't implement a proprietary vulnerability metrics system. All
metrics are inherited from security advisories that Docker Scout integrates
with. Advisories may use different thresholds for classifying vulnerabilities.
When the selected advisory source provides both CVSS v4 and v3 data, Docker
Scout prefers CVSS v4. The qualitative severity ratings defined by CVSS v3.x
and v4.0 use the same score ranges:

| CVSS score | Severity rating  |
| ---------- | ---------------- |
| 0.1 – 3.9  | **Low** (L)      |
| 4.0 – 6.9  | **Medium** (M)   |
| 7.0 – 8.9  | **High** (H)     |
| 9.0 – 10.0 | **Critical** (C) |

For more information, see [Vulnerability Metrics (NIST)](https://nvd.nist.gov/vuln-metrics/cvss).

Note that, given the advisory prioritization and fallback mechanism described
earlier, severity ratings displayed in Docker Scout may deviate from this
rating system.

## Maximum image size

Image analysis on the Docker Scout platform, and analysis triggered by background
indexing in Docker Desktop, has an image file size limit of 10 GB (uncompressed).
To analyze images larger than that:

- Attach an [SBOM attestation](../../build/metadata/attestations/sbom.md) at build-time. When an image includes an SBOM attestation, Docker Scout uses it instead of generating one, so the 10 GB limit doesn’t apply.
- Alternatively, you can use the [CLI](#cli) to analyze the image locally. The 10 GB limit doesn’t apply when using the CLI. If the image includes an SBOM attestation, the CLI uses it to complete the analysis faster.


---

# Dashboard

*Sección: Scout*

The [Docker Scout Dashboard](https://scout.docker.com/) helps you share the
analysis of images in an organization with your team. Developers can see an
overview of their security status across all their images from Docker Hub, and
get remediation advice at their fingertips. It helps team members in roles such
as security, compliance, and operations to know what vulnerabilities and issues
they need to focus on.

## Overview

![A screenshot of the Docker Scout Dashboard overview](../images/dashboard-overview.webp?border=true)

The **Overview** tab provides a summary for the repositories in the selected
organization.

At the top of this page, you can select which **Environment** to view.
By default, the most recently pushed images are shown. To learn more about
environments, see [Environment monitoring](../integrations/environment/index.md).

The vulnerability chart shows the total number of vulnerabilities for images in
the selected environment over time. You can configure the timescale for the
chart using the drop-down menu.

Use the header menu at the top of the website to access the different main
sections of the Docker Scout Dashboard:

- **Images**: lists all Docker Scout-enabled repositories in the organization, see [Images](#images)
- **Base images**: lists all base images used by repositories in an organization
- **Packages**: lists all packages across repositories in the organization
- **Vulnerabilities**: lists all CVEs in the organization's images, see [Vulnerabilities](#vulnerabilities)
- **Settings**: manage repository settings, see [Settings](#settings)

## Images

The **Images** view shows all images in Scout-enabled repositories for the selected environment.
You can filter the list by selecting a different environment, or by repository name using the text filter.

![Screenshot of the images view](../images/dashboard-images.webp)

For each repository, the list displays the following details:

- The repository name (image reference without the tag or digest)
- The most recent tag of the image in the selected environment
- Operating systems and architectures for the most recent tag
- Vulnerabilities status for the most recent tag

Selecting a repository link takes you to a list of all images in that repository that have been analyzed.
From here you can view the full analysis results for a specific image,
and compare tags to view the differences in packages and vulnerabilities

Selecting an image link takes you to a details view for the selected tag or digest.
The **Image layers** tab shows a breakdown of the image analysis results.
You can get a complete view of the vulnerabilities your image contains
and understand how they got in.

## Vulnerabilities

The **Vulnerabilities** view shows a list of all vulnerabilities for images in the organization.
This list includes details about CVE such as the severity and Common Vulnerability Scoring System (CVSS) score,
as well as whether there's a fix version available.
The CVSS score displayed here is the highest score out of all available [sources](../deep-dive/advisory-db-sources.md).

Selecting the links on this page opens the vulnerability details page,
This page is a publicly visible page, and shows detailed information about a CVE.
You can share the link to a particular CVE description with other people
even if they're not a member of your Docker organization or signed in to Docker Scout.

If you are signed in, the **My images** tab on this page lists all of your images
affected by the CVE.

## Settings

The settings menu in the Docker Scout Dashboard contains:

- [**Repository settings**](#repository-settings) for enabling and disabling repositories.

### Repository settings

When you enable Docker Scout for a repository,
Docker Scout analyzes new tags automatically when you push to that repository.
To enable repositories in third-party registries, you first need to integrate
them. See [Container registry integrations](../integrations/index.md#container-registries)


---

# Manage vulnerability exceptions

*Sección: Scout*

Vulnerabilities found in container images sometimes need additional context.
Just because an image contains a vulnerable package, it doesn't mean that the
vulnerability is exploitable. **Exceptions** in Docker Scout lets you
acknowledge accepted risks or address false positives in image analysis.

By negating non-applicable vulnerabilities, you can make it easier for yourself
and downstream consumers of your images to understand the security implications
of a vulnerability in the context of an image.

In Docker Scout, exceptions are automatically factored into the results.
If an image contains an exception that flags a CVE as non-applicable,
then that CVE is excluded from analysis results.

## Create exceptions

To create an exception for an image, you can:

- Create an exception in the [GUI](../how-tos/create-exceptions-gui.md) of
  Docker Scout Dashboard or Docker Desktop.
- Create a [VEX](../how-tos/create-exceptions-vex.md) document and attach
  it to the image.

The recommended way to create exceptions is to use Docker Scout Dashboard or
Docker Desktop. The GUI provides a user-friendly interface for creating
exceptions. It also lets you create exceptions for multiple images, or your
entire organization, all at once.

## View exceptions

To view exceptions for images, you need to have the appropriate permissions.

- Exceptions created [using the GUI](../how-tos/create-exceptions-gui.md)
  are visible to members of your Docker organization. Unauthenticated users or
  users who aren't members of your organization cannot see these exceptions.
- Exceptions created [using VEX documents](../how-tos/create-exceptions-vex.md)
  are visible to anyone who can pull the image, since the VEX document is
  stored in the image manifest or on filesystem of the image.

### View exceptions in Docker Scout Dashboard or Docker Desktop

The [**Exceptions** tab](https://scout.docker.com/reports/vulnerabilities/exceptions)
of the Vulnerabilities page in Docker Scout Dashboard lists all exceptions for
for all images in your organization. From here, you can see more details about
each exception, the CVEs being suppressed, the images that exceptions apply to,
the type of exception and how it was created, and more.

For exceptions created using the [GUI](../how-tos/create-exceptions-gui.md),
selecting the action menu lets you edit or remove the exception.

To view all exceptions for a specific image tag:

{{< tabs >}}
{{< tab name="Docker Scout Dashboard" >}}

1. Go to the [Images page](https://scout.docker.com/reports/images).
2. Select the tag that you want to inspect.
3. Open the **Exceptions** tab.

{{< /tab >}}
{{< tab name="Docker Desktop" >}}

1. Open the **Images** view in Docker Desktop.
2. Open the **Hub** tab.
3. Select the tag you want to inspect.
4. Open the **Exceptions** tab.

{{< /tab >}}
{{< /tabs >}}

### View exceptions in the CLI

{{< summary-bar feature_name="Docker Scout exceptions" >}}

Vulnerability exceptions are highlighted in the CLI when you run `docker scout
cves <image>`. If a CVE is suppressed by an exception, a `SUPPRESSED` label
appears next to the CVE ID. Details about the exception are also displayed.

![SUPPRESSED label in the CLI output](/scout/images/suppressed-cve-cli.png)

> [!IMPORTANT]
> In order to view exceptions in the CLI, you must configure the CLI to use
> the same Docker organization that you used to create the exceptions.
>
> To configure an organization for the CLI, run:
>
> ```console
> $ docker scout configure organization <organization>
> ```
>
> Replace `<organization>` with the name of your Docker organization.
>
> You can also set the organization on a per-command basis by using the
> `--org` flag:
>
> ```console
> $ docker scout cves --org <organization> <image>
> ```

To exclude suppressed CVEs from the output, use the `--ignore-suppressed` flag:

```console
$ docker scout cves --ignore-suppressed <image>
```


---

# Image details view

*Sección: Scout*

The image details view shows a breakdown of the Docker Scout analysis. You can
access the image view from the Docker Scout Dashboard, the Docker Desktop
**Images** view, and from the image tag page on Docker Hub. The image details
show a breakdown of the image hierarchy (base images), image layers, packages,
and vulnerabilities.

![The image details view in Docker Desktop](../images/dd-image-view.png)

Docker Desktop first analyzes images locally, where it generates a software bill of materials (SBOM).
Docker Desktop, Docker Hub, and the Docker Scout Dashboard and CLI all use the [package URL (PURL) links](https://github.com/package-url/purl-spec)
in this SBOM to query for matching Common Vulnerabilities and Exposures (CVEs) in [Docker Scout's advisory database](../deep-dive/advisory-db-sources.md).

## Image hierarchy

The image you inspect may have one or more base images represented under
**Image hierarchy**. This means the author of the image used other images as
starting points when building the image. Often these base images are either
operating system images such as Debian, Ubuntu, and Alpine, or programming
language images such as PHP, Python, and Java.

Selecting each image in the chain lets you see which layers originate from each
base image. Selecting the **ALL** row selects all layers and base images.

One or more of the base images may have updates available, which may include
updated security patches that remove vulnerabilities from your image. Any base
images with available updates are noted to the right of **Image hierarchy**.

## Layers

A Docker image consists of layers. Image layers are listed from top to bottom,
with the earliest layer at the top and the most recent layer at the bottom.
Often, the layers at the top of the list originate from a base image, and the
layers towards the bottom added by the image author, often using
commands in a Dockerfile. Selecting a base image under **Image hierarchy** 
highlights with layers originate from a base image.

Selecting individual or multiple layers filters the packages and vulnerabilities
on the right-hand side to show what the selected layers added.

## Vulnerabilities

The **Vulnerabilities** tab displays a list of vulnerabilities and exploits detected in the image. The list is grouped by package, and sorted in order of severity.

You can find further information on the vulnerability or exploit, including if a fix is available, by expanding the list item.

## Remediation recommendations

When you inspect an image in Docker Desktop or Docker Hub,
Docker Scout can provide recommendations for improving the security of that image.

### Recommendations in Docker Desktop

To view security recommendations for an image in Docker Desktop:

1. Go to the **Images** view in Docker Desktop.
2. Select the image tag that you want to view recommendations for.
3. Near the top, select the **Recommended fixes** drop-down button.

The drop-down menu lets you choose whether you want to see recommendations for
the current image or any base images used to build it:

- [**Recommendations for this image**](#recommendations-for-current-image)
  provides recommendations for the current image that you're inspecting.
- [**Recommendations for base image**](#recommendations-for-base-image) provides
  recommendations for base images used to build the image.

If the image you're viewing has no associated base images, the drop-down menu only 
shows the option to view recommendations for the current image.

### Recommendations in Docker Hub

To view security recommendations for an image in Docker Hub:

1. Go to the repository page for an image where you have activated Docker Scout
   image analysis.
2. Open the **Tags** tab.
3. Select the tag that you want to view recommendations for.
4. Select the **View recommended base image fixes** button.

   This opens a window which gives you recommendations for you can improve the
   security of your image by using better base images. See
   [Recommendations for base image](#recommendations-for-base-image) for more
   details.

### Recommendations for current image

The recommendations for the current image view helps you determine whether the image
version that you're using is out of date. If the tag you're using is referencing an
old digest, the view shows a recommendation to update the tag by pulling the
latest version.

Select the **Pull new image** button to get the updated version. Check the
checkbox to remove the old version after pulling the latest.

### Recommendations for base image

The base image recommendations view contains two tabs for toggling between
different types of recommendations:

- **Refresh base image**
- **Change base image**

These base image recommendations are only actionable if you're the author of the
image you're inspecting. This is because changing the base image for an image
requires you to update the Dockerfile and re-build the image.

#### Refresh base image

This tab shows if the selected base image tag is the latest available version,
or if it's outdated.

If the base image tag used to build the current image isn't the latest, then the
delta between the two versions shows in this window. The delta information
includes:

- The tag name, and aliases, of the recommended (newer) version
- The age of the current base image version
- The age of the latest available version
- The number of CVEs affecting each version

At the bottom of the window, you also receive command snippets that you can 
run to re-build the image using the latest version.

#### Change base image

This tab shows different alternative tags that you can use, and outlines the
benefits and disadvantages of each tag version. Selecting the base image shows
recommended options for that tag.

For example, if the image you're inspecting is using an old version of `debian`
as a base image, it shows recommendations for newer and more secure versions
of `debian` to use. By providing more than one alternative to choose from, you
can see for yourself how the options compare with each other, and decide which
one to use.

![Base image recommendations](../images/change-base-image.png)

Select a tag recommendation to see further details of the recommendation.
It shows the benefits and potential disadvantages of the tag, why it's a
recommended, and how to update your Dockerfile to use this version.


---

# Docker Scout metrics exporter

*Sección: Scout*

Docker Scout exposes a metrics HTTP endpoint that lets you scrape vulnerability
and policy data from Docker Scout, using Prometheus or Datadog. With this you
can create your own, self-hosted Docker Scout dashboards for visualizing supply
chain metrics.

## Metrics

The metrics endpoint exposes the following metrics:

| Metric                          | Description                                         | Labels                            | Type  |
| ------------------------------- | --------------------------------------------------- | --------------------------------- | ----- |
| `scout_stream_vulnerabilities`  | Vulnerabilities in a stream                         | `streamName`, `severity`          | Gauge |
| `scout_policy_compliant_images` | Compliant images for a policy in a stream           | `id`, `displayName`, `streamName` | Gauge |
| `scout_policy_evaluated_images` | Total images evaluated against a policy in a stream | `id`, `displayName`, `streamName` | Gauge |

> **Streams**
>
> In Docker Scout, the streams concept is a superset of [environments](../integrations/environment/index.md).
> Streams include all runtime environments that you've defined,
> as well as the special `latest-indexed` stream.
> The `latest-indexed` stream contains the most recently pushed (and analyzed) tag for each repository.
>
> Streams is mostly an internal concept in Docker Scout,
> with the exception of the data exposed through this metrics endpoint.
{ #stream }

## Creating an access token

To export metrics from your organization, first make sure your organization is enrolled in Docker Scout.
Then, create a Personal Access Token (PAT) - a secret token that allows the exporter to authenticate with the Docker Scout API.

The PAT does not require any specific permissions, but it must be created by a user who is an owner of the Docker organization.
To create a PAT, follow the steps in [Create an access token](../../security/access-tokens/personal-access-tokens.md).

Once you have created the PAT, store it in a secure location.
You will need to provide this token to the exporter when scraping metrics.

## Prometheus

This section describes how to scrape the metrics endpoint using Prometheus.

### Add a job for your organization

In the Prometheus configuration file, add a new job for your organization.
The job should include the following configuration;
replace `ORG` with your organization name:

```yaml
scrape_configs:
  - job_name: <ORG>
    metrics_path: /v1/exporter/org/<ORG>/metrics
    scheme: https
    static_configs:
      - targets:
          - api.scout.docker.com
```

The address in the `targets` field is set to the domain name of the Docker Scout API, `api.scout.docker.com`.
Make sure that there's no firewall rule in place preventing the server from communicating with this endpoint.

### Add bearer token authentication

To scrape metrics from the Docker Scout Exporter endpoint using Prometheus, you need to configure Prometheus to use the PAT as a bearer token.
The exporter requires the PAT to be passed in the `Authorization` header of the request.

Update the Prometheus configuration file to include the `authorization` configuration block.
This block defines the PAT as a bearer token stored in a file:

```yaml
scrape_configs:
  - job_name: $ORG
    authorization:
      type: Bearer
      credentials_file: /etc/prometheus/token
```

The content of the file should be the PAT in plain text:

```console
dckr_pat_...
```

If you are running Prometheus in a Docker container or Kubernetes pod, mount the file into the container using a volume or secret.

Finally, restart Prometheus to apply the changes.

### Prometheus sample project

If you don't have a Prometheus server set up, you can run a [sample project](https://github.com/dockersamples/scout-metrics-exporter) using Docker Compose.
The sample includes a Prometheus server that scrapes metrics for a Docker organization enrolled in Docker Scout,
alongside Grafana with a pre-configured dashboard to visualize the vulnerability and policy metrics.

1. Clone the starter template for bootstrapping a set of Compose services
   for scraping and visualizing the Docker Scout metrics endpoint:

   ```console
   $ git clone git@github.com:dockersamples/scout-metrics-exporter.git
   $ cd scout-metrics-exporter/prometheus
   ```

2. [Create a Docker access token](../../security/access-tokens/personal-access-tokens.md)
   and store it in a plain text file at `/prometheus/prometheus/token` under the template directory.

   ```plaintext {title=token}
   $ echo $DOCKER_PAT > ./prometheus/token
   ```

3. In the Prometheus configuration file at `/prometheus/prometheus/prometheus.yml`,
   replace `ORG` in the `metrics_path` property on line 6 with the namespace of your Docker organization.

   ```yaml {title="prometheus/prometheus.yml",hl_lines="6",linenos=true}
   global:
     scrape_interval: 60s
     scrape_timeout: 40s
   scrape_configs:
     - job_name: Docker Scout policy
       metrics_path: /v1/exporter/org/<ORG>/metrics
       scheme: https
       static_configs:
         - targets:
             - api.scout.docker.com
       authorization:
         type: Bearer
         credentials_file: /etc/prometheus/token
   ```

4. Start the compose services.

   ```console
   docker compose up -d
   ```

   This command starts two services: the Prometheus server and Grafana.
   Prometheus scrapes metrics from the Docker Scout endpoint,
   and Grafana visualizes the metrics using a pre-configured dashboard.

To stop the demo and clean up any resources created, run:

```console
docker compose down -v
```

### Access to Prometheus

After starting the services, you can access the Prometheus expression browser by visiting <http://localhost:9090>.
The Prometheus server runs in a Docker container and is accessible on port 9090.

After a few seconds, you should see the metrics endpoint as a target in the
Prometheus UI at <http://localhost:9090/targets>.

![Docker Scout metrics exporter Prometheus target](../images/scout-metrics-prom-target.png "Docker Scout metrics exporter Prometheus target")

### Viewing the metrics in Grafana

To view the Grafana dashboards, go to <http://localhost:3000/dashboards>,
and sign in using the credentials defined in the Docker Compose file (username: `admin`, password: `grafana`).

![Vulnerability dashboard in Grafana](../images/scout-metrics-grafana-vulns.png "Vulnerability dashboard in Grafana")

![Policy dashboard in Grafana](../images/scout-metrics-grafana-policy.png "Policy dashboard in Grafana")

The dashboards are pre-configured to visualize the vulnerability and policy metrics scraped by Prometheus.

## Datadog

This section describes how to scrape the metrics endpoint using Datadog.
Datadog pulls data for monitoring by running a customizable
[agent](https://docs.datadoghq.com/agent/?tab=Linux) that scrapes available
endpoints for any exposed metrics. The OpenMetrics and Prometheus checks are
included in the agent, so you don’t need to install anything else on your
containers or hosts.

This guide assumes you have a Datadog account and a Datadog API Key. Refer to
the [Datadog documentation](https://docs.datadoghq.com/agent) to get started.

### Configure the Datadog agent

To start collecting the metrics, you will need to edit the agent’s
configuration file for the OpenMetrics check. If you're running the agent as a
container, such file must be mounted at
`/etc/datadog-agent/conf.d/openmetrics.d/conf.yaml`.

The following example shows a Datadog configuration that:

- Specifies the OpenMetrics endpoint targeting the `dockerscoutpolicy` Docker organization
- A `namespace` that all collected metrics will be prefixed with
- The [`metrics`](#metrics) you want the agent to scrape (`scout_*`)
- An `auth_token` section for the Datadog agent to authenticate to the Metrics
  endpoint, using a Docker PAT as a Bearer token.

```yaml
instances:
  - openmetrics_endpoint: "https://api.scout.docker.com/v1/exporter/org/dockerscoutpolicy/metrics"
    namespace: "scout-metrics-exporter"
    metrics:
      - scout_*
    auth_token:
      reader:
        type: file
        path: /var/run/secrets/scout-metrics-exporter/token
      writer:
        type: header
        name: Authorization
        value: Bearer <TOKEN>
```

> [!IMPORTANT]
>
> Do not replace the `<TOKEN>` placeholder in the previous configuration
> example. It must stay as it is. Only make sure the Docker PAT is correctly
> mounted into the Datadog agent in the specified filesystem path. Save the
> file as `conf.yaml` and restart the agent.

When creating a Datadog agent configuration of your own, make sure to edit the
`openmetrics_endpoint` property to target your organization, by replacing
`dockerscoutpolicy` with the namespace of your Docker organization.

### Datadog sample project

If you don't have a Datadog server set up, you can run a [sample project](https://github.com/dockersamples/scout-metrics-exporter)
using Docker Compose. The sample includes a Datadog agent, running as a
container, that scrapes metrics for a Docker organization enrolled in Docker
Scout. This sample project assumes that you have a Datadog account, an API key,
and a Datadog site.

1. Clone the starter template for bootstrapping a Datadog Compose service for
   scraping the Docker Scout metrics endpoint:

   ```console
   $ git clone git@github.com:dockersamples/scout-metrics-exporter.git
   $ cd scout-metrics-exporter/datadog
   ```

2. [Create a Docker access token](../../security/access-tokens/personal-access-tokens.md)
   and store it in a plain text file at `/datadog/token` under the template directory.

   ```plaintext {title=token}
   $ echo $DOCKER_PAT > ./token
   ```

3. In the `/datadog/compose.yaml` file, update the `DD_API_KEY` and `DD_SITE` environment variables
   with the values for your Datadog deployment.

   ```yaml {hl_lines="5-6"}
     datadog-agent:
       container_name: datadog-agent
       image: gcr.io/datadoghq/agent:7
       environment:
         - DD_API_KEY=${DD_API_KEY} # e.g. 1b6b3a42...
         - DD_SITE=${DD_SITE} # e.g. datadoghq.com
         - DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true
       volumes:
         - /var/run/docker.sock:/var/run/docker.sock:ro
         - ./conf.yaml:/etc/datadog-agent/conf.d/openmetrics.d/conf.yaml:ro
         - ./token:/var/run/secrets/scout-metrics-exporter/token:ro
   ```

   The `volumes` section mounts the Docker socket from the host to the
   container. This is required to obtain an accurate hostname when running as a
   container ([more details here](https://docs.datadoghq.com/agent/troubleshooting/hostname_containers/)).

   It also mounts the agent's config file and the Docker access token.

4. Edit the `/datadog/config.yaml` file by replacing the placeholder `<ORG>` in
   the `openmetrics_endpoint` property with the namespace of the Docker
   organization that you want to collect metrics for.

   ```yaml {hl_lines=2}
   instances:
     - openmetrics_endpoint: "https://api.scout.docker.com/v1/exporter/org/<<ORG>>/metrics"
       namespace: "scout-metrics-exporter"
   # ...
   ```

5. Start the Compose services.

   ```console
   docker compose up -d
   ```

If configured properly, you should see the OpenMetrics check under Running
Checks when you run the agent’s status command whose output should look similar
to:

```text
openmetrics (4.2.0)
-------------------
  Instance ID: openmetrics:scout-prometheus-exporter:6393910f4d92f7c2 [OK]
  Configuration Source: file:/etc/datadog-agent/conf.d/openmetrics.d/conf.yaml
  Total Runs: 1
  Metric Samples: Last Run: 236, Total: 236
  Events: Last Run: 0, Total: 0
  Service Checks: Last Run: 1, Total: 1
  Average Execution Time : 2.537s
  Last Execution Date : 2024-05-08 10:41:07 UTC (1715164867000)
  Last Successful Execution Date : 2024-05-08 10:41:07 UTC (1715164867000)
```

For a comprehensive list of options, take a look at this [example config file](https://github.com/DataDog/integrations-core/blob/master/openmetrics/datadog_checks/openmetrics/data/conf.yaml.example) for the generic OpenMetrics check.

### Visualizing your data

Once the agent is configured to grab Prometheus metrics, you can use them to build comprehensive Datadog graphs, dashboards, and alerts.

Go into your [Metric summary page](https://app.datadoghq.com/metric/summary?filter=scout_prometheus_exporter)
to see the metrics collected from this example. This configuration will collect
all exposed metrics starting with `scout_` under the namespace
`scout_metrics_exporter`.

![datadog_metrics_summary](../images/datadog_metrics_summary.png)

The following screenshots show examples of a Datadog dashboard containing
graphs about vulnerability and policy compliance for a specific [stream](#stream).

![datadog_dashboard_1](../images/datadog_dashboard_1.png)
![datadog_dashboard_2](../images/datadog_dashboard_2.png)

> The reason why the lines in the graphs look flat is due to the own nature of
> vulnerabilities (they don't change too often) and the short time interval
> selected in the date picker.

## Scrape interval

By default, Prometheus and Datadog scrape metrics at a 15 second interval.
Because of the own nature of vulnerability data, the metrics exposed through this API are unlikely to change at a high frequency.
For this reason, the metrics endpoint has a 60-minute cache by default,
which means a scraping interval of 60 minutes or higher is recommended.
If you set the scrape interval to less than 60 minutes, you will see the same data in the metrics for multiple scrapes during that time window.

To change the scrape interval:

- Prometheus: set the `scrape_interval` field in the Prometheus configuration
  file at the global or job level.
- Datadog: set the `min_collection_interval` property in the Datadog agent
  configuration file, see [Datadog documentation](https://docs.datadoghq.com/developers/custom_checks/write_agent_check/#updating-the-collection-interval).

## Revoke an access token

If you suspect that your PAT has been compromised or is no longer needed, you can revoke it at any time.
To revoke a PAT, follow the steps in the [Create and manage access tokens](../../security/access-tokens/personal-access-tokens.md).

Revoking a PAT immediately invalidates the token, and prevents Prometheus from scraping metrics using that token.
You will need to create a new PAT and update the Prometheus configuration to use the new token.


---

# How-tos

*Sección: Scout*




---

# Use Scout with different artifact types

*Sección: Scout*

Some of the Docker Scout CLI commands support prefixes for specifying
the location or type of artifact that you would like to analyze.

By default, image analysis with the `docker scout cves` command
targets images in the local image store of the Docker Engine.
The following command always uses a local image if it exists:

```console
$ docker scout cves <image>
```

If the image doesn't exist locally, Docker pulls the image before running the analysis.
Analyzing the same image again would use the same local version by default,
even if the tag has since changed in the registry.

By adding a `registry://` prefix to the image reference,
you can force Docker Scout to analyze the registry version of the image:

```console
$ docker scout cves registry://<image>
```

## Supported prefixes

The supported prefixes are:

| Prefix               | Description                                                          |
| -------------------- | -------------------------------------------------------------------- |
| `image://` (default) | Use a local image, or fall back to a registry lookup                 |
| `local://`           | Use an image from the local image store (don't do a registry lookup) |
| `registry://`        | Use an image from a registry (don't use a local image)               |
| `oci-dir://`         | Use an OCI layout directory                                          |
| `archive://`         | Use a tarball archive, as created by `docker save`                   |
| `fs://`              | Use a local directory or file                                        |

You can use prefixes with the following commands:

- `docker scout compare`
- `docker scout cves`
- `docker scout quickview`
- `docker scout recommendations`
- `docker scout sbom`

## Examples

This section contains a few examples showing how you can use prefixes
to specify artifacts for `docker scout` commands.

### Analyze a local project

The `fs://` prefix lets you analyze local source code directly,
without having to build it into a container image.
The following `docker scout quickview` command gives you an
at-a-glance vulnerability summary of the source code in the current working directory:

```console
$ docker scout quickview fs://.
```

To view the details of vulnerabilities found in your local source code, you can
use the `docker scout cves --details fs://.` command. Combine it with
other flags to narrow down the results to the packages and vulnerabilities that
you're interested in.

```console
$ docker scout cves --details --only-severity high fs://.
    ✓ File system read
    ✓ Indexed 323 packages
    ✗ Detected 1 vulnerable package with 1 vulnerability

​## Overview

                    │        Analyzed path
────────────────────┼──────────────────────────────
  Path              │  /Users/david/demo/scoutfs
    vulnerabilities │    0C     1H     0M     0L

​## Packages and Vulnerabilities

   0C     1H     0M     0L  fastify 3.29.0
pkg:npm/fastify@3.29.0

    ✗ HIGH CVE-2022-39288 [OWASP Top Ten 2017 Category A9 - Using Components with Known Vulnerabilities]
      https://scout.docker.com/v/CVE-2022-39288

      fastify is a fast and low overhead web framework, for Node.js. Affected versions of
      fastify are subject to a denial of service via malicious use of the Content-Type
      header. An attacker can send an invalid Content-Type header that can cause the
      application to crash. This issue has been addressed in commit  fbb07e8d  and will be
      included in release version 4.8.1. Users are advised to upgrade. Users unable to
      upgrade may manually filter out http content with malicious Content-Type headers.

      Affected range : <4.8.1
      Fixed version  : 4.8.1
      CVSS Score     : 7.5
      CVSS Vector    : CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

1 vulnerability found in 1 package
  LOW       0
  MEDIUM    0
  HIGH      1
  CRITICAL  0
```

### Compare a local project to an image

With `docker scout compare`, you can compare the analysis of source code on
your local filesystem with the analysis of a container image.
The following example compares local source code (`fs://.`)
with a registry image `registry://docker/scout-cli:latest`.
In this case, both the baseline and target for the comparison use prefixes.

```console
$ docker scout compare fs://. --to registry://docker/scout-cli:latest --ignore-unchanged
WARN 'docker scout compare' is experimental and its behaviour might change in the future
    ✓ File system read
    ✓ Indexed 268 packages
    ✓ SBOM of image already cached, 234 packages indexed


  ## Overview

                           │              Analyzed File System              │              Comparison Image
  ─────────────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────
    Path / Image reference │  /Users/david/src/docker/scout-cli-plugin      │  docker/scout-cli:latest
                           │                                                │  bb0b01303584
      platform             │                                                │ linux/arm64
      provenance           │ https://github.com/dvdksn/scout-cli-plugin.git │ https://github.com/docker/scout-cli-plugin
                           │  6ea3f7369dbdfec101ac7c0fa9d78ef05ffa6315      │  67cb4ef78bd69545af0e223ba5fb577b27094505
      vulnerabilities      │    0C     0H     1M     1L                     │    0C     0H     1M     1L
                           │                                                │
      size                 │ 7.4 MB (-14 MB)                                │ 21 MB
      packages             │ 268 (+34)                                      │ 234
                           │                                                │


  ## Packages and Vulnerabilities


    +   55 packages added
    -   21 packages removed
       213 packages unchanged
```

The previous example is truncated for brevity.

### View the SBOM of an image tarball

The following example shows how you can use the `archive://` prefix
to get the SBOM of an image tarball, created with `docker save`.
The image in this case is `docker/scout-cli:latest`,
and the SBOM is exported to file `sbom.spdx.json` in SPDX format.

```console
$ docker pull docker/scout-cli:latest
latest: Pulling from docker/scout-cli
257973a141f5: Download complete 
1f2083724dd1: Download complete 
5c8125a73507: Download complete 
Digest: sha256:13318bb059b0f8b0b87b35ac7050782462b5d0ac3f96f9f23d165d8ed68d0894
$ docker save docker/scout-cli:latest -o scout-cli.tar
$ docker scout sbom --format spdx -o sbom.spdx.json archive://scout-cli.tar
```

## Learn more

Read about the commands and supported flags in the CLI reference documentation:

- [`docker scout quickview`](/reference/cli/docker/scout/quickview/)
- [`docker scout cves`](/reference/cli/docker/scout/cves/)
- [`docker scout compare`](/reference/cli/docker/scout/compare/)


---

# Configure Docker Scout with environment variables

*Sección: Scout*

The following environment variables are available to configure the Docker Scout
CLI commands, and the corresponding `docker/scout-cli` container image:

| Name                                    | Format  | Description                                                                                 |
| :-------------------------------------- | ------- | :------------------------------------------------------------------------------------------ |
| DOCKER_SCOUT_CACHE_FORMAT               | String  | Format of the local image cache; can be `oci` or `tar` (default: `oci`)                     |
| DOCKER_SCOUT_CACHE_DIR                  | String  | Directory where the local SBOM cache is stored (default: `$HOME/.docker/scout`)             |
| DOCKER_SCOUT_NO_CACHE                   | Boolean | When set to `true`, disables the use of local SBOM cache                                    |
| DOCKER_SCOUT_OFFLINE                    | Boolean | Use [offline mode](#offline-mode) when indexing SBOM                                        |
| DOCKER_SCOUT_REGISTRY_TOKEN             | String  | Token for authenticating to a registry when pulling images                                  |
| DOCKER_SCOUT_REGISTRY_USER              | String  | Username for authenticating to a registry when pulling images                               |
| DOCKER_SCOUT_REGISTRY_PASSWORD          | String  | Password or personal access token for authenticating to a registry when pulling images      |
| DOCKER_SCOUT_HUB_USER                   | String  | Docker Hub username for authenticating to the Docker Scout backend                          |
| DOCKER_SCOUT_HUB_PASSWORD               | String  | Docker Hub password or personal access token for authenticating to the Docker Scout backend |
| DOCKER_SCOUT_NEW_VERSION_WARN           | Boolean | Warn about new versions of the Docker Scout CLI                                             |
| DOCKER_SCOUT_EXPERIMENTAL_WARN          | Boolean | Warn about experimental features                                                            |
| DOCKER_SCOUT_EXPERIMENTAL_POLICY_OUTPUT | Boolean | Disable experimental output for policy evaluation                                           |

## Offline mode

Under normal operation, Docker Scout cross-references external systems, such as
npm, NuGet, or proxy.golang.org, to retrieve additional information about
packages found in your image.

When `DOCKER_SCOUT_OFFLINE` is set to `true`, Docker Scout image analysis runs
in offline mode. Offline mode means Docker Scout doesn't make outbound requests
to external systems.

To use offline mode:

```console
$ export DOCKER_SCOUT_OFFLINE=true
```


---

# Create an exception using the GUI

*Sección: Scout*

The Docker Scout Dashboard and Docker Desktop provide a user-friendly interface
for creating [exceptions](../explore/exceptions.md) for
vulnerabilities found in container images. Exceptions let you acknowledge
accepted risks or address false positives in image analysis.

## Prerequisites

To create an in the Docker Scout Dashboard or Docker Desktop, you need a Docker
account with **Editor** or **Owner** permissions for the Docker organization
that owns the image.

## Steps

To create an exception for a vulnerability in an image using the Docker Scout
Dashboard or Docker Desktop:

{{< tabs >}}
{{< tab name="Docker Scout Dashboard" >}}

1. Go to the [Images page](https://scout.docker.com/reports/images).
2. Select the image tag that contains the vulnerability you want to create an
   exception for.
3. Open the **Image layers** tab.
4. Select the layer that contains the vulnerability you want to create an
   exception for.
5. In the **Vulnerabilities** tab, find the vulnerability you want to create an
   exception for. Vulnerabilities are grouped by package. Find the package that
   contains the vulnerability you want to create an exception for, and then
   expand the package.
6. Select the **Create exception** button next to the vulnerability.

{{% create_panel.inline %}}
Selecting the **Create exception** button opens the **Create exception** side panel.
In this panel, you can provide the details of the exception:

- **Exception type**: The type of exception. The only supported types are:

  - **Accepted risk**: The vulnerability is not addressed due to its minimal
    security risk, high remediation costs, dependence on an upstream fix, or
    similar.
  - **False positive**: The vulnerability presents no security risk in your
    specific use case, configuration, or because of measures in place that
    block exploitation

    If you select **False positive**, you must provide a justification for why
    the vulnerability is a false positive:

- **Additional details**: Any additional information that you want to
  provide about the exception.

- **Scope**: The scope of the exception. The scope can be:

  - **Image**: The exception applies to the selected image.
  - **All images in repository**: The exception applies to all images in the
    repository.
  - **Specific repository**: The exception applies to all images in the
    specified repositories.
  - **All images in my organization**: The exception applies to all images in
    your organization.

- **Package scope**: The scope of the exception. The package scope can be:

  - **Selected package**: The exception applies to the selected package.
  - **Any packages**: The exception applies to all packages vulnerable to this
    CVE.

When you've filled in the details, select the **Create** button to create the
exception.

The exception is now created and factored into the analysis results for the
images that you selected. The exception is also listed on the **Exceptions**
tab of the [Vulnerabilities page](https://scout.docker.com/reports/vulnerabilities/exceptions)
in the Docker Scout Dashboard.

{{% /create_panel.inline %}}

{{< /tab >}}
{{< tab name="Docker Desktop" >}}

1. Open the **Images** view in Docker Desktop.
2. Open the **Hub** tab.
3. Select the image tag that contains the vulnerability you want to create an
   exception for.
4. Select the layer that contains the vulnerability you want to create an
   exception for.
5. In the **Vulnerabilities** tab, find the vulnerability you want to create an
   exception for.
6. Select the **Create exception** button next to the vulnerability.

{{% create_panel.inline / %}}

{{< /tab >}}
{{< /tabs >}}


---

# Create an exception using the VEX

*Sección: Scout*

Vulnerability Exploitability eXchange (VEX) is a standard format for
documenting vulnerabilities in the context of a software package or product.
Docker Scout supports VEX documents to create
[exceptions](../explore/exceptions.md) for vulnerabilities in images.

> [!NOTE]
> You can also create exceptions using the Docker Scout Dashboard or Docker
> Desktop. The GUI provides a user-friendly interface for creating exceptions,
> and it's easy to manage exceptions for multiple images. It also lets you
> create exceptions for multiple images, or your entire organization, all at
> once. For more information, see [Create an exception using the GUI](create-exceptions-gui.md).

## Prerequisites

To create exceptions using OpenVEX documents, you need:

- The latest version of Docker Desktop or the Docker Scout CLI plugin
- The [`vexctl`](https://github.com/openvex/vexctl) command line tool.

Additional requirements depend on how you attach the VEX document:

- The [containerd image store](../../desktop/features/containerd.md)
  must be enabled to attach the document as an attestation.
- Write permissions to the registry repository where the image is stored
  are required to attach the document as an attestation.

## Introduction to VEX

The VEX standard is defined by a working group by the United States
Cybersecurity and Infrastructure Security Agency (CISA). At the core of VEX are
exploitability assessments. These assessments describe the status of a given
CVE for a product. The possible vulnerability statuses in VEX are:

- Not affected: No remediation is required regarding this vulnerability.
- Affected: Actions are recommended to remediate or address this vulnerability.
- Fixed: These product versions contain a fix for the vulnerability.
- Under investigation: It is not yet known whether these product versions are affected by the vulnerability. An update will be provided in a later release.

There are multiple implementations and formats of VEX. Docker Scout supports
the [OpenVex](https://github.com/openvex/spec) implementation. Regardless of
the specific implementation, the core idea is the same: to provide a framework
for describing the impact of vulnerabilities. Key components of VEX regardless
of implementation includes:

VEX document
: A type of security advisory for storing VEX statements.
  The format of the document depends on the specific implementation.

VEX statement
: Describes the status of a vulnerability in a product,
  whether it's exploitable, and whether there are ways to remediate the issue.

Justification and impact
: Depending on the vulnerability status, statements include a justification
  or impact statement describing why a product is or isn't affected.

Action statements
: Describe how to remediate or mitigate the vulnerability.

## `vexctl` example

The following example command creates a VEX document stating that:

- The software product described by this VEX document is the Docker image
  `example/app:v1`
- The image contains the npm package `express@4.17.1`
- The npm package is affected by a known vulnerability: `CVE-2022-24999`
- The image is unaffected by the CVE, because the vulnerable code is never
  executed in containers that run this image

```console
$ vexctl create \
  --author="author@example.com" \
  --product="pkg:docker/example/app@v1" \
  --subcomponents="pkg:npm/express@4.17.1" \
  --vuln="CVE-2022-24999" \
  --status="not_affected" \
  --justification="vulnerable_code_not_in_execute_path" \
  --file="CVE-2022-24999.vex.json"
```

Here's a description of the options in this example:

`--author`
: The email of the author of the VEX document.

`--product`
: Package URL (PURL) of the Docker image. A PURL is an identifier
  for the image in a standardized format, defined in the PURL
  [specification](https://github.com/package-url/purl-spec/blob/master/PURL-TYPES.rst#docker).

  Docker image PURL strings begin with a `pkg:docker` type prefix, followed by
  the image repository and version (the image tag or SHA256 digest). Unlike
  image tags, where the version is specified like `example/app:v1`, in PURL the
  image repository and version are separated by an `@`.

`--subcomponents`
: PURL of the vulnerable package in the image. In this example, the
  vulnerability exists in an npm package, so the `--subcomponents` PURL is the
  identifier for the npm package name and version (`pkg:npm/express@4.17.1`).
  
  If the same vulnerability exists in multiple packages, `vexctl` lets you
  specify the `--subcomponents` flag multiple times for a single `create`
  command.

  You can also omit `--subcomponents`, in which case the VEX statement applies
  to the entire image.

`--vuln`
: ID of the CVE that the VEX statement addresses.

`--status`
: This is the status label of the vulnerability. This describes the
  relationship between the software (`--product`) and the CVE (`--vuln`).
  The possible values for the status label in OpenVEX are:

  - `not_affected`
  - `affected`
  - `fixed`
  - `under_investigation`

  In this example, the VEX statement asserts that the Docker image is
  `not_affected` by the vulnerability. The `not_affected` status is the only
  status that results in CVE suppression, where the CVE is filtered out of the
  analysis results. The other statuses are useful for documentation purposes,
  but they do not work for creating exceptions. For more information about all
  the possible status labels, see [Status Labels](https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-labels)
  in the OpenVEX specification.

`--justification`
: Justifies the `not_affected` status label, informing why the product is not
  affected by the vulnerability. In this case, the justification given is
  `vulnerable_code_not_in_execute_path`, signalling that the vulnerability
  can't be executed as used by the product.

  In OpenVEX, status justifications can have one of the five possible values:

  - `component_not_present`
  - `vulnerable_code_not_present`
  - `vulnerable_code_not_in_execute_path`
  - `vulnerable_code_cannot_be_controlled_by_adversary`
  - `inline_mitigations_already_exist`

  For more information about these values and their definitions, see
  [Status Justifications](https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md#status-justifications)
  in the OpenVEX specification.

`--file`
: Filename of the VEX document output

## Example JSON document

Here's the OpenVEX JSON generated by this command:

```json
{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "@id": "https://openvex.dev/docs/public/vex-749f79b50f5f2f0f07747c2de9f1239b37c2bda663579f87a35e5f0fdfc13de5",
  "author": "author@example.com",
  "timestamp": "2024-05-27T13:20:22.395824+02:00",
  "version": 1,
  "statements": [
    {
      "vulnerability": {
        "name": "CVE-2022-24999"
      },
      "timestamp": "2024-05-27T13:20:22.395829+02:00",
      "products": [
        {
          "@id": "pkg:docker/example/app@v1",
          "subcomponents": [
            {
              "@id": "pkg:npm/express@4.17.1"
            }
          ]
        }
      ],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path"
    }
  ]
}
```

Understanding how VEX documents are supposed to be structured can be a bit of a
mouthful. The [OpenVEX specification](https://github.com/openvex/spec)
describes the format and all the possible properties of documents and
statements. For the full details, refer to the specification to learn more
about the available fields and how to create a well-formed OpenVEX document.

To learn more about the available flags and syntax of the `vexctl` CLI tool and
how to install it, refer to the [`vexctl` GitHub repository](https://github.com/openvex/vexctl).

## Verifying VEX documents

To test whether the VEX documents you create are well-formed and produce the
expected results, use the `docker scout cves` command with the `--vex-location`
flag to apply a VEX document to a local image analysis using the CLI.

The following command invokes a local image analysis that incorporates all VEX
documents in the specified location, using the `--vex-location` flag. In this
example, the CLI is instructed to look for VEX documents in the current working
directory.

```console
$ docker scout cves <IMAGE> --vex-location .
```

The output of the `docker scout cves` command displays the results with any VEX
statements found in under the `--vex-location` location factored into the
results. For example, CVEs assigned a status of `not_affected` are filtered out
from the results. If the output doesn't seem to take the VEX statements into
account, that's an indication that the VEX documents might be invalid in some
way.

Things to look out for include:

- The PURL of a Docker image must begin with `pkg:docker/` followed by the image name.
- In a Docker image PURL, the image name and version is separated by `@`.
  An image named `example/myapp:1.0` has the following PURL: `pkg:docker/example/myapp@1.0`.
- Remember to specify an `author` (it's a mandatory field in OpenVEX)
- The [OpenVEX specification](https://github.com/openvex/spec) describes how
  and when to use `justification`, `impact_statement`, and other fields in the
  VEX documents. Specifying these in an incorrect way results in an invalid
  document. Make sure your VEX documents comply with the OpenVEX specification.

## Attach VEX documents to images

When you've created a VEX document,
you can attach it to your image in the following ways:

- Attach the document as an [attestation](#attestation)
- Embed the document in the [image filesystem](#image-filesystem)

You can't remove a VEX document from an image once it's been added. For
documents attached as attestations, you can create a new VEX document and
attach it to the image again. Doing so will overwrite the previous VEX document
(but it won't remove the attestation). For images where the VEX document has
been embedded in the image's filesystem, you need to rebuild the image to
change the VEX document.

### Attestation

To attach VEX documents as an attestation, you can use the `docker scout
attestation add` CLI command. Using attestations is the recommended option for
attaching exceptions to images when using VEX. This method requires the
[containerd image store](../../desktop/features/containerd.md) and write
access to the registry repository where the image is stored.

You can attach attestations to images that have already been pushed to a
registry. You don't need to build or push the image again. Additionally, having
the exceptions attached to the image as attestations means consumers can
inspect the exceptions for an image, directly from the registry.

To attach an attestation to an image:

1. Build the image and push it to a registry.

   ```console
   $ docker build --provenance=true --sbom=true --tag <IMAGE> --push .
   ```

2. Attach the exception to the image as an attestation.

   ```console
   $ docker scout attestation add \
     --file <cve-id>.vex.json \
     --predicate-type https://openvex.dev/ns/v0.2.0 \
     <IMAGE>
   ```

   The options for this command are:

   - `--file`: the location and filename of the VEX document
   - `--predicate-type`: the in-toto `predicateType` for OpenVEX

### Image filesystem

Embedding VEX documents directly on the image filesystem is a good option if
you know the exceptions ahead of time, before you build the image. And it's
relatively easy; just `COPY` the VEX document to the image in your Dockerfile.
Unlike attestations, this method doesn't require the containerd image store or
write access to a registry before the image is pushed.

The downside with this approach is that you can't change or update the
exception later. Image layers are immutable, so anything you put in the image's
filesystem is there forever. Attaching the document as an
[attestation](#attestation) provides better flexibility.

> [!NOTE]
> VEX documents embedded in the image filesystem are not considered for images
> that have attestations. If your image has **any** attestations, Docker Scout
> will only look for exceptions in the attestations, and not in the image
> filesystem.
>
> If you want to use the VEX document embedded in the image filesystem, you
> must remove the attestation from the image. Note that provenance attestations
> may be added automatically for images. To ensure that no attestations are
> added to the image, you can explicitly disable both SBOM and provenance
> attestations using the `--provenance=false` and `--sbom=false` flags when
> building the image.

To embed a VEX document on the image filesystem, `COPY` the file into the image
as part of the image build. The following example shows how to copy all VEX
documents under `.vex/` in the build context, to `/var/lib/db` in the image.

```dockerfile
# syntax=docker/dockerfile:1

FROM alpine
COPY .vex/* /var/lib/db/
```

The filename of the VEX document must match the `*.vex.json` glob pattern.
It doesn't matter where on the image's filesystem you store the file.

Note that the copied files must be part of the filesystem of the final image,
For multi-stage builds, the documents must persist in the final stage.


---

# Docker Scout SBOMs

*Sección: Scout*

[Image analysis](../explore/analysis.md) uses image SBOMs to understand what packages and versions an image contains.
Docker Scout uses SBOM attestations if available on the image (recommended).
If no SBOM attestation is available, Docker Scout creates one by indexing the image contents.

## View from CLI

To view the contents of the SBOM that Docker Scout generates, you can use the
`docker scout sbom` command.

```console
$ docker scout sbom [IMAGE]
```

By default, this prints the SBOM in a JSON format to stdout.
The default JSON format produced by `docker scout sbom` isn't SPDX-JSON.
To output SPDX, use the `--format spdx` flag:

```console
$ docker scout sbom --format spdx [IMAGE]
```

To generate a human-readable list, use the `--format list` flag:

```console
$ docker scout sbom --format list alpine

           Name             Version    Type
───────────────────────────────────────────────
  alpine-baselayout       3.4.3-r1     apk
  alpine-baselayout-data  3.4.3-r1     apk
  alpine-keys             2.4-r1       apk
  apk-tools               2.14.0-r2    apk
  busybox                 1.36.1-r2    apk
  busybox-binsh           1.36.1-r2    apk
  ca-certificates         20230506-r0  apk
  ca-certificates-bundle  20230506-r0  apk
  libc-dev                0.7.2-r5     apk
  libc-utils              0.7.2-r5     apk
  libcrypto3              3.1.2-r0     apk
  libssl3                 3.1.2-r0     apk
  musl                    1.2.4-r1     apk
  musl-utils              1.2.4-r1     apk
  openssl                 3.1.2-r0     apk
  pax-utils               1.3.7-r1     apk
  scanelf                 1.3.7-r1     apk
  ssl_client              1.36.1-r2    apk
  zlib                    1.2.13-r1    apk
```

For more information about the `docker scout sbom` command, refer to the [CLI
reference](/reference/cli/docker/scout/sbom/).

## Attach as build attestation {#attest}

You can generate the SBOM and attach it to the image at build-time as an
[attestation](../../build/metadata/attestations/index.md). BuildKit provides a default
SBOM generator which is different from what Docker Scout uses.
You can configure BuildKit to use the Docker Scout SBOM generator
using the `--attest` flag for the `docker build` command.
The Docker Scout SBOM indexer provides richer results
and ensures better compatibility with the Docker Scout image analysis.

```console
$ docker build --tag <org>/<image> \
  --attest type=sbom,generator=docker/scout-sbom-indexer:latest \
  --push .
```

To build images with SBOM attestations, you must use either the [containerd
image store](../../desktop/features/containerd.md) feature, or use a `docker-container`
builder together with the `--push` flag to push the image (with attestations)
directly to a registry. The classic image store doesn't support manifest lists
or image indices, which is required for adding attestations to an image.

## Extract to file

The command for extracting the SBOM of an image to an SPDX JSON file is
different depending on whether the image has been pushed to a registry or if
it's a local image.

### Remote image

To extract the SBOM of an image and save it to a file, you can use the `docker
buildx imagetools inspect` command. This command only works for images in a
registry.

```console
$ docker buildx imagetools inspect <image> --format "{{ json .SBOM }}" > sbom.spdx.json
```

### Local image

To extract the SPDX file for a local image, build the image with the `local`
exporter and use the `scout-sbom-indexer` SBOM generator plugin.

The following command saves the SBOM to a file at `build/sbom.spdx.json`.

```console
$ docker build --attest type=sbom,generator=docker/scout-sbom-indexer:latest \
  --output build .
```


---

# Install Docker Scout

*Sección: Scout*

The Docker Scout CLI plugin comes pre-installed with Docker Desktop.

If you run Docker Engine without Docker Desktop,
Docker Scout doesn't come pre-installed,
but you can install it as a standalone binary.

## Installation script

To install the latest version of the plugin, run the following commands:

```console
$ curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh
$ sh install-scout.sh
```

> [!NOTE]
>
> Always examine scripts downloaded from the internet before running them
> locally. Before installing, make yourself familiar with potential risks and
> limitations of the convenience script.

## Manual installation

{{< tabs >}}
{{< tab name="Linux" >}}

1. Download the latest release from the [releases page](https://github.com/docker/scout-cli/releases).
2. Create a subdirectory under `$HOME/.docker` called `scout`.

   ```console
   $ mkdir -p $HOME/.docker/scout
   ```

3. Extract the archive and move the `docker-scout` binary to the `$HOME/.docker/scout` directory.
4. Make the binary executable: `chmod +x $HOME/.docker/scout/docker-scout`.
5. Add the `scout` subdirectory to your `.docker/config.json` as a plugin directory:

   ```json
   {
     "cliPluginsExtraDirs": [
       "/home/<USER>/.docker/scout"
     ]
   }
   ```

   Substitute `<USER>` with your username on the system.

   > [!NOTE]
   > The path for `cliPluginsExtraDirs` must be an absolute path.

{{< /tab >}}
{{< tab name="macOS" >}}

1. Download the latest release from the [releases page](https://github.com/docker/scout-cli/releases).
2. Create a subdirectory under `$HOME/.docker` called `scout`.

   ```console
   $ mkdir -p $HOME/.docker/scout
   ```

3. Extract the archive and move the `docker-scout` binary to the `$HOME/.docker/scout` directory.
4. Make the binary executable:

   ```console
   $ chmod +x $HOME/.docker/scout/docker-scout
   ```

5. Authorize the binary to be executable on macOS:

   ```console
   xattr -d com.apple.quarantine $HOME/.docker/scout/docker-scout
   ```

6. Add the `scout` subdirectory to your `.docker/config.json` as a plugin directory:

   ```json
   {
     "cliPluginsExtraDirs": [
       "/Users/<USER>/.docker/scout"
     ]
   }
   ```

   Substitute `<USER>` with your username on the system.

   > [!NOTE]
   > The path for `cliPluginsExtraDirs` must be an absolute path.

{{< /tab >}}
{{< tab name="Windows" >}}

1. Download the latest release from the [releases page](https://github.com/docker/scout-cli/releases).
2. Create a subdirectory under `%USERPROFILE%/.docker` called `scout`.

   ```console
   % mkdir %USERPROFILE%\.docker\scout
   ```

3. Extract the archive and move the `docker-scout.exe` binary to the `%USERPROFILE%\.docker\scout` directory.
4. Add the `scout` subdirectory to your `.docker\config.json` as a plugin directory:

   ```json
   {
     "cliPluginsExtraDirs": [
       "C:\Users\<USER>\.docker\scout"
     ]
   }
   ```

   Substitute `<USER>` with your username on the system.

   > [!NOTE]
   > The path for `cliPluginsExtraDirs` must be an absolute path.

{{< /tab >}}
{{< /tabs >}}

## Container image

The Docker Scout CLI plugin is also available as a [container image](https://hub.docker.com/r/docker/scout-cli).
Use the `docker/scout-cli` to run `docker scout` commands without installing the CLI plugin on your host.

```console
$ docker run -it \
  -e DOCKER_SCOUT_HUB_USER=<your Docker Hub user name> \
  -e DOCKER_SCOUT_HUB_PASSWORD=<your Docker Hub PAT>  \
  docker/scout-cli <command>
```

## GitHub Action

The Docker Scout CLI plugin is also available as a [GitHub action](https://github.com/docker/scout-action).
You can use it in your GitHub workflows to automatically analyze images and evaluate policy compliance with each push.

Docker Scout also integrates with many more CI/CD tools, such as Jenkins, GitLab, and Azure DevOps.
Learn more about the [integrations](integrations/index.md) available for Docker Scout.


---

# Integrating Docker Scout with other systems

*Sección: Scout*

By default, Docker Scout integrates with your Docker organization and your
Docker Scout-enabled repositories on Docker Hub. You can integrate Docker Scout
with additional third-party systems to get access to even more insights,
including real-time information about you running workloads.

## Integration categories

You'll get different insights depending on where and how you choose to integrate
Docker Scout.

### Container registries

Integrating Docker Scout with third-party container
registries enables Docker Scout to run image analysis on those repositories,
so that you can get insights into the composition of those images even if they
aren't hosted on Docker Hub.

Docker Scout integrates with any Docker/OCI-compliant registry using
[`docker scout watch`](registry.md), including Amazon ECR, Azure
Container Registry, JFrog Artifactory, Harbor, and Sonatype Nexus.

### Continuous Integration

Integrating Docker Scout with Continuous Integration (CI) systems is a great way
to get instant, automatic feedback about your security posture in your inner
loop. Analysis running in CI also gets the benefit of additional context that's
useful for getting even more insights.

The following CI integrations are available:

- [GitHub Actions](ci/gha.md)
- [GitLab](ci/gitlab.md)
- [Microsoft Azure DevOps Pipelines](ci/azure.md)
- [Circle CI](ci/circle-ci.md)
- [Jenkins](ci/jenkins.md)

### Environment monitoring

Environment monitoring refers to integrating Docker Scout with your deployments.
This can give you information in real-time about your running container workloads.

Integrating with environments lets you compare production workloads to other
versions, in your image repositories or in your other environments.

The following environment monitoring integrations are available:

- [Generic CLI integration](environment/cli.md)

For more information about environment integrations, see
[Environments](environment/index.md).


---

# Using Docker Scout in continuous integration

*Sección: Scout*

You can analyze Docker images in continuous integration pipelines as you build
them using a GitHub action or the Docker Scout CLI plugin.

Available integrations:

- [GitHub Actions](gha.md)
- [GitLab](gitlab.md)
- [Microsoft Azure DevOps Pipelines](azure.md)
- [Circle CI](circle-ci.md)
- [Jenkins](jenkins.md)

You can also add runtime integration as part of your CI/CD pipeline, which lets
you assign an image to an environment, such as `production` or `staging`, when
you deploy it. For more information, see [Environment monitoring](../environment/index.md).


---

# Integrate Docker Scout with Microsoft Azure DevOps Pipelines

*Sección: Scout*

The following examples runs in an Azure DevOps-connected repository containing
a Docker image's definition and contents. Triggered by a commit to the main
branch, the pipeline builds the image and uses Docker Scout to create a CVE
report.

First, set up the rest of the workflow and set up the variables available to all
pipeline steps. Add the following to an _azure-pipelines.yml_ file:

```yaml
trigger:
  - main

resources:
  - repo: self

variables:
  tag: "$(Build.BuildId)"
  image: "vonwig/nodejs-service"
```

This sets up the workflow to use a particular container image for the
application and tag each new image build with the build ID.

Add the following to the YAML file:

```yaml
stages:
  - stage: Build
    displayName: Build image
    jobs:
      - job: Build
        displayName: Build
        pool:
          vmImage: ubuntu-latest
        steps:
          - task: Docker@2
            displayName: Build an image
            inputs:
              command: build
              dockerfile: "$(Build.SourcesDirectory)/Dockerfile"
              repository: $(image)
              tags: |
                $(tag)
          - task: CmdLine@2
            displayName: Find CVEs on image
            inputs:
              script: |
                # Install the Docker Scout CLI
                curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s --
                # Login to Docker Hub required for Docker Scout CLI
                echo $(DOCKER_HUB_PAT) | docker login -u $(DOCKER_HUB_USER) --password-stdin
                # Get a CVE report for the built image and fail the pipeline when critical or high CVEs are detected
                docker scout cves $(image):$(tag) --exit-code --only-severity critical,high
```

This creates the flow mentioned previously. It builds and tags the image using
the checked-out Dockerfile, downloads the Docker Scout CLI, and then runs the
`cves` command against the new tag to generate a CVE report. It only shows
critical or high-severity vulnerabilities.


---

# Integrate Docker Scout with Circle CI

*Sección: Scout*

The following examples runs when triggered in CircleCI. When triggered, it
checks out the "docker/scout-demo-service:latest" image and tag and then uses
Docker Scout to create a CVE report.

Add the following to a _.circleci/config.yml_ file.

First, set up the rest of the workflow. Add the following to the YAML file:

```yaml
version: 2.1

jobs:
  build:
    docker:
      - image: cimg/base:stable
    environment:
      IMAGE_TAG: docker/scout-demo-service:latest
```

This defines the container image the workflow uses and an environment variable
for the image.

Add the following to the YAML file to define the steps for the workflow:

```yaml
steps:
  # Checkout the repository files
  - checkout
  
  # Set up a separate Docker environment to run `docker` commands in
  - setup_remote_docker:
      version: 20.10.24

  # Install Docker Scout and login to Docker Hub
  - run:
      name: Install Docker Scout
      command: |
        env
        curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /home/circleci/bin
        echo $DOCKER_HUB_PAT | docker login -u $DOCKER_HUB_USER --password-stdin

  # Build the Docker image
  - run:
      name: Build Docker image
      command: docker build -t $IMAGE_TAG .
  
  # Run Docker Scout          
  - run:
      name: Scan image for CVEs
      command: |
        docker scout cves $IMAGE_TAG --exit-code --only-severity critical,high
```

This checks out the repository files and then sets up a separate Docker
environment to run commands in.

It installs Docker Scout, logs into Docker Hub, builds the Docker image, and
then runs Docker Scout to generate a CVE report. It only shows critical or
high-severity vulnerabilities.

Finally, add a name for the workflow and the workflow's jobs:

```yaml
workflows:
  build-docker-image:
    jobs:
      - build
```


---

# Integrate Docker Scout with GitHub Actions

*Sección: Scout*

The following example shows how to set up a Docker Scout workflow with GitHub
Actions. Triggered by a pull request, the action builds the image and uses
Docker Scout to compare the new version to the version of that image running in
production.

This workflow uses the
[docker/scout-action](https://github.com/docker/scout-action) GitHub Action to
run the `docker scout compare` command to visualize how images for pull request
stack up against the image you run in production.

## Prerequisites

- This example assumes that you have an existing image repository, in Docker Hub
  or in another registry, where you've enabled Docker Scout.
- This example makes use of [environments](../environment/index.md), to compare
  the image built in the pull request with a different version of the same image
  in an environment called `production`.

## Steps

First, set up the GitHub Action workflow to build an image. This isn't specific
to Docker Scout here, but you'll need to build an image to have
something to compare with.

Add the following to a GitHub Actions YAML file:

```yaml
name: Docker

on:
  push:
    tags: ["*"]
    branches:
      - "main"
  pull_request:
    branches: ["**"]

env:
  # Hostname of your registry
  REGISTRY: docker.io
  # Image repository, without hostname and tag
  IMAGE_NAME: ${{ github.repository }}
  SHA: ${{ github.event.pull_request.head.sha || github.event.after }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      pull-requests: write

    steps:
      # Authenticate to the container registry
      - name: Authenticate to registry ${{ env.REGISTRY }}
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ secrets.REGISTRY_USER }}
          password: ${{ secrets.REGISTRY_TOKEN }}
      
      - name: Setup Docker buildx
        uses: docker/setup-buildx-action@{{% param "setup_buildx_action_version" %}}

      # Extract metadata (tags, labels) for Docker
      - name: Extract Docker metadata
        id: meta
        uses: docker/metadata-action@{{% param "metadata_action_version" %}}
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          labels: |
            org.opencontainers.image.revision=${{ env.SHA }}
          tags: |
            type=edge,branch=$repo.default_branch
            type=semver,pattern=v{{version}}
            type=sha,prefix=,suffix=,format=short

      # Build and push Docker image with Buildx
      # (don't push on PR, load instead)
      - name: Build and push Docker image
        id: build-and-push
        uses: docker/build-push-action@{{% param "build_push_action_version" %}}
        with:
          sbom: ${{ github.event_name != 'pull_request' }}
          provenance: ${{ github.event_name != 'pull_request' }}
          push: ${{ github.event_name != 'pull_request' }}
          load: ${{ github.event_name == 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
```

This creates workflow steps to:

1. Set up Docker Buildx.
2. Authenticate to the registry.
3. Extract metadata from Git reference and GitHub events.
4. Build and push the Docker image to the registry.

> [!NOTE]
>
> The Scout compare step only runs on pull requests
> (`if: github.event_name == 'pull_request'`). Those builds set `load: true`
> and leave `sbom` / `provenance` off so the image can land in the runner's
> local store.
>
> On push events the same job turns SBOM and provenance on and pushes to
> the registry. Don't enable those attestations (or a multi-platform build)
> on the PR path — those images can't be loaded locally, and compare would
> have nothing to inspect.

With this setup out of the way, you can add the following steps to run the
image comparison:

```yaml
      # You can skip this step if Docker Hub is your registry
      # and you already authenticated before
      - name: Authenticate to Docker
        uses: docker/login-action@{{% param "login_action_version" %}}
        with:
          username: ${{ secrets.DOCKER_USER }}
          password: ${{ secrets.DOCKER_PAT }}

      # Compare the image built in the pull request with the one in production
      - name: Docker Scout
        id: docker-scout
        if: ${{ github.event_name == 'pull_request' }}
        uses: docker/scout-action@v1
        with:
          command: compare
          image: ${{ steps.meta.outputs.tags }}
          to-env: production
          ignore-unchanged: true
          only-severities: critical,high
          github-token: ${{ secrets.GITHUB_TOKEN }}
```

The compare command analyzes the image and evaluates policy compliance, and
cross-references the results with the corresponding image in the `production`
environment. This example only includes critical and high-severity
vulnerabilities, and excludes vulnerabilities that exist in both images,
showing only what's changed.

The GitHub Action outputs the comparison results in a pull request comment by
default.

![A screenshot showing the results of Docker Scout output in a GitHub Action](../../images/gha-output.webp)

Expand the **Policies** section to view the difference in policy compliance
between the two images. Note that while the new image in this example isn't
fully compliant, the output shows that the standing for the new image has
improved compared to the baseline.

![GHA policy evaluation output](../../images/gha-policy-eval.webp)


---

# Integrate Docker Scout with GitLab CI/CD

*Sección: Scout*

The following examples runs in GitLab CI in a repository containing a Docker
image's definition and contents. Triggered by a commit, the pipeline builds the
image. If the commit was to the default branch, it uses Docker Scout to get a
CVE report. If the commit was to a different branch, it uses Docker Scout to
compare the new version to the current published version.

## Steps

First, set up the rest of the workflow. There's a lot that's not specific to
Docker Scout but needed to create the images to compare.

Add the following to a `.gitlab-ci.yml` file at the root of your repository.

```yaml
docker-build:
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY

    # Install curl and the Docker Scout CLI
    - |
      apk add --update curl
      curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- 
      apk del curl 
      rm -rf /var/cache/apk/*
    # Login to Docker Hub required for Docker Scout CLI
    - echo "$DOCKER_HUB_PAT" | docker login -u "$DOCKER_HUB_USER" --password-stdin
```

This sets up the workflow to build Docker images with Docker-in-Docker mode,
running Docker inside a container.

It then downloads `curl` and the Docker Scout CLI plugin, logs into the Docker
registry using environment variables defined in your repository's settings.

Add the following to the YAML file:

```yaml
script:
  - |
    if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
      tag=""
      echo "Running on default branch '$CI_DEFAULT_BRANCH': tag = 'latest'"
    else
      tag=":$CI_COMMIT_REF_SLUG"
      echo "Running on branch '$CI_COMMIT_BRANCH': tag = $tag"
    fi
  - docker build --pull -t "$CI_REGISTRY_IMAGE${tag}" .
  - |
    if [[ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]]; then
      # Get a CVE report for the built image and fail the pipeline when critical or high CVEs are detected
      docker scout cves "$CI_REGISTRY_IMAGE${tag}" --exit-code --only-severity critical,high    
    else
      # Compare image from branch with latest image from the default branch and fail if new critical or high CVEs are detected
      docker scout compare "$CI_REGISTRY_IMAGE${tag}" --to "$CI_REGISTRY_IMAGE:latest" --exit-code --only-severity critical,high --ignore-unchanged
    fi

  - docker push "$CI_REGISTRY_IMAGE${tag}"
```

This creates the flow mentioned previously. If the commit was to the default
branch, Docker Scout generates a CVE report. If the commit was to a different
branch, Docker Scout compares the new version to the current published version.
It only shows critical or high-severity vulnerabilities and ignores
vulnerabilities that haven't changed since the last analysis.

Add the following to the YAML file:

```yaml
rules:
  - if: $CI_COMMIT_BRANCH
    exists:
      - Dockerfile
```

These final lines ensure that the pipeline only runs if the commit contains a
Dockerfile and if the commit was to the CI branch.

## Video walkthrough

The following is a video walkthrough of the process of setting up the workflow with GitLab.

<iframe class="border-0 w-full aspect-video mb-8" allow="fullscreen" src="https://www.loom.com/embed/451336c4508c42189532108fc37b2560?sid=f912524b-276d-417d-b44a-c2d39719aa1a"></iframe>


---

# Integrate Docker Scout with Jenkins

*Sección: Scout*

You can add the following stage and steps definition to a `Jenkinsfile` to run
Docker Scout as part of a Jenkins pipeline. The pipeline needs a `DOCKER_HUB`
credential containing the username and password for authenticating to Docker
Hub. It also needs an environment variable defined for the image and tag.

```groovy
pipeline {
    agent {
        // Agent details
    }

    environment {
        DOCKER_HUB = credentials('jenkins-docker-hub-credentials')
        IMAGE_TAG  = 'myorg/scout-demo-service:latest'
    }

    stages {
        stage('Analyze image') {
            steps {
                // Install Docker Scout
                sh 'curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /usr/local/bin'

                // Log into Docker Hub
                sh 'echo $DOCKER_HUB_PSW | docker login -u $DOCKER_HUB_USR --password-stdin'

                // Analyze and fail on critical or high vulnerabilities
                sh 'docker scout cves $IMAGE_TAG --exit-code --only-severity critical,high'
            }
        }
    }
}
```

This installs Docker Scout, logs into Docker Hub, and then runs Docker Scout to
generate a CVE report for an image and tag. It only shows critical or
high-severity vulnerabilities.

> [!NOTE]
>
> If you're seeing a `permission denied` error related to the image cache, try
> setting the [`DOCKER_SCOUT_CACHE_DIR`](../../how-tos/configure-cli.md) environment
> variable to a writable directory. Or alternatively, disable local caching
> entirely with `DOCKER_SCOUT_NO_CACHE=true`.


---

# Integrating Docker Scout with environments

*Sección: Scout*

You can integrate Docker Scout with your runtime environments, and get insights
for your running workloads. This gives you a real-time view of your security
status for your deployed artifacts.

Docker Scout lets you define multiple environments, and assign images to
different environments. This gives you a complete overview of your software
supply chain, and lets you view and compare deltas between environments, for
example staging and production.

How you define and name your environments is up to you. You can use patterns
that are meaningful to you and that matches how you ship your applications.

## Assign to environments

Each environment contains references to a number of images. These references
represent containers currently running in that particular environment.

For example, say you're running `myorg/webapp:3.1` in production, you can
assign that tag to your `production` environment. You might be running a
different version of the same image in staging, in which case you can assign
that version of the image to the `staging` environment.

To add environments to Docker Scout, you can:

- Use the `docker scout env <environment> <image>` CLI command to record images to environments manually
- Enable a runtime integration to automatically detect images in your environments.

Docker Scout supports the following runtime integrations:

- [Docker Scout GitHub Action](https://github.com/marketplace/actions/docker-scout#record-an-image-deployed-to-an-environment)
- [CLI client](cli.md)

> [!NOTE]
>
> Only organization owners can create new environments and set up integrations.
> Additionally, Docker Scout only assigns an image to an environment if the
> image [has been analyzed](../../explore/analysis.md), either manually or
> through a [registry integration](../index.md#container-registries).

## List environments

To see all of the available environments for an organization, you can use the
`docker scout env` command.

```console
$ docker scout env
```

By default, this prints all environments for your personal Docker organization.
To list environments for another organization that you're a part of, use the
`--org` flag.

```console
$ docker scout env --org <org>
```

You can use the `docker scout config` command to change the default
organization. This changes the default organization for all `docker scout`
commands, not just `env`.

```console
$ docker scout config organization <org>
```

## Comparing between environments

Assigning images to environments lets you make comparisons with and between
environments. This is useful for things like GitHub pull requests, for
comparing the image built from the code in the PR to the corresponding image in
staging or production.

You can also compare with streams using the `--to-env` flag on the
[`docker scout compare`](/reference/cli/docker/scout/compare/)
CLI command:

```console
$ docker scout compare --to-env production myorg/webapp:latest
```

## View images for an environment

To view the images for an environment:

1. Go to the [Images page](https://scout.docker.com/) in the Docker Scout Dashboard.
2. Open the **Environments** drop-down menu.
3. Select the environment that you want to view.

The list displays all images that have been assigned to the selected
environment. If you've deployed multiple versions of the same image in an
environment, all versions of the image appear in the list.

Alternatively, you can use the `docker scout env` command to view the images from the terminal.

```console
$ docker scout env production
docker/scout-demo-service:main@sha256:ef08dca54c4f371e7ea090914f503982e890ec81d22fd29aa3b012351a44e1bc
```

### Mismatching image tags

When you've selected an environment on the **Images** tab, tags in the list
represent the tag that was used to deploy the image. Tags are mutable, meaning
that you can change the image digest that a tag refers to. If Docker Scout
detects that a tag refers to an outdated digest, a warning icon displays next
to the image name.


---

# Generic environment integration with CLI

*Sección: Scout*

You can create a generic environment integration by running the Docker Scout
CLI client in your CI workflows. The CLI client is available as a binary on
GitHub and as a container image on Docker Hub. Use the client to invoke the
`docker scout environment` command to assign your images to environments.

For more information about how to use the `docker scout environment` command,
refer to the [CLI reference](/reference/cli/docker/scout/environment/).

## Examples

Before you start, set the following environment variables in your CI system:

- `DOCKER_SCOUT_HUB_USER`: your Docker Hub username
- `DOCKER_SCOUT_HUB_PASSWORD`: your Docker Hub personal access token

Make sure the variables are accessible to your project.

{{< tabs >}}
{{< tab name="Circle CI" >}}

```yaml
version: 2.1

jobs:
  record_environment:
    machine:
      image: ubuntu-2204:current
    image: namespace/repo
    steps:
      - run: |
          if [[ -z "$CIRCLE_TAG" ]]; then
            tag="$CIRCLE_BRANCH"
            echo "Running on branch '$CIRCLE_BRANCH'"
          else
            tag="$CIRCLE_TAG"
            echo "Running tag '$CIRCLE_TAG'"
          fi
          echo "tag = $tag"
      - run: docker run -it \
          -e DOCKER_SCOUT_HUB_USER=$DOCKER_SCOUT_HUB_USER \
          -e DOCKER_SCOUT_HUB_PASSWORD=$DOCKER_SCOUT_HUB_PASSWORD \
          docker/scout-cli:1.0.2 environment \
          --org "<MY_DOCKER_ORG>" \
          "<ENVIRONMENT>" ${image}:${tag}
```

{{< /tab >}}
{{< tab name="GitLab" >}}

The following example uses the [Docker executor](https://docs.gitlab.com/runner/executors/docker.html).

```yaml
variables:
  image: namespace/repo

record_environment:
  image: docker/scout-cli:1.0.2
  script:
    - |
      if [[ -z "$CI_COMMIT_TAG" ]]; then
        tag="$CI_COMMIT_REF_SLUG"
        echo "Running on branch '$CI_COMMIT_BRANCH'"
      else
        tag="$CI_COMMIT_TAG"
        echo "Running tag '$CI_COMMIT_TAG'"
      fi
      echo "tag = $tag"
    - environment --org <MY_DOCKER_ORG> "PRODUCTION" ${image}:${tag}
```

{{< /tab >}}
{{< tab name="Azure DevOps" >}}

```yaml
trigger:
  - main

resources:
  - repo: self

variables:
  tag: "$(Build.BuildId)"
  image: "namespace/repo"

stages:
  - stage: Docker Scout
    displayName: Docker Scout environment integration
    jobs:
      - job: Record
        displayName: Record environment
        pool:
          vmImage: ubuntu-latest
        steps:
          - script: docker run -it \
              -e DOCKER_SCOUT_HUB_USER=$DOCKER_SCOUT_HUB_USER \
              -e DOCKER_SCOUT_HUB_PASSWORD=$DOCKER_SCOUT_HUB_PASSWORD \
              docker/scout-cli:1.0.2 environment \
              --org "<MY_DOCKER_ORG>" \
              "<ENVIRONMENT>" $(image):$(tag)
```

{{< /tab >}}
{{< tab name="Jenkins" >}}

```groovy
stage('Record environment') {
    steps {
        // Install Docker Scout
        sh 'curl -sSfL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh | sh -s -- -b /usr/local/bin'
        
        // Log into Docker Hub
        sh 'echo $DOCKER_SCOUT_HUB_PASSWORD | docker login -u $DOCKER_SCOUT_HUB_USER --password-stdin'

        // Record image to environment
        sh 'docker-scout environment --org "<MY_DOCKER_ORG>" "<ENVIRONMENT>" $IMAGE_TAG'
    }
}
```

{{< /tab >}}
{{< /tabs >}}


---

# Integrate Docker Scout with a container registry

*Sección: Scout*

[`docker scout watch`](/reference/cli/docker/scout/watch/) is a long-running
CLI process that indexes images from a container registry and pushes the
results to Docker Scout. It works with any Docker/OCI-compliant registry,
including Amazon ECR, Azure Container Registry, JFrog Artifactory, Harbor, and
Sonatype Nexus.

## How it works

You run `docker scout watch` on a host you control. The process can:

- Watch specific repositories or an entire registry
- Optionally ingest all existing images once, using `--all-images`
- Periodically refresh repository lists, using `--refresh-registry`
- Receive webhook callbacks from registries that support them, for
  near-real-time analysis instead of polling

After the integration, Docker Scout automatically pulls and analyzes images
that you push to the registry. Metadata about your images are stored on the
Docker Scout platform, but Docker Scout doesn't store the container images
themselves. For more information about how Docker Scout handles image data,
see [Data handling](../deep-dive/data-handling.md).

## Set up `docker scout watch`

1. Pick a host on which to run `docker scout watch`.

   The host must have network access to your registry and be able to access
   the Scout API (`https://api.scout.docker.com`) over the internet. If
   you're using webhook callbacks, the registry must also be able to reach the
   `docker scout watch` host on the configured port.

2. Ensure you are running the latest version of Scout.

   ```console
   $ docker scout version
   ```

   If necessary, [install the latest version of Scout](../install.md).

3. Authenticate Docker to your registry.

   ```console
   $ docker login <registry-hostname> --username <user> --password <password-or-access-token>
   ```

   For Amazon ECR, authenticate using the AWS CLI instead:

   ```console
   $ aws ecr get-login-password --region <region> | \
     docker login --username AWS --password-stdin \
     <aws_account_id>.dkr.ecr.<region>.amazonaws.com
   ```

   The AWS identity used must have at least `ecr:GetAuthorizationToken` and
   `ecr:BatchGetImage` permissions on the target registry.

   For Azure Container Registry:

   ```console
   $ docker login <registry-name>.azurecr.io \
     --username <username> \
     --password <password-or-access-token>
   ```

   > [!TIP]
   >
   > As a best practice, use a dedicated user or token with read-only access
   > to the registry.

4. Set up your Scout credentials.

   1. Generate an organization access token. For more details, see
      [Create an organization access token](../../security/access-tokens/organization-access-tokens.md#create-an-organization-access-token).
   2. Sign in to Docker using the organization access token.

      ```console
      $ docker login --username <your_organization_name>
      ```

      When prompted for a password, paste the organization access token.

   3. Connect your local Docker environment to your organization's Docker Scout service.

      ```console
      $ docker scout enroll <your_organization_name>
      ```

5. Index existing images. You only need to do this once.

   ```console
   $ docker scout watch --registry <registry-hostname> --all-images
   ```

6. Confirm the images have been indexed by viewing them on the
   [Scout Dashboard](https://scout.docker.com/).

7. Continuously watch for new images.

   ```console
   $ docker scout watch --registry <registry-hostname> --refresh-registry
   ```

   `docker scout watch` is a long-running process. Run it as a system
   service, for example using `systemd` or `nohup`, to ensure it continues
   running in the background. Use `--interval` (default 60 seconds) to
   control polling frequency, and `--repository` and `--tag` to narrow scope.

Reference: [`docker scout watch`](/reference/cli/docker/scout/watch/)

## Registry-specific options

Some registries need extra configuration beyond a hostname, passed through
the `--registry` flag as a `key=value` string, for example a REST API
endpoint for webhook callbacks, or a non-standard repository layout. Built-in
adapters exist for `type=artifactory`, `type=harbor`, and `type=nexus`, and a
`type=oci` adapter covers any OCI-compliant registry that implements the
`_catalog` endpoint. For the full option reference for each type, see
[`docker scout watch`](/reference/cli/docker/scout/watch/).

The following example walks through the `type=artifactory` adapter in detail.
See the CLI reference for equivalent Harbor, Nexus, and generic OCI examples.

### Example: JFrog Artifactory

These `type=artifactory` options override the generic registry handling for
the `--registry` option:

| Key              | Required | Description                                                                            |
|------------------|:--------:|----------------------------------------------------------------------------------------|
| `type`           |   Yes    | Must be `artifactory`.                                                                 |
| `registry`       |   Yes    | Docker/OCI registry hostname (e.g., `example.jfrog.io`).                               |
| `api`            |   Yes    | Artifactory REST API base URL (e.g., `https://example.jfrog.io/artifactory`).          |
| `repository`     |   Yes    | Repository to watch (replaces `--repository`).                                         |
| `includes`       |    No    | Globs to include (e.g., `*/frontend*`).                                                |
| `excludes`       |    No    | Globs to exclude (e.g., `*/legacy/*`).                                                 |
| `port`           |    No    | Local port to listen on for webhook callbacks.                                         |
| `subdomain-mode` |    No    | `true` or `false`; matches Artifactory's Docker layout (subdomain versus repository-path). |

Set up credentials for the Scout client to authenticate with Artifactory, and
a secret for Artifactory to authenticate its webhook callbacks:

```console
$ export DOCKER_SCOUT_ARTIFACTORY_API_USER=<user>
$ export DOCKER_SCOUT_ARTIFACTORY_API_PASSWORD=<password-or-access-token>
$ export DOCKER_SCOUT_ARTIFACTORY_WEBHOOK_SECRET=<random-64-128-character-secret>
```

> [!TIP]
>
> As a best practice, create a dedicated user with read-only access and use an
> access token instead of a password. Generate the webhook secret as a
> high-entropy random string of 64-128 characters.

Index existing images with the Artifactory-specific registry string:

```console
$ docker scout watch --registry \
  "type=artifactory,registry=example.jfrog.io,api=https://example.jfrog.io/artifactory,include=*/frontend*,exclude=*/dta/*,repository=docker-local,port=9000,subdomain-mode=true" \
  --all-images
```

Then configure Artifactory to call the webhook: in your Artifactory UI or via
REST API, set up a webhook for image push/update events, pointing to your
`docker scout watch` host and port, and include the
`DOCKER_SCOUT_ARTIFACTORY_WEBHOOK_SECRET` for authentication. For more
information, see the [JFrog Artifactory Webhooks
documentation](https://jfrog.com/help/r/jfrog-platform-administration-documentation/webhooks)
or the [JFrog Artifactory REST API Webhooks
documentation](https://jfrog.com/help/r/jfrog-rest-apis/webhooks).

Finally, run the same command with `--refresh-registry` instead of
`--all-images` as your long-running watch process, so new images are picked up
going forward:

```console
$ docker scout watch --registry \
  "type=artifactory,registry=example.jfrog.io,api=https://example.jfrog.io/artifactory,include=*/frontend*,exclude=*/dta/*,repository=docker-local,port=9000,subdomain-mode=true" \
  --refresh-registry
```


---

# Policy Evaluation

*Sección: Scout*

Policy Evaluation in Docker Scout lets you define supply chain rules for your
artifacts and evaluate compliance using the `docker scout policy` command. Run
evaluations locally, in CI pipelines, with custom Rego policies, or using OCI
bundles. See [Evaluate policies](local.md).

## How Policy Evaluation works

When you run `docker scout policy`, the CLI indexes the image into an SBOM and
enriches it with CVE and VEX data. It then evaluates each configured policy
in-process against that data. No data is sent to the Scout service, and an
organization is not required for most use cases.

A policy defines image quality criteria your artifacts should meet. For
example, the **No copyleft licenses** policy flags any image containing
packages distributed under a copyleft license. If an image contains such a
package, it's non-compliant with that policy.

## Policy types

Docker Scout includes the following built-in policy types:

- [Severity-Based Vulnerability](#severity-based-vulnerability)
- [No copyleft licenses](#no-copyleft-licenses)
- [No outdated base images](#no-outdated-base-images)
- [High-Profile Vulnerabilities](#high-profile-vulnerabilities)
- [Supply Chain Attestations](#supply-chain-attestations)
- [Default Non-Root User](#default-non-root-user)
- [Approved Base Images](#approved-base-images)

For configuration options for each policy type, see
[Evaluate policies](local.md#configure-built-in-policies).

<!-- vale Docker.HeadingSentenceCase = NO -->

### Severity-Based Vulnerability

The **Severity-Based Vulnerability** policy type checks whether your artifacts
are exposed to known vulnerabilities. By default, it flags critical and high
severity vulnerabilities where a fix version is available.

Configurable parameters include severity levels, a grace period for newly
disclosed CVEs, fixable-only filtering, and package type filtering.

### No copyleft licenses

The **No copyleft licenses** policy type checks whether your images contain
packages distributed under an inappropriate license. You can configure the
list of licenses to flag and add package-level exceptions.

### No outdated base images

The **No outdated base images** policy type checks whether the base images you
use are current. Images are non-compliant if the tag you built from points to
a different digest than what you're using.

Your images need provenance attestations for this policy to evaluate
successfully. For more information, see [No base image data](#no-base-image-data).

### High-Profile Vulnerabilities

The **High-Profile Vulnerabilities** policy type checks whether your images
contain vulnerabilities from a [curated list of widely recognized, high-impact
CVEs](local.md#default-high-profile-cves), including Log4Shell, Spring4Shell,
and XZ backdoor. The list is updated as new high-profile vulnerabilities are
disclosed.

You can configure which CVEs are considered high-profile and enable tracking
of CISA's Known Exploited Vulnerabilities catalog.

### Supply Chain Attestations

The **Supply Chain Attestations** policy type checks whether your images have
[SBOM](../../build/metadata/attestations/sbom.md) and
[provenance](../../build/metadata/attestations/slsa-provenance.md)
attestations. Images are non-compliant if they lack either attestation type.

To ensure compliance, build with attestations:

```console
$ docker buildx build --provenance=true --sbom=true -t <IMAGE> --push .
```

### Default Non-Root User

The **Default Non-Root User** policy type detects images configured to run as
the `root` user. Use the
[`USER`](../../build/concepts/dockerfile.md#user) Dockerfile instruction to set a
non-root default user for the runtime stage.

### Approved Base Images

The **Approved Base Images** policy type ensures the base images you use match
a configurable allowlist of glob patterns. Images are non-compliant if the
base image reference doesn't match any of the allowed patterns.

Your images need provenance attestations for this policy to evaluate
successfully. For more information, see [No base image data](#no-base-image-data).

<!-- vale Docker.HeadingSentenceCase = YES -->

## No base image data

The **No outdated base images** and **Approved Base Images** policies require
provenance attestations to determine the base image used in your build. Without
them, these policies report **No data**.

To ensure Docker Scout always has base image information, attach provenance
attestations at build time:

```console
$ docker buildx build --provenance=true -t <IMAGE> --push .
```


---

# Evaluate policies

*Sección: Scout*

{{< summary-bar feature_name="Evaluate policies" >}}

`docker scout policy` lets you evaluate images against a configurable policy
set using the CLI. You can use the built-in defaults, adjust thresholds to
match your requirements, or write custom policies in
[Rego](https://www.openpolicyagent.org/docs/latest/policy-language/).

## How it works

When you run `docker scout policy`, the CLI indexes the image into an SBOM,
enriches it with CVE and VEX data, then evaluates each configured policy
in-process. No data is sent to the Scout service, and an
organization is not required for most use cases.

Policies come from three sources, which can be combined:

- Built-in defaults: a curated set embedded in the CLI, used when no other
  source is given.
- OCI policy bundles: Rego packaged as an OCI artifact and pulled from a
  registry with `--policy-bundle`.
- Local `.rego` files: for authoring and iterating on custom policies with
  `--policy-file` or `--policy-dir`.

## Use in CI

Use the [Docker Scout GitHub Action](https://github.com/marketplace/actions/docker-scout)
to evaluate policies as part of your workflow:

```yaml
- name: Evaluate policies
  uses: docker/scout-action@v1
  with:
    command: policy
    image: ${{ env.IMAGE_NAME }}
    organization: <ORG>
```

For other CI platforms, install the
[Docker Scout CLI plugin](../install.md) on your runner and run
`docker scout policy <image> --exit-code`.

To gate a build on policy compliance compared to an environment, use the
`compare` command with a policy configuration:

```yaml
- uses: docker/scout-action@v1
  with:
    command: compare
    image: ${{ env.IMAGE_NAME }}
    to-env: production
    exit-on: policy
    policy-config: policies.json
    organization: <ORG>
```

See [Configure built-in policies](#configure-built-in-policies) for the
`policy-config` file format.

## Examples

Evaluate an image against the built-in policy set:

```console
$ docker scout policy myorg/app:latest
```

Use `--exit-code` to fail the pipeline when any policy is not met:

```console
$ docker scout policy myorg/app:latest --exit-code
```

To customize which policies run and their thresholds, pass a policy-config
file:

```console
$ docker scout policy myorg/app:latest --policy-config policies.json
```

Policy results are also surfaced by `docker scout quickview` and
`docker scout compare`, which accept the same `--policy-file`,
`--policy-dir`, `--policy-bundle`, and `--policy-config` flags.

Other useful flags:

```console
# Evaluate a specific platform for a multi-platform image
$ docker scout policy myorg/app:latest --platform linux/arm64

# Show results for a specific policy only
$ docker scout policy myorg/app:latest --only-policy "No copyleft licenses"

# Write the report to a file
$ docker scout policy myorg/app:latest --output report.txt
```

## Health score

`docker scout policy`, `docker scout quickview`, and `docker scout compare` also
report a health score alongside the policy results: a numeric percentage and an
A-F letter grade, computed entirely from the local policy evaluation. No data is
sent to the Scout service to compute it.

```console
$ docker scout policy myorg/app:latest
...
Health score  B (83%)
```

`docker scout compare` shows the score for both images:

```console
Health score  Analyzed B (83%)  Comparison C (65%)
```

### How the score is calculated

The score is a weighted pass ratio:

- Each policy contributes a weight to the total, taken from its `custom.weight`
  metadata annotation (see [Metadata annotations](#metadata-annotations)) or a
  `weight` override in the policy-config file. Policies without a declared
  weight default to `10`.
- A policy that passes (reports zero violations) contributes its full weight to
  the scored points.
- A policy that fails still counts its weight toward the total, but contributes
  nothing to the scored points, which lowers the score.
- A policy with no data to evaluate (unknown) also counts toward the total
  without contributing to the scored points.
- A policy with a weight of `0` is excluded from the score entirely.

The percentage is `scored / total * 100`, mapped to a letter grade using strict
greater-than thresholds:

| Score | Grade |
| --- | --- |
| > 90% | A |
| > 70% | B |
| > 50% | C |
| > 30% | D |
| > 10% | E |
| <= 10% | F |

Thresholds are exclusive of their lower bound, so an exact boundary value
grades down: a score of exactly 90% is a B, not an A; exactly 70% is a C, and
so on.

If every policy is excluded from the score (for example, all policies are
configured with `weight: 0`), no health score is shown at all.

To change a policy's contribution to the score, set `custom.weight` in the
policy's Rego metadata, or override it per policy in the policy-config file:

```json
{
  "policies": [
    {
      "name": "copyleft-license",
      "weight": 0
    }
  ]
}
```

## Built-in policies

The following policies are available by default:

| Policy | What it checks |
| --- | --- |
| No fixable critical or high vulnerabilities | Critical/high CVEs that have a fix available |
| No high-profile vulnerabilities | Curated list of well-known CVEs (Log4Shell, XZ backdoor, and others) |
| No copyleft licenses | Packages under AGPL, GPL, LGPL, MPL, and similar licenses |
| No outdated base images | Base image is behind the latest digest of its tag |
| Supply chain attestations | Provenance and SBOM attestations are attached |
| Default non-root user | Image is configured to run as a non-root user |
| No unapproved base images | Base image matches a configurable allowlist |

## Configure built-in policies

A JSON policy-config file controls which policies run and their thresholds.
Pass it with `--policy-config`.

```json
{
  "policies": [
    {
      "name": "fixable-vulnerabilities",
      "config": {
        "severities": ["CRITICAL"],
        "grace_period_days": 14
      }
    },
    {
      "name": "no-stale-base-images",
      "enabled": false
    }
  ]
}
```

- `policies[].name`: the policy's stable ID (see the following table).
- `policies[].enabled`: set to `false` to skip the policy. Policies not listed are enabled by default.
- `policies[].weight`: overrides the policy's `custom.weight` metadata annotation,
  which determines its contribution to the [health score](#health-score). A
  weight of `0` excludes the policy from the score. When omitted, the policy's
  own annotation is used, or `10` if it has none.
- `policies[].config`: an object passed to the policy as `data.config`.

### Configuration reference

The following table lists the configurable keys for each built-in policy.

| Policy (stable ID) | config key | Default | Description |
| --- | --- | --- | --- |
| `fixable-vulnerabilities` | `severities` | `["CRITICAL","HIGH"]` | Severity levels that count as a violation |
| `fixable-vulnerabilities` | `fixable_only` | `true` | When `true`, only vulnerabilities with a known fix count |
| `fixable-vulnerabilities` | `package_types` | `[]` | Allowlist of PURL package types to consider; empty means all |
| `fixable-vulnerabilities` | `grace_period_days` | `0` | Days a newly disclosed CVE is exempt |
| `high-profile-vulnerabilities` | `cves` | [Default high-profile CVEs](#default-high-profile-cves) | CVE IDs considered high-profile |
| `high-profile-vulnerabilities` | `ignored_cves` | `[]` | CVE IDs excluded from causing a failure |
| `high-profile-vulnerabilities` | `include_cisa_kev` | `true` | Also flag vulnerabilities in the CISA KEV catalog |
| `copyleft-license` | `licenses` | AGPL/GPL/LGPL/MPL/… | SPDX license IDs treated as copyleft |
| `copyleft-license` | `ignored_packages` | `[]` | Package URLs exempted from the check |
| `approved-base-images` | `allowed_base_images` | `["*"]` | Glob patterns of allowed base image references |
| `approved-base-images` | `allowed_distros_only` | `true` | When enabled, base image must use an allowed OS distribution |
| `approved-base-images` | `allowed_distros` | curated list | OS distributions considered allowed |
| `supply-chain-attestations` | `required_attestations` | provenance and SBOM predicate types | Attestation predicate types that must be present |

#### Default high-profile CVEs

The built-in `cves` list includes the following CVEs. Docker updates this list
as new high-profile vulnerabilities are disclosed.

| CVE ID | Common name |
| --- | --- |
| CVE-2014-0160 | Heartbleed |
| CVE-2014-6271 | Shellshock |
| CVE-2021-44228 | Log4Shell |
| CVE-2021-45046 | Log4j follow-up |
| CVE-2022-22965 | Spring4Shell |
| CVE-2023-38545 | curl SOCKS5 heap overflow |
| CVE-2023-44487 | HTTP/2 Rapid Reset |
| CVE-2024-3094 | XZ Utils backdoor |

To override the list, set `cves` in your policy-config file:

```json
{
  "policies": [
    {
      "name": "high-profile-vulnerabilities",
      "config": {
        "cves": ["CVE-2021-44228", "CVE-2024-3094"]
      }
    }
  ]
}
```

## Write custom policies

Policies are Rego modules in the `docker.scout` package. A policy declares a
boolean `pass` rule and a `violation` set. Use `--policy-file` for a single
file or `--policy-dir` to load a directory recursively.

```rego
# METADATA
# title: No packages from internal registry
# description: Flags packages sourced from registry.internal.example.com.
# custom:
#   name: no-internal-registry
#   result_type: generic
#   weight: 5
#   not_compliant_title: Packages from internal registry found
#   details_order:
#   - purl
#   - reason
package docker.scout

import rego.v1

default pass := false

pass if {
    count(violation) == 0
}

violation contains v if {
    att := oci.referrer("https://scout.docker.com/sbom/v0.1")
    some pkg in att.statement.predicate.artifacts
    contains(pkg.purl, "registry.internal.example.com")
    v := {
        "message": sprintf("Package %s sourced from internal registry", [pkg.purl]),
        "detail": {
            "purl": pkg.purl,
            "reason": "matches registry.internal.example.com",
        },
    }
}
```

```console
# Single file
$ docker scout policy myorg/app:latest --policy-file ./no-internal-registry.rego

# Directory of policies
$ docker scout policy myorg/app:latest --policy-dir ./rego

# Custom policies combined with a config file
$ docker scout policy myorg/app:latest \
  --policy-dir ./rego \
  --policy-config ./policies.json
```

Both `--policy-file` and `--policy-dir` are repeatable. When either is
provided, the built-in defaults are not loaded automatically. To run both
built-in and custom policies together, publish the built-in set to a registry
with `docker scout policy publish`, then pass both bundles using
`--policy-bundle`:

```console
$ docker scout policy myorg/app:latest \
  --policy-bundle registry.example.com/default-policies:latest \
  --policy-bundle registry.example.com/dhi-policies:latest \
  --policy-file ./custom.rego
```

`--policy-bundle` is repeatable, so you can combine as many bundles as needed
alongside local policy files.

### Metadata annotations

The CLI reads [OPA metadata annotations](https://www.openpolicyagent.org/docs/latest/annotations/)
to render results. Place them in a `# METADATA` block immediately above the
`package` declaration.

| Annotation | Purpose |
| --- | --- |
| `title` | Human-readable policy name shown in the report |
| `description` | Longer explanation |
| `custom.name` | Stable ID used to match `--policy-config` entries. Defaults to the package path if omitted |
| `custom.result_type` | How violations are rendered: `vulnerability`, `license`, `boolean`, or `generic` (default) |
| `custom.weight` | Scoring weight and display sort order. Higher weights sort first in the report and contribute more to the [health score](#health-score). Defaults to `10` when omitted; a weight of `0` excludes the policy from the score |
| `custom.not_compliant_title` | Status label shown when the policy fails |
| `custom.details_order` | Ordered list of `detail` keys to display as columns |

### Output contract

- `pass`: `true` when the policy is met. The standard form is `pass if { count(violation) == 0 }`.
- `violation`: a set of objects. Each object should have a `message` string and
  a `detail` object whose keys match `custom.details_order`. An optional
  `remediation` string is shown as remediation guidance.

### Input and built-in functions

The evaluation input is the enriched SBOM. Key entry points:

- `input.source.image`: image metadata, including `input.source.image.config.config.User`,
  `input.source.image.name`, and `input.source.image.digest`.
- `data.config`: the per-policy `config` object from the policy-config file.

The following built-in functions are available in policy Rego:

| Function | Description |
| --- | --- |
| `oci.referrer(predicateType)` | Retrieve an attestation by predicate type |
| `oci.canonical_name(ref)` | Normalize an image reference, for example `"node:25"` to `"docker.io/library/node"` |
| `oci.image_digest(ref)` | Resolve the current digest of a tag from its registry |
| `oci.index(ref, digest)` | Get the OCI image index for an image |
| `oci.referrer_index(ref, digest)` | Get the OCI referrer index for an image |
| `oci.referrer_by_digest(ref, digest)` | Get a referrer for an image by digest |
| `scout.parse_purl(purl)` | Parse a PURL into its components |
| `scout.package_provenance(purl)` | Provenance of a package from the SBOM |
| `scout.vulnerabilities(purls)` | Vulnerabilities for the given PURLs |
| `scout.package_recommendation(purl)` | Recommended (fixed) version for a package |
| `scout.base_image()` | Base image matches recorded in the SBOM |
| `cosign.verify_dsse(envelope, opts)` | Verify an in-toto DSSE envelope's cosign signature |
| `cosign.verify_image(ref, opts)` | Verify an image's cosign signature |
| `gpg.verify_commit(...)` | Verify a detached commit signature |

Common predicate types for `oci.referrer`:

| Predicate type | Content |
| --- | --- |
| `https://scout.docker.com/vulnerabilities/v0.1` | CVEs per package |
| `https://scout.docker.com/sbom/v0.1` | SBOM artifacts, with `purl` and `licenses` |
| `https://scout.docker.com/provenance/v0.1` | Build provenance, including `base_image` |
| `https://openvex.dev/ns/v0.2.0` | VEX statements |

## Debug policies

Add `print()` statements to your Rego and enable debug output by setting
`"debug": true` in the policy-config file:

```rego
violation contains v if {
    att := oci.referrer("https://scout.docker.com/sbom/v0.1")
    some pkg in att.statement.predicate.artifacts
    print("checking", pkg.purl)
    contains(pkg.purl, blocked)
    # ...
}
```

```json
{
  "debug": true,
  "policies": [
    { "name": "no-internal-registry" }
  ]
}
```

Output is prefixed with the policy name and source line:

```text
no-internal-registry#28: checking pkg:deb/debian/curl@7.88.1
```

> [!NOTE]
>
> The `debug` field in the policy-config controls `print()` output from your
> Rego. The global `--debug` flag is separate: it enables CLI-level debug
> logging for bundle loading, registry resolution, and similar internals.

### Inspect raw evaluation results

Use `--result-file` to write the full evaluation result for every policy to a
JSON file. This is useful when iterating on a custom policy to inspect
intermediate values.

```console
$ docker scout policy myorg/app:latest \
  --policy-file ./no-internal-registry.rego \
  --result-file result.json
```

Each entry in the output contains:

- `pass`: the policy's boolean outcome.
- `violations`: the `detail` object of each reported violation.
- `bindings`: the raw `data.docker.scout` document, including the `violation`
  set and any other complete rules, for inspecting intermediate values.
- `metrics`: OPA evaluation metrics (timers and counters).

```json
{
  "no-internal-registry": {
    "pass": false,
    "violations": [
      { "purl": "pkg:deb/debian/curl@7.88.1", "reason": "matches \"registry.internal.example.com\"" }
    ],
    "bindings": {
      "blocked": "registry.internal.example.com",
      "violation": [
        {
          "message": "Package pkg:deb/debian/curl@7.88.1 sourced from internal registry",
          "detail": {
            "purl": "pkg:deb/debian/curl@7.88.1",
            "reason": "matches \"registry.internal.example.com\""
          }
        }
      ]
    },
    "metrics": {
      "timer_rego_query_eval_ns": 1234567
    }
  }
}
```

## Share policies as OCI bundles

Package `.rego` files as an OCI artifact and distribute them through any
registry.

### Publish a bundle

```console
# Publish a directory of policies
$ docker scout policy publish \
  --policy-dir ./rego \
  registry.example.com/my-policies:latest

# Publish specific files
$ docker scout policy publish \
  --policy-file fixable.rego \
  --policy-file licenses.rego \
  registry.example.com/my-policies:latest

# Publish the built-in default set
$ docker scout policy publish registry.example.com/my-policies:latest
```

Each module's metadata is validated before publishing. The command prints the
resulting digest and the list of bundled policies.

### Use a bundle

```console
$ docker scout policy myorg/app:latest \
  --policy-bundle registry.example.com/my-policies:latest

# Combine a bundle with local files and a config
$ docker scout policy myorg/app:latest \
  --policy-bundle registry.example.com/my-policies:latest \
  --policy-file ./extra.rego \
  --policy-config ./policies.json
```

`--policy-bundle` is repeatable. Authentication uses your existing Docker
registry credentials. Bundles are cached by digest, so re-running against the
same bundle does not re-download it. A new digest (for example, after
re-publishing `:latest`) is fetched automatically.


---

# Docker Scout quickstart

*Sección: Scout*

Docker Scout analyzes image contents and generates a detailed report of packages
and vulnerabilities that it detects. It can provide you with
suggestions for how to remediate issues discovered by image analysis.

This guide takes a vulnerable container image and shows you how to use Docker
Scout to identify and fix the vulnerabilities, compare image versions over time,
and share the results with your team.

## Step 1: Setup

[This example project](https://github.com/docker/scout-demo-service) contains
a vulnerable Node.js application that you can use to follow along.

1. Clone its repository:

   ```console
   $ git clone https://github.com/docker/scout-demo-service.git
   ```

2. Move into the directory:

   ```console
   $ cd scout-demo-service
   ```

3. Make sure you're signed in to your Docker account,
   either by running the `docker login` command or by signing in with Docker Desktop.

4. Build the image and push it to a `<ORG_NAME>/scout-demo:v1`,
   where `<ORG_NAME>` is the Docker Hub namespace you push to.

   ```console
   $ docker build --push -t <ORG_NAME>/scout-demo:v1 .
   ```

## Step 2: Enable Docker Scout

Docker Scout analyzes all local images by default. To analyze images in
remote repositories, you need to enable it first.
You can do this from Docker Hub, the Docker Scout Dashboard, and CLI.
[Find out how in the overview guide](/scout).

1. Sign in to your Docker account with the `docker login` command or use the
   **Sign in** button in Docker Desktop.

2. Next, enroll your organization with Docker Scout, using the `docker scout enroll` command.

   ```console
   $ docker scout enroll <ORG_NAME>
   ```

3. Enable Docker Scout for your image repository with the `docker scout repo enable` command.

   ```console
   $ docker scout repo enable --org <ORG_NAME> <ORG_NAME>/scout-demo
   ```

## Step 3: Analyze image vulnerabilities

After building, use the `docker scout` CLI command to see vulnerabilities
detected by Docker Scout.

The example application for this guide uses a vulnerable version of Express.
The following command shows all CVEs affecting Express in the image you just
built:

```console
$ docker scout cves --only-package express
```

Docker Scout analyzes the image you built most recently by default,
so there's no need to specify the name of the image in this case.

Learn more about the `docker scout cves` command in the
[`CLI reference documentation`](/reference/cli/docker/scout/cves).

## Step 4: Fix application vulnerabilities

After the Docker Scout analysis, a high vulnerability CVE-2022-24999 was found, caused by an outdated version of the **express** package.

The version 4.17.3 of the express package fixes the vulnerability. Therefore, update the `package.json` file to the new version:

   ```diff
      "dependencies": {
   -    "express": "4.17.1"
   +    "express": "4.17.3"
      }
   ```
   
Rebuild the image with a new tag and push it to your Docker Hub repository:

   ```console
   $ docker build --push -t <ORG_NAME>/scout-demo:v2 .
   ```

Run the `docker scout` command again and verify that HIGH CVE-2022-24999 is no longer present:

```console
$ docker scout cves --only-package express
    ✓ Provenance obtained from attestation
    ✓ Image stored for indexing
    ✓ Indexed 79 packages
    ✓ No vulnerable package detected


  ## Overview

                      │                  Analyzed Image                   
  ────────────────────┼───────────────────────────────────────────────────
    Target            │  mobywhale/scout-demo:v2                   
      digest          │  ef68417b2866                                     
      platform        │ linux/arm64                                       
      provenance      │ https://github.com/docker/scout-demo-service.git  
                      │  7c3a06793fc8f97961b4a40c73e0f7ed85501857         
      vulnerabilities │    0C     0H     0M     0L                        
      size            │ 19 MB                                             
      packages        │ 1                                                 


  ## Packages and Vulnerabilities

  No vulnerable packages detected

```

## Step 5: Evaluate policy compliance

While inspecting vulnerabilities based on specific packages can be useful,
it isn't the most effective way to improve your supply chain conduct.

Docker Scout also supports policy evaluation,
a higher-level concept for detecting and fixing issues in your images.
Policies are a set of customizable rules that let organizations track whether
images are compliant with their supply chain requirements.

Because policy rules are specific to each organization,
you must specify which organization's policy you're evaluating against.
Use the `docker scout config` command to configure your Docker organization.

```console
$ docker scout config organization <ORG_NAME>
    ✓ Successfully set organization to <ORG_NAME>
```

Now you can run the `quickview` command to get an overview
of the compliance status for the image you just built.
The image is evaluated against the default policy configurations. You'll see output similar to the following:

```console
$ docker scout quickview

...
Policy status  FAILED  (2/6 policies met, 2 missing data)

  Status │                  Policy                      │           Results
─────────┼──────────────────────────────────────────────┼──────────────────────────────
  ✓      │ No copyleft licenses                         │    0 packages
  !      │ Default non-root user                        │
  !      │ No fixable critical or high vulnerabilities  │    2C    16H     0M     0L
  ✓      │ No high-profile vulnerabilities              │    0C     0H     0M     0L
  ?      │ No outdated base images                      │    No data
  ?      │ Supply chain attestations                    │    No data
```

Exclamation marks in the status column indicate a violated policy.
Question marks indicate that there isn't enough metadata to complete the evaluation.
A check mark indicates compliance.

## Step 6: Improve compliance

The output of the `quickview` command shows that there's room for improvement.
Some of the policies couldn't evaluate successfully (`No data`)
because the image lacks provenance and SBOM attestations.
The image also failed the check on a few of the evaluations.

Policy evaluation does more than just check for vulnerabilities.
Take the `Default non-root user` policy for example.
This policy helps improve runtime security by ensuring that
images aren't set to run as the `root` superuser by default.

To address this policy violation, edit the Dockerfile by adding a `USER`
instruction, specifying a non-root user:

```diff
  CMD ["node","/app/app.js"]
  EXPOSE 3000
+ USER appuser
```

Additionally, to get a more complete policy evaluation result,
your image should have SBOM and provenance attestations attached to it.
Docker Scout uses the provenance attestations to determine how the image was
built so that it can provide a better evaluation result.

Before you can build an image with attestations,
you must enable the [containerd image store](../desktop/features/containerd.md)
(or create a custom builder using the `docker-container` driver).
The classic image store doesn't support manifest lists,
which is how the provenance attestations are attached to an image.

Open **Settings** in Docker Desktop. Under the **General** section, make sure
that the **Use containerd for pulling and storing images** option is checked, then select **Apply**.
Note that changing image stores temporarily hides images and containers of the
inactive image store until you switch back.

With the containerd image store enabled, rebuild the image with a new `v3` tag.
This time, add the `--provenance=true` and `--sbom=true` flags.

```console
$ docker build --provenance=true --sbom=true --push -t <ORG_NAME>/scout-demo:v3 .
```

## Step 7: View in Dashboard

After pushing the updated image with attestations, it's time to view the
results through a different lens: the Docker Scout Dashboard.

1. Open the [Docker Scout Dashboard](https://scout.docker.com/).
2. Sign in with your Docker account.
3. Select **Images** in the left-hand navigation.

The images page lists your Scout-enabled repositories.

Select the row for the image you want to view, anywhere in the row except on a link, to open the **Image details** sidebar.

The sidebar shows a compliance overview for the last pushed tag of a repository.

> [!NOTE]
>
> If policy results haven't appeared yet, try refreshing the page.
> It might take a few minutes before the results appear if this is your
> first time using the Docker Scout Dashboard.

Go back to the image list and select the image version, available in the **Most recent image** column.
Then, at the top right of the page, select the **Update base image** button to inspect the policy.

This policy checks whether base images you use are up-to-date.
It currently has a non-compliant status,
because the example image uses an old version `alpine` as a base image.

Close the **Recommended fixes for base image** modal. In the policy listing, select **View fixes** button, next to the policy name for details about the violation, and recommendations on how to address it.

In this case, the recommended action is to update the base image to a newer
version. You can use GitHub Dependabot with `package-ecosystem: "docker"` to
automate base image updates.

## Summary

This quickstart guide has scratched the surface on some of the ways
Docker Scout can support software supply chain management:

- How to enable Docker Scout for your repositories
- Analyzing images for vulnerabilities
- Policy and compliance
- Fixing vulnerabilities and improving compliance

## What's next?

There's lots more to discover, from third-party integrations,
to policy customization, and runtime environment monitoring in real-time.

Check out the following sections:

- [Image analysis](explore/analysis.md)
- [Data sources](/scout/advisory-db-sources)
- [Docker Scout Dashboard](/scout/dashboard)
- [Integrations](integrations/index.md)
- [Policy evaluation](policy/index.md)


---

# Release notes

*Sección: Scout*




---

# Cli

*Sección: Scout*

---
title: CLI release notes
params:
  sidebar:
    goto: "https://github.com/docker/scout-cli/releases"
---


---

# Docker Scout release notes

*Sección: Scout*

<!-- vale Docker.We = NO -->

This page contains information about the new features, improvements, known
issues, and bug fixes in Docker Scout releases. These release notes cover the
Docker Scout platform, including the Dashboard. For CLI release notes, refer to
[Docker Scout CLI release notes](cli.md).

## Q2 2026

### 2026-09-01

The following Docker Scout features were retired:

- Notifications: In-product and email notifications about newly disclosed CVEs.
  Integrate `docker scout cves` or `docker scout policy` into your CI pipeline
  to surface vulnerability and policy results without push notifications.
- Native Amazon ECR integration: ECR is still supported using
  [`docker scout watch`](../integrations/registry.md) for continuous
  polling, or by integrating Scout into your CI pipeline.
- Native Azure Container Registry integration: ACR is still supported using
  the same options as ECR.
- Policies page in the Dashboard: The `docker scout policy`
  command replaces this with more options for evaluating policies. You can run
  evaluations locally, in CI, against custom Rego policies, or using OCI
  bundles. See [Evaluate policies](../policy/local.md).
- SonarQube integration.

### 2026-07-30

The following Docker Scout feature was retired:

- Slack integration: Integrate `docker scout cves` or `docker scout policy`
  into your CI pipeline to surface vulnerability and policy results without
  push notifications.

### 2026-07-01

The following Docker Scout features were retired:

- Health scores and Scout Everywhere: Docker Hub and Docker Desktop no longer
  display health scores or the always-on Scout experience. Use
  `docker scout quickview` for a quick vulnerability and policy summary. This is
  unrelated to the health score reported locally by `docker scout policy`,
  `docker scout quickview`, and `docker scout compare`. See
  [Health score](../policy/local.md#health-score).
- Sysdig integration: The Sysdig runtime environment integration has been removed.
- GitHub source code management integration: Migrate to GitHub Dependabot for
  base-image updates and build with `--provenance=mode=max` for
  image-to-source linkage.

The following is deprecated and will be retired on July 30, 2026:

- Slack integration: Vulnerability and policy compliance notifications to Slack
  channels.

The following are deprecated and will be retired on September 1, 2026:

- Notifications: In-product and email notifications about newly disclosed CVEs.
- Amazon ECR integration: Automatically analyzed images pushed to ECR
  registries.
- Azure Container Registry integration: Automatically analyzed images pushed
  to ACR registries.
- Policies page in the Dashboard: Provided a visual interface in the Docker
  Scout Dashboard for tracking policy compliance.
- SonarQube integration.

## Q4 2024

New features and enhancements released in the fourth quarter of 2024.

### 2024-10-09

Policy Evaluation has graduated from Early Access to General Availability.

Docker Scout Dashboard UI changes:

- On the Docker Scout Dashboard, selecting a policy card now opens the policy
  details page instead of the policy results page.
- The policy results page and the policy details side panel are now read-only.
  Policy actions (edit, disable, delete) are now accessible from the policy
  details page.

## Q3 2024

New features and enhancements released in the third quarter of 2024.

### 2024-09-30

In this release, we've changed how custom policies work. Before, custom
policies were created by copying an out-of-the-box policy. Now, you can
customize policies either by editing the default policy from a **policy type**
which acts as a template. The default policies in Docker Scout are also
implemented based on these types.

For more information, refer to [policy types](../policy/index.md#policy-types).

### 2024-09-09

This release changes how health scores are
calculated in Docker Scout. The health score calculation now considers optional
and custom policies that you have configured for your organization.

This means that if you have enabled, disabled, or customized any of the default
policies, Docker Scout will now take those policies into account when
calculating the health score for your organization's images.

If you haven't yet enabled Docker Scout for your organization, the health score
calculation will be based on the out-of-the-box policies.

### 2024-08-13

This release changes the out-of-the-box policies to align with the policy
configurations used to evaluate Docker Scout health scores.

The default out-of-the-box policies are now:

- **No high-profile vulnerabilities**
- **No fixable critical or high vulnerabilities**
- **Approved Base Images**
- **Default non-root user**
- **Supply chain attestations**
- **Up-to-Date Base Images**
- **No AGPL v3 licenses**

The configurations for these policies are now the same as the configurations
used to calculate health scores. Previously, the out-of-the-box policies had
different configurations than the health score policies.

## Q2 2024

New features and enhancements released in the second quarter of 2024.

### 2024-06-27

This release introduces initial support for **Exceptions** in the Docker Scout
Dashboard. Exceptions let you suppress vulnerabilities found in your images
(false positives), using VEX documents. Attach VEX documents to images as
attestations, or embed them on image filesystems, and Docker Scout will
automatically detect and incorporate the VEX statements into the image analysis
results.

The new [Exceptions page](https://scout.docker.com/reports/vex/) lists all
exceptions affecting images in your organization. You can also go to the image
view in the Docker Scout Dashboard to see all exceptions that apply to a given
image.

For more information, see [Manage vulnerability exceptions](../explore/exceptions.md).

### 2024-05-06

New HTTP endpoint that lets you scrape data from Docker Scout with Prometheus,
to create your own vulnerability and policy dashboards with Grafana.
For more information, see [Docker Scout metrics exporter](../explore/metrics-exporter.md).

## Q1 2024

New features and enhancements released in the first quarter of 2024.

### 2024-03-29

The **No high-profile vulnerabilities** policy now reports the `xz` backdoor
vulnerability [CVE-2024-3094](https://scout.docker.com/v/CVE-2024-3094). Any
images in your Docker organization containing the version of `xz/liblzma` with
the backdoor will be non-compliant with the **No high-profile vulnerabilities**
policy.

### 2024-03-20

The **No fixable critical or high vulnerabilities** policy now supports a
**Fixable vulnerabilities only** configuration option, which lets you decide
whether or not to only flag vulnerabilities with an available fix version.

### 2024-03-14

The **All critical vulnerabilities** policy has been removed.
The **No fixable critical or high vulnerabilities** policy provides similar functionality,
and will be updated in the future to allow for more extensive customization,
making the now-removed **All critical vulnerabilities** policy redundant.

### 2024-01-26

**Azure Container Registry** integration graduated from
[Early Access](../../release-lifecycle.md#early-access-ea) to
[General Availability](../../release-lifecycle.md#general-availability-ga).

For more information and setup instructions, see
Integrate Azure Container Registry.

### 2024-01-23

New **Approved Base Images** policy, which lets you restrict which base
images you allow in your builds. You define the allowed base images using a
pattern. Base images whose image reference don't match the specified patterns
cause the policy to fail.

### 2024-01-12

New **Default non-root user** policy, which flags images that would run as the
`root` superuser with full system administration privileges by default.
Specifying a non-root default user for your images can help strengthen your
runtime security.

### 2024-01-11

[Beta](../../release-lifecycle.md#beta) launch of a new GitHub app for integrating
Docker Scout with your source code management, and a remediation feature for
helping you improve policy compliance.

Remediation is a new capability for Docker Scout to provide contextual,
recommended actions based on policy evaluation results on how you can improve
compliance.

The GitHub integration enhances the remediation feature. With the integration
enabled, Docker Scout is able to connect analysis results to the source. This
additional context about how your images are built is used to generate better,
more precise recommendations.

For more information about the types of recommendations that Docker Scout can
provide to help you improve policy compliance, see
Use the Dashboard.

For more information about how to authorize the Docker Scout GitHub app on your
source repositories, see Integrate Docker Scout with GitHub.

## Q4 2023

New features and enhancements released in the fourth quarter of 2023.

### 2023-12-20

**Azure Container Registry** integration graduated from
[Beta](../../release-lifecycle.md#beta) to
[Early Access](../../release-lifecycle.md#early-access-ea).

For more information and setup instructions, see
Integrate Azure Container Registry.

### 2023-12-06

New [SonarQube](https://www.sonarsource.com/products/sonarqube/) integration
and related policy. SonarQube is an open-source platform for continuous
inspection of code quality. This integration lets you add SonarQube's quality
gates as a policy evaluation in Docker Scout. Enable the integration, push your
images, and see the SonarQube quality gate conditions surfaced in the new
**SonarQube quality gates passed** policy.

### 2023-12-01

[Beta](../../release-lifecycle.md#beta) release of a new **Azure Container
Registry** (ACR) integration, which lets Docker Scout pull and analyze images
in ACR repositories automatically.

To learn more about the integration and how to get started, see
Integrate Azure Container Registry.

### 2023-11-21

New **configurable policies** feature, which enables you to tweak the
out-of-the-box policies according to your preferences, or disable them entirely
if they don't quite match your needs. Some examples of how you can adapt
policies for your organization include:

- Change the severity-thresholds that vulnerability-related policies use
- Customize the list of "high-profile vulnerabilities"
- Add or remove software licenses to flag as "copyleft"

For more information, see Configurable policies.

### 2023-11-10

New **Supply chain attestations** policy for helping you track whether your
images are built with SBOM and provenance attestations. Adding attestations to
images is a good first step in improving your supply chain conduct, and is
often a prerequisite for doing more.

### 2023-11-01

New **No high-profile vulnerabilities** policy, which ensures your artifacts are
free from a curated list of vulnerabilities widely recognized to be risky.

### 2023-10-04

This marks the General Availability (GA) release of Docker Scout.

The following new features are included in this release:

- [Policy Evaluation](#policy-evaluation) (Early Access)
- [Amazon ECR integration](#amazon-ecr-integration)
- [Sysdig integration](#sysdig-integration)
- [JFrog Artifactory integration](#jfrog-artifactory-integration)

#### Policy evaluation

Policy Evaluation is an early access feature that helps you ensure software
integrity and track how your artifacts are doing over time. This release ships
with four out-of-the-box policies, enabled by default for all organizations.

![Policy overview in Dashboard](../images/release-notes/policy-ea.webp)

- **Base images not up-to-date** evaluates whether the base images are out of
  date, and require updating. Up-to-date base images help you ensure that your
  environments are reliable and secure.
- **Critical and high vulnerabilities with fixes** reports if there are
  vulnerabilities with critical or high severity in your images, and where
  there's a fix version available that you can upgrade to.
- **All critical vulnerabilities** looks out for any vulnerabilities of
  critical severity found in your images.
- **Packages with AGPLv3, GPLv3 license** helps you catch possibly unwanted
  copyleft licenses used in your images.

You can view and evaluate policy status for images using the Docker Scout
Dashboard and the `docker scout policy` CLI command. For more information,
refer to the [Policy Evaluation documentation](/scout/policy/).

#### Amazon ECR integration

The new Amazon Elastic Container Registry (ECR) integration enables image
analysis for images hosted in ECR repositories.

You set up the integration using a pre-configured CloudFormation stack template
that bootstraps the necessary AWS resources in your account. Docker Scout
automatically analyzes images that you push to your registry, storing only the
metadata about the image contents, and not the container images themselves.

The integration offers a straightforward process for adding additional
repositories, activating Docker Scout for specific repositories, and removing
the integration if needed. To learn more, refer to the Amazon ECR integration
documentation.

#### Sysdig integration

The new Sysdig integration gives you real-time security insights for your
Kubernetes runtime environments.

Enabling this integration helps you address and prioritize risks for images
used to run your production workloads. It also helps reduce monitoring noise,
by automatically excluding vulnerabilities in programs that are never loaded
into memory, using VEX documents.

For more information, see the [Scout platform release notes](#2026-07-01).

#### JFrog Artifactory integration

The new JFrog Artifactory integration enables automatic image analysis on
Artifactory registries.

The integration involves deploying a Docker Scout Artifactory agent that polls
for new images, performs analysis, and uploads results to Docker Scout, all
while preserving the integrity of image data.

#### Known limitations

- Image analysis only works for Linux images
- Docker Scout can't process images larger than 12GB in compressed size
- Creating an image SBOM (part of image analysis) has a timeout limit of 4 minutes


---

# Security

*Sección: Security*

Security helps individual users and organization owners secure their
accounts, manage access, and control membership. You configure these
settings in [Docker Home](https://app.docker.com/).

## Individual accounts

You sign in with your individual account.

- [Two-factor authentication](authentication/2fa/index.md)
(2FA) adds a time-based one-time password (TOTP) from an authenticator
app to your password.
- A [personal access token](access-tokens/personal-access-tokens.md)
(PAT) authenticates the Docker CLI and tools without your password, and
is required for CLI sign-in when 2FA is on or single sign-on (SSO) is
enforced.

## Organization accounts

Organization and company owners set up how members sign in, add them to
the organization, configure automation, and control what members can do.

- [Single sign-on](authentication/single-sign-on/index.md)
(SSO) federates sign-in through your identity provider, which can cover
one organization or every organization in a company.
- [Provisioning](provisioning/index.md) adds users with
System for Cross-domain Identity Management (SCIM), Just-in-Time (JIT)
provisioning, auto-provisioning, or domain matching.
- An [organization access token](access-tokens/organization-access-tokens.md)
(OAT) stays with the organization when membership changes.
- [OIDC connections](authentication/oidc-connections/index.md)
use OpenID Connect to authenticate GitHub Actions with short-lived
tokens, as an alternative to a long-lived OAT.
- [Roles and permissions](roles-and-permissions/index.md)
control what members can do after they join.

## Next steps

{{< grid >}}


---

# Access tokens

*Sección: Security*

Access tokens let you authenticate to Docker Hub without using your password.
Use a token for the Docker CLI, automation, and any account that has
two-factor authentication (2FA) or enforced single sign-on (SSO), because
password sign-in to the CLI is not supported in those cases.

## Choose a token type

| Token | Ownership | Use when | Limitations |
| --- | --- | --- | --- |
| Personal access token (PAT) | Tied to an individual Docker account | CLI access, local tools, and automation that should run as you. Required for CLI sign-in when 2FA is on or SSO is enforced | Access ends if the account leaves the organization or the token is revoked |
| Organization access token (OAT) | Owned by the organization. Any organization owner can manage it | CI/CD and other automation that must keep working when membership changes | Incompatible with Docker Desktop and Image Access Management |

For GitHub Actions, [OIDC connections](../authentication/oidc-connections/index.md)
are an alternative to storing a long-lived organization access token.

## Next steps

{{< grid >}}


---

# Organization access tokens

*Sección: Security*

{{< summary-bar feature_name="OATs" >}}

Organization access tokens (OATs) provide secure, programmatic access to Docker Hub for automated systems, CI/CD pipelines, and other business-critical tasks. Unlike personal access tokens tied to individual users, OATs are associated with your organization and can be managed by any organization owner.

> [!WARNING]
>
> Organization access tokens are incompatible with Docker Desktop and Image Access Management. If you use these features, use [personal access tokens](personal-access-tokens.md) instead.

## Who should use organization access tokens?

Use OATs for automated systems that need Docker Hub access without depending on individual user accounts:

- CI/CD pipelines: Build and deployment systems that push and pull images
- Production systems: Applications that pull images during deployment
- Monitoring tools: Systems that need to check repository status or pull images
- Backup systems: Tools that periodically pull images for archival
- Integration services: Third-party tools that integrate with your Docker Hub repositories

## Key benefits

Benefits of using organization access tokens include:

- Organizational ownership: Not tied to individual users who might leave the company
- Shared management: All organization owners can create and manage OATs
- Separate usage limits: OATs have their own Docker Hub rate limits, not counting against personal accounts
- Better security audit: Track when tokens were last used and identify suspicious activity
- Granular permissions: Limit access to specific repositories and operations

## Prerequisites

To create and use organization access tokens, you must have:

- A Docker Team or Business subscription
- Owner permissions
- Repositories you want to grant access to

## Create an organization access token

Owners can create tokens with these limits:

- Team subscription: Up to 10 OATs per organization
- Business subscription: Up to 100 OATs per organization

Expired tokens count toward your total limit.

To create an OAT:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
organization.
1. Select **Identity & auth**, then **Access tokens**.
1. Select **Generate access token**.
1. Configure token details:
    - Label: Descriptive name indicating the token's purpose
    - Description (optional): Additional details
    - Expiration date: When the token should expire
1. Expand the **Repository** drop-down to set per-repository access permissions:
    - Optional. Select **Read public repositories** for access to public repositories.
    - Select **Add repository** and choose a repository from the drop-down.
    - Set the permission level for each repository. Available scopes range from
       pulling and pushing images to managing tags, webhooks, repository groups,
       and immutable tag settings. See [Repository scopes](#repository-scopes)
       for the full list.
    - Add up to 50 repositories as needed.
1. Optional. Configure organization-level permissions by expanding the **Organization** drop-down and selecting **Allow management access to this organization's resources**:
    - **Member Edit**: Edit members of the organization
    - **Member Read**: Read members of the organization
    - **Invite Edit**: Invite members to the organization
    - **Invite Read**: Read invites to the organization
    - **Group Edit**: Edit groups of the organization
    - **Group Read**: Read groups of the organization
    - **Repository List**: List all repositories, including private ones (`scope-repository-list`)
    - **Repository Create**: Create new repositories (`scope-repository-create`)
    - **Registry Usage Read**: Read namespace-level registry usage metrics (`scope-registry-usage-read`)
1. Select **Generate token**. Copy the token that appears on the screen and save it. You won't be able to retrieve the token once you exit the screen.

> [!IMPORTANT]
>
> Treat organization access tokens like passwords. Store them securely in a credential manager and never commit them to source code repositories.

## Use organization access tokens

Sign in to the Docker CLI using your organization access token:

```console
$ docker login --username <YOUR_ORGANIZATION_NAME>
Password: [paste your OAT here]
```

When prompted for a password, enter your organization access token.

## Modify existing tokens

To manage existing tokens:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
organization.
1. Select **Identity & auth**, then **Access tokens**.
1. Select the actions menu in the token row, you can:
    - **Edit**
    - **Deactivate**
    - **Delete**
1. Select **Save** after making changes to a token.

## Available scopes

Scopes control what an OAT can do. Repository-level scopes are assigned per
repository when you create the token. Organization-level scopes apply to the
whole organization.

Higher scopes include the permissions of lower ones where noted.

### Repository scopes

| Scope | Description | Includes |
|---|---|---|
| `scope-image-pull` | Pull images from the registry | — |
| `scope-image-push` | Push images to the registry | `scope-image-pull` |
| `scope-image-delete` | Delete images and tags via registry endpoints | `scope-image-push` |
| `scope-repository-read` | Read repository metadata, Dockerfile, and stars | — |
| `scope-repository-edit` | Edit repository privacy, categories, Dockerfile, description, and stars | `scope-repository-read` |
| `scope-repository-admin` | Delete the repository | `scope-repository-edit` |
| `scope-tag-read` | List and read tags, image lists, attestations, and compose files | — |
| `scope-tag-admin` | Delete tags | `scope-tag-read` |
| `scope-webhook-read` | List webhook pipelines and delivery history | — |
| `scope-webhook-edit` | Create webhook pipelines | `scope-webhook-read` |
| `scope-webhook-admin` | Delete webhook pipelines | `scope-webhook-edit` |
| `scope-repo-group-read` | List and read repository group assignments | — |
| `scope-repo-group-edit` | Create and update repository group assignments | `scope-repo-group-read` |
| `scope-repo-group-admin` | Delete repository group assignments | `scope-repo-group-edit` |
| `scope-repository-settings-admin` | Configure immutable tag rules | — |

### Organization scopes

| Scope | Description |
|---|---|
| `scope-repository-list` | List all repositories in the namespace, including private ones |
| `scope-repository-create` | Create new repositories |
| `scope-registry-usage-read` | Read namespace-level registry usage metrics |

Creating a repository requires the organization-level `scope-repository-create`
permission. No repository-level scope, including admin scopes on existing
repositories, grants this permission.

## Hub API support

OATs can authenticate requests to most Docker Hub API endpoints under
`/v2/namespaces/{namespace}/repositories/`. Pass the token as a Bearer token
in the `Authorization` header with your organization name as the username.

### Supported endpoints

The following endpoint categories accept OAT authentication:

- Repository management: list, create, get, update, and delete repositories
- Tags: list, get, and delete tags; get tag images, attestations, and compose files
- Dockerfile: get and update a repository's linked Dockerfile
- Repository groups: list, get, create, update, and delete group assignments
- Stars: list, count, add, and remove repository stars
- Immutable tags: update and verify immutable tag policies
- Repository categories, privacy, and webhook pipeline settings
- Namespace metrics

### Listing behavior

`GET /v2/namespaces/{namespace}/repositories` returns results based on the
token's configured scopes:

- **With `scope-repository-list` scope** (or equivalent): all repositories are
  returned, including private ones.
- **Without that scope**: only public repositories are returned.

This filtering is silent: the response is a normal `200`, with no error or
indicator that private repositories were withheld.

### Unsupported legacy endpoints

OATs only authenticate requests to the namespace-scoped routes documented
above. The following legacy repository paths are OAT unsupported and reject
every OAT with `403 token issued from organization access token is not
allowed`, regardless of the token's scopes. Use the linked replacement
endpoints instead:

- `GET /v2/repositories/{namespace}/{repository}` — use
  [Get repository](/reference/api/hub/latest/#tag/repositories/operation/GetRepository).
- `GET /v2/repositories/{namespace}` — use
  [List repositories](/reference/api/hub/latest/#tag/repositories/operation/listNamespaceRepositories).
- `GET /v2/users/{username}/repositories` — use
  [List repositories](/reference/api/hub/latest/#tag/repositories/operation/listNamespaceRepositories).

## Organization access token best practices

- Regular token rotation: Set reasonable expiration dates and rotate tokens regularly to minimize security risks.
- Principle of least privilege: Grant only the minimum repository access and permissions needed for each use case.
- Monitor token usage: Regularly review when tokens were last used to identify unused or suspicious tokens.
- Secure storage: Store tokens in secure credential management systems, never in plain text or source code.
- Immediate revocation: Deactivate or delete tokens immediately if they're compromised or no longer needed.


---

# Personal access tokens

*Sección: Security*

{{< summary-bar feature_name="PATs" >}}

Personal access tokens (PATs) provide a secure alternative to passwords for Docker CLI authentication. Use PATs to authenticate automated systems, CI/CD pipelines, and development tools without exposing your Docker Hub password.

## Key benefits

PATs offer significant security advantages over password authentication:

- Enhanced security: Investigate token usage, disable suspicious tokens, and prevent administrative actions that could compromise your account if your system is compromised.
- Better automation: Issue multiple tokens for different integrations, each with specific permissions, and revoke them independently when no longer needed.
- Two-factor authentication compatibility: Required when you have two-factor authentication turned on, providing secure CLI access without bypassing 2FA protection.
- Usage tracking: Monitor when and how tokens are used to identify potential security issues or unused automation.

## Who should use personal access tokens?

Use PATs for these common scenarios:

- Development workflows: Authenticate Docker CLI during local development
- CI/CD pipelines: Automate image builds and deployments in continuous integration systems
- Automation scripts: Push and pull images in automated deployment or backup scripts
- Development tools: Integrate Docker Hub access with IDEs, container management tools, or monitoring systems
- Two-factor authentication: Required for CLI access when 2FA is turned on

> [!NOTE]
>
> For organization-wide automation, consider [organization access tokens](organization-access-tokens.md) which aren't tied to individual user accounts.

## Create a personal access token

> [!IMPORTANT]
>
> Treat access tokens like passwords and keep them secure. Store tokens in credential managers and never commit them to source code repositories.

To create a personal access token:

1. Sign in to [Docker Home](https://app.docker.com/).
1. Select your avatar in the top-right corner and from the drop-down menu select **Account settings**.
1. Select **Personal access tokens**.
1. Select **Generate new token**.
1. Configure your token:
   - **Description:** Use a descriptive name that indicates the token's purpose
   - **Expiration date:** Set an expiration date based on your security policies
   - **Access permissions:** **Read**, **Write**, or **Delete**.
1. Select **Generate**. Copy the token that appears on the screen and save it. You won't be able to retrieve the token once you exit the screen.

## Use personal access tokens

Sign in to the Docker CLI using your personal access token:

```console
$ docker login --username <YOUR_USERNAME>
Password: [paste your PAT here]
```

When prompted for a password, enter your personal access token instead of your Docker Hub password.

## Modify personal access tokens

> [!NOTE]
>
> You can't edit the expiration date on an existing personal access token. You must create a new PAT if you need to set a new expiration date.

You can rename, activate, deactivate, or delete a token as needed. You can manage your tokens in your account settings.

1. Sign in to [Docker Home](https://app.docker.com/login).
1. Select your avatar in the top-right corner and from the drop-down menu select **Account settings**.
1. Select **Personal access tokens**.
      - This page shows an overview of all your tokens, and lists if the token was generated manually or if it was
   [auto-generated](#auto-generated-tokens). You can also view the scope of the
   tokens, which tokens are activate and inactive, when they were created, when
   they were last used, and their expiration date.
1. Select the actions menu on the far right of a token row, then select **Deactivate** or **Activate**, **Edit**, or **Delete** to modify the token.
1. After editing the token, select **Save token**.

## Auto-generated tokens

Docker Desktop automatically creates authentication tokens when you sign in, with these characteristics:

- Automatic creation: Generated when you sign in to Docker Desktop
- Full permissions: Include Read, Write, and Delete access
- Session-based: Automatically removed when Docker Desktop session expires
- Account limits: Up to 5 auto-generated tokens per account
- Automatic cleanup: Older tokens are deleted when new ones are created

You can manually delete auto-generated tokens if needed, but they'll be recreated when you use Docker Desktop.

## Fair use policy

When using personal access tokens, be aware that excessive token creation may result in throttling or additional charges. Docker reserves the right to impose restrictions on accounts with excessive PAT usage to ensure fair resource allocation and maintain service quality.

Best practices for fair use include:

- Reuse tokens across similar use cases instead of creating many single-purpose tokens
- Delete unused tokens regularly
- Use [organization access tokens](organization-access-tokens.md) for organization-wide automation
- Monitor token usage to identify optimization opportunities


---

# Enable two-factor authentication for your Docker account

*Sección: Security*

{{< summary-bar feature_name="2FA" >}}

Two-factor authentication (2FA) adds an essential security layer to your Docker account by requiring a unique security code in addition to your password when signing in. This prevents unauthorized access even if your password is compromised.

When you turn on two-factor authentication, Docker provides a unique recovery code specific to your account. Store this code securely as it lets you recover your account if you lose access to your authenticator app.

## Key benefits

Two-factor authentication significantly improves your account security:

- Protection against password breaches: Even if your password is stolen or leaked, attackers can't access your account without your second factor.
- Secure CLI access: Required for Docker CLI authentication when 2FA is turned on, ensuring automated tools use personal access tokens instead of passwords.
- Compliance requirements: Many organizations require 2FA for accessing development and production resources.
- Peace of mind: Know that your Docker repositories, images, and account settings are protected by industry-standard security practices.

## Prerequisites

Before turning on two-factor authentication, you need:

- A smartphone or device with a Time-based One-time password (TOTP) authenticator app installed
- Access to your Docker account password

## Enable two-factor authentication

To turn on 2FA for your Docker account:

1. Sign in to your [Docker account](https://app.docker.com/login).
1. Select your avatar and then from the drop-down menu, select **Account settings**.
1. Select **2FA**.
1. Enter your account password, then select **Confirm**.
1. Save your recovery code and store it somewhere safe. You can use your recovery code to recover your account in the event you lose access to your authenticator app.
1. Use a TOTP mobile app to scan the QR code or enter the text code.
1. Once you've linked your authenticator app, enter the six-digit code in the text-field.
1. Select **Enable 2FA**.

Two-factor authentication is now active on your account. You'll need to enter a security code from your authenticator app each time you sign in.

## Disable two-factor authentication

> [!WARNING]
>
> Disabling two-factor authentication results in decreased security for your Docker account.

1. Sign in to your [Docker account](https://app.docker.com/login).
2. Select your avatar and then from the drop-down menu, select **Account settings**.
3. Select **2FA**.
4. Enter your password, then select **Confirm**.
5. Select **Disable 2FA**.


---

# Recover your Docker account

*Sección: Security*

{{< summary-bar feature_name="2FA" >}}

This page explains how to recover your Docker account and manage recovery codes for two-factor authentication.

## Generate a new recovery code

If you lost your two-factor authentication recovery code but still have access to your Docker Hub account, you can generate a new recovery code.

1. Sign in to your [Docker account](https://app.docker.com/login) with your username and password.
1. Select your avatar and from the drop-down menu, select **Account settings**.
1. Select **2FA**.
1. Enter your password, then select **Confirm**.
1. Select **Generate new code**.

This generates a new code. Select the visibility icon to view the code. Save your recovery code and store it somewhere safe.

## Recover your account without access

If you lost access to both your two-factor authentication application and your recovery code:

1. Sign in to your [Docker account](https://app.docker.com/login) with your username and password.
1. Select **I've lost my authentication device** and **I've lost my recovery code**.
1. Complete the [Contact Support form](https://hub.docker.com/support/contact/?category=2fa-lockout).

You must enter the primary email address associated with your Docker ID in the Contact Support form for recovery instructions.


---

# Authentication

*Sección: Security*

Authentication in Docker Home is how users and workloads prove who they are
before they access Docker products.

Two-factor authentication (2FA) protects an individual account. Single
sign-on (SSO) federates sign-in for an organization or company. OpenID
Connect (OIDC) connections authenticate CI workloads such as GitHub Actions.

## Choose an authentication method

| Method | Who it covers | Who configures it | How authentication works |
| --- | --- | --- | --- |
| Two-factor authentication (2FA) | An individual Docker account | The account holder | Password plus a time-based one-time password (TOTP) from an authenticator app |
| Single sign-on (SSO) | An organization or company | An organization or company owner | Users sign in through the organization's identity provider (IdP) |
| OIDC connections | GitHub Actions and similar workloads | An organization owner or editor | Docker exchanges short-lived tokens issued per workflow run |

SSO requires a Docker Business subscription. OIDC connections require a
Docker Team or Business subscription.

To require Docker Desktop users to sign in as organization members, see
[Enforce sign-in](../../enterprise/security/enforce-sign-in/index.md).
Enforce sign-in is configured in Enterprise, not in this section.

## Next steps

{{< grid >}}


---

# OIDC connections overview

*Sección: Security*

{{< summary-bar feature_name="OIDC connections" >}}

OIDC connections create a trust relationship between Docker and a trusted
third party so you don't have to maintain long-lived credentials. When you
create an OIDC connection, Docker exchanges short-lived tokens with another
vendor that can grant fine-grained access to your Docker resources.

## How OIDC connections work

OIDC connections follow the OpenID Connect (OIDC) standard. Establishing a
trust relationship involves creating the connection, configuring a
workflow, and testing. For example, a trust relationship between Docker and
GitHub follows these steps:

- GitHub issues a JWT ID token for the workflow run.
- During authentication, Docker:
  - Verifies the token against GitHub's public key registry
  - Matches subject claims against rulesets created in
    [Docker Home](https://app.docker.com/)
- Docker returns an access token so the GitHub Action can sign in to Docker
  and access resources.

All tokens created and exchanged during an OIDC workflow are short-lived
and issued on a per-workflow basis.

For how OIDC connections compare to organization access tokens, see
[Access tokens](../../access-tokens/index.md).

## Next steps

- [Create an OIDC connection](create-manage.md)
- [OIDC rulesets and subject claims](rulesets-claims.md)


---

# Create and manage OIDC connections

*Sección: Security*

{{< summary-bar feature_name="OIDC connections" >}}

Organization owners and editors create and manage OIDC connections from
**OIDC connections** in Docker Home. After you create a connection,
configure your GitHub Actions workflow so it can sign in to Docker Hub
with a short-lived token.

> [!NOTE]
> OIDC connections support only GitHub as a trusted third party.

## Create an OIDC connection

1. Sign in to [Docker Home](https://app.docker.com/), select your
   organization, then go to **Identity & auth**.
1. Select **OIDC connections**.
1. Select **Create OIDC connection** and fill in the OIDC connection form.
   - Provide rulesets and subject claims. Other values are optional.
   - For rulesets, subject claims, and resources, see
     [OIDC connections rulesets and subject claims](rulesets-claims.md).
1. Select **Create connection**.
1. Copy your OIDC connection ID.

## Configure a GitHub Actions workflow

Use `docker/login-action` version 4.5.0 or later. The action exchanges
the GitHub OIDC token and signs in to Docker Hub in a single step.

1. Add the following to your workflow YAML. Replace `<YOUR_ORG_NAME>`
   with your Docker organization name and `<YOUR_CONNECTION_ID>` with
   the ID you copied from Docker Home:

   ```yaml
   permissions:
     contents: read
     id-token: write

   jobs:
     build:
       runs-on: ubuntu-latest
       steps:
         - name: Docker login
           uses: docker/login-action@v4 # v4.5.0+
           with:
             username: <YOUR_ORG_NAME>
           env:
             DOCKERHUB_OIDC_CONNECTIONID: <YOUR_CONNECTION_ID>
   ```

   The `username` value must be a Docker organization name. Only
   organization accounts can sign in using OIDC.

1. Run the workflow and confirm it can sign in to Docker.

## Manage OIDC connections

You can view, edit, deactivate, or delete connections from the **OIDC
connections** page.

1. Select **Identity & auth**, then **OIDC connections**.
1. Find the row with your target connection ID.
1. Select the action menu icon for your options.
   - **Edit** opens the **Edit OIDC connection** page where you can copy
     your connection ID, update rulesets, or view the **Failures** table.
   - **Deactivate** temporarily disables access to your GitHub workflow.
   - **Activate** restores access to your GitHub workflow.
   - **Delete** permanently deletes a connection.

## Deactivate or delete a connection

Deactivate an OIDC connection to pause GitHub workflow access to your
Docker resources without deleting the connection. A deactivated
connection does not issue Docker access tokens, so `docker/login-action`
fails at the token-exchange step until you activate the connection.

> [!WARNING]
> Deleting an OIDC connection is permanent. Any workflow that still sets
> `DOCKERHUB_OIDC_CONNECTIONID` to the deleted ID fails at the
> token-exchange step. Update that environment variable with a
> replacement connection ID in every affected workflow before it runs
> again.

## Next steps

- [OIDC connections rulesets and subject claims](rulesets-claims.md)


---

# OIDC connections rulesets and subject claims

*Sección: Security*

{{< summary-bar feature_name="OIDC connections" >}}

Rulesets and subject claims define what actions your GitHub workflows can
take with your Docker resources. Use them to authorize GitHub workflow
behaviors for an OIDC connection.

## Rulesets

A ruleset is a set of conditions that Docker evaluates against an incoming
GitHub ID token. When a workflow triggers an OIDC exchange, Docker checks
the token against every ruleset defined in your connection. If a ruleset's
conditions are satisfied, Docker grants access based on the parameters set
by that ruleset.

Each ruleset contains the following fields:

- Label: A name for the ruleset.
- Rules: One or more conditions based on OIDC token claims, such as the
  repository name, branch, or workflow path.
  - These are expressed as subject claim strings.
  - See [Subject claims](#subject-claims).
- Resources: The Docker resources a workflow can access when the ruleset
  matches. See [Resources](#resources).
- Scopes: The permissions granted on those resources, such as read or write
  access.

You can define between 1 and 5 rulesets per connection. Use multiple
rulesets to apply different access levels across different workflows or
branches. If more than one ruleset matches an incoming token, Docker merges
the resources from all matching rulesets and grants access to the combined
set.

## Subject claims

A subject claim is the `sub` field in a GitHub-issued JWT ID token. It
encodes details of a workflow into a single string, identifying the
workflow by organization, repository, branch, environment, and so on.

Docker uses the subject claim as the primary condition when evaluating your
ruleset rules. The default subject claim format is:

```text
repo:<org>/<repo>:ref:refs/heads/<branch>
```

For example:

```text
repo:octo-org/octo-repo:ref:refs/heads/main
```

The exact format varies and depends on what triggered the workflow.

- A branch push, pull request, tag, or environment deployment each produces
  a different `sub` value.
- Refer to
  [GitHub's OpenID Connect reference](https://docs.github.com/en/actions/reference/security/oidc)
  for the full list of formats.

> [!NOTE]
> GitHub repositories created after July 15, 2026 use immutable
> identifiers for default subject claims. For example:
> `repo:octocat@123456/my-repo@456789:ref:refs/heads/main`. See the
> [GitHub changelog](https://github.blog/changelog/2026-04-23-immutable-subject-claims-for-github-actions-oidc-tokens/)
> for more details.

You can use wildcards to match across repositories or branches:

| Pattern                                        | Matches                                         |
| :--------------------------------------------- | :---------------------------------------------- |
| `repo:my-org/my-repo:ref:refs/heads/main`      | Only the `main` branch of a specific repository |
| `repo:my-org/*`                                | All repos in the organization                   |
| `repo:my-org/my-repo:ref:refs/heads/release-*` | All branches starting with `release-`           |

## Resources

Resources define the Docker resources a workflow can access when a ruleset
matches. You specify resources per ruleset, alongside the scopes that
determine the level of access granted.

Docker Hub repositories and Docker Build Cloud are supported resources.

## Next steps

- [OIDC connections overview](index.md)
- [Create or manage OIDC connections](create-manage.md)


---

# Single sign-on overview

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

Single sign-on (SSO) lets users access Docker by authenticating through their
identity providers (IdPs). SSO can be configured for an entire company,
including all associated organizations, or for a single organization that has a
Docker Business subscription.

## How SSO works

When SSO is enabled, Docker supports a non-IdP-initiated flow for user sign-in.
Instead of signing in with a Docker username and password, users are redirected
to your IdP’s sign-in page. Users must initiate the SSO authentication process
by signing in to Docker Hub or Docker Desktop.

The following diagram illustrates how SSO operates and is managed between
Docker Hub, Docker Desktop, and your IdP.

![SSO architecture](images/SSO.png)

## Set up SSO

To configure SSO in Docker, follow these steps:

1. [Configure your domain](connect.md) by creating and verifying it.
1. [Create your SSO connection](connect.md) in Docker and your IdP.
1. Link Docker to your identity provider.
1. Test your SSO connection.
1. Provision users in Docker.
1. Optional. [Enforce sign-in](../../../enterprise/security/enforce-sign-in/index.md).
1. [Manage your SSO configuration](manage.md).

Once configuration is complete, users can sign in to Docker services using
their company email address. After signing in, users are added to your company,
assigned to an organization, and added to a team.

> [!IMPORTANT]
>
> When SSO is enforced, CLI password-based sign-in is no longer supported.
> Use a personal access token (PAT) for CLI access. For more information, see the
> [security announcement](../../security-announcements.md#deprecation-of-password-logins-on-cli-when-sso-enforced).

## Next steps

- Start [configuring SSO](connect.md).
- Read the [FAQs](../../../faqs/security.md).
- [Troubleshoot](troubleshoot-sso.md) SSO issues.


---

# Set up single sign-on

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

To set up a single sign-on (SSO), you need to establish a connection between Docker
and your identity provider (IdP). While this guide
uses Okta and Microsoft Entra ID as a working example, the general process remains the same for other IdPs.

If you're unfamiliar with the SSO process, first review [SSO overview](index.md) to learn about how SSO works.

## Prerequisites

Docker supports any SAML 2.0 or OIDC-compatible identity provider. Before you begin, make sure the following conditions are met:

- Notify your company about the upcoming SSO sign-in process.
- Confirm that each Docker user has a valid IdP account using the same
  email address as their Unique Primary Identifier (UPN).
- Ensure CI/CD pipelines use PATs or OATs instead of passwords.

## Set up an SSO connection

> [!TIP]
> These procedures have you copy and paste values between Docker and your IdP. Complete this guide in one session with separate browser windows open for Docker and your IdP.

### Step 1: Add a domain

To add a domain:

1. Sign in to [app.docker.com](https://app.docker.com), then choose your
   organization. If your organization is part of a company, then select the company to manage
   the domain at the company level.
1. Select **Identity & auth**, then **Domain management**.
1. Select **Add a domain**.
1. Enter your domain in the text box and select **Add domain**.
1. In the modal, copy the **TXT Record Value** provided for domain verification.

### Step 2: Verify your domain

To confirm domain ownership, add a TXT record to your Domain Name System (DNS)
host using the TXT Record Value from Docker. DNS propagation can take up to
72 hours. Docker automatically checks for the record during this time.

> [!TIP]
>
> When adding a record name, use `@` or leave it empty for root domains like `example.com`. Avoid common values like `docker`, `docker-verification`, `www`, or your domain name itself. Always check your DNS provider's documentation to verify their specific record name requirements.

{{< tabs >}}
{{< tab name="AWS Route 53" >}}

1. To add your TXT record to AWS, see [Creating records by using the Amazon Route 53 console](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-creating.html).
1. Wait up to 72 hours for TXT record verification.
1. After the record is live, go to **Identity & auth**, then **Domain management**, and select **Verify**.

{{< /tab >}}
{{< tab name="Google Cloud DNS" >}}

1. To add your TXT record to Google Cloud DNS, see [Verifying your domain with a TXT record](https://cloud.google.com/identity/docs/verify-domain-txt).
1. Wait up to 72 hours for TXT record verification.
1. After the record is live, go to **Identity & auth**, then **Domain management**, and select **Verify**.

{{< /tab >}}
{{< tab name="GoDaddy" >}}

1. To add your TXT record to GoDaddy, see [Add a TXT record](https://www.godaddy.com/help/add-a-txt-record-19232).
1. Wait up to 72 hours for TXT record verification.
1. After the record is live, go to **Identity & auth**, then **Domain management**, and select **Verify**.

{{< /tab >}}
{{< tab name="Other providers" >}}

1. Sign in to your domain host.
1. Add a TXT record to your DNS settings and save the record.
1. Wait up to 72 hours for TXT record verification.
1. After the record is live, go to **Identity & auth**, then **Domain management**, and select **Verify**.

{{< /tab >}}
{{< /tabs >}}

### Step 3: Create an SSO connection in Docker

1. From [app.docker.com](https://app.docker.com), choose your
   organization.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. Select **Create Connection**. Name the connection, then choose **SAML 2.0**.
1. Keep this window open. You need to copy and paste these values in your Okta window:
   - **Entity ID**
   - **ACS URL**
   - **Connection ID**

You will return here to finish connecting after creating an SSO connection in your IdP.

### Step 4: Create an SSO connection in your IdP

Use the following tabs based on your IdP provider.

{{< tabs >}}
{{< tab name="Okta SAML" >}}

You need [super admin permissions](https://help.okta.com/en-us/content/topics/security/administrators-super-admin.htm) for the Okta org.

1. Sign in to your Okta Admin account. From the top nav, select the **Admin** button to go to Okta's Admin Console.
1. From the **Applications** section in the left nav, choose **Applications**. Select **Create App Integration**.
1. Choose SAML 2.0 to match your selection from Docker Home.
1. For **General Settings**, name your app "Docker." Uploading a logo is optional.
1. For **Configure SAML**, input the following values:
   - For the **Single Sign On URL** value, paste the Docker ACS URL.
   - For the **Audience URI (SP Entity ID)** value, paste the Docker Entity ID.
   - For **Name ID format**, choose `EmailAddress`
   - For **Application username**, choose `Email`
   - For **Update application username on**, choose `Create and update`
   - Optional. Add [SAML attributes](../../provisioning/index.md#sso-attributes), if required by your org.
1. For **Feedback**, choose **This is an internal app that we have created** checkbox before finishing.

Keep your Okta window open for the next step.

{{< /tab >}}
{{< tab name="Entra ID SAML 2.0" >}}

To enable SSO with Microsoft Entra, you need [Cloud Application Administrator](https://learn.microsoft.com/en-us/entra/identity/role-based-access-control/permissions-reference#cloud-application-administrator) permissions.

1. From Microsoft Entra admin center, select **Entra ID**, then go to **Enterprise apps**. Select **All applications**.
1. Choose **Create your own application** and name your app "Docker". Select **Non-gallery**.
1. After creating your app, go to **Single Sign-On** and select **SAML**.
1. Select **Edit** on the **Basic SAML configuration** section. From **Basic SAML configuration**, choose **Edit** and paste the values you copied from creating an SSO connection in Docker:
   - For the **Identifier** value, paste the Docker Entity ID.
   - For the **Reply URL** value, paste Docker ACS URL.
1. Optional. Add [SAML attributes](../../provisioning/index.md#sso-attributes), if required by your org.
1. From the **SAML Signing Certificate** section, download your **Certificate (Base64)**.

{{< /tab >}}
{{< tab name="Azure OpenID Connect (OIDC)" >}}

#### Register the app

1. Sign in to [Microsoft Entra admin center](https://entra.microsoft.com/).
1. Go to **App Registration** and select **New Registration**.
1. Name the application "Docker".
1. Set account types and paste the **Redirect URI** from Docker.
1. Select **Register**.
1. Copy the **Client ID**.

#### Create client secrets

1. In your app, go to **Certificates & secrets**.
1. Select **New client secret**, describe and configure duration, then **Add**.
1. Copy the **value** of the new secret.

#### Set API permissions

1. In your app, go to **API permissions**.
1. Select **Grant admin consent** and confirm.
1. Select **Add a permissions** > **Delegated permissions**.
1. Search and select `User.Read`.
1. Confirm that admin consent is granted.

{{< /tab >}}
{{< /tabs >}}

### Step 5: Connect Docker to your IdP

Complete the integration by pasting your IdP values into Docker.

> [!IMPORTANT]
> When prompted to copy a certificate, copy the entire certificate starting with
> `----BEGIN CERTIFICATE----` and including the `----END CERTIFICATE----` lines.

{{< tabs >}}
{{< tab name="Okta SAML" >}}

1. Go to **Applications** and choose **Applications**. Choose your app from the **ACTIVE** table.
1. From **Sign on**, go to **View SAML setup instructions**. This page contains the **SAML Sign-in URL** and **x509 Certificate**. Keep this page open.
1. Return to your opened Docker window for the **Create single sign-on connection** step. Paste in the **SAML Sign-in URL** and **x509 Certificate** values.
1. Optional. Select a default team, if required by your org.
1. Review and select **Create connection**.

{{< /tab >}}
{{< tab name="Entra ID SAML 2.0" >}}

1. Open your downloaded **Certificate (Base64)** in a text editor.
1. Copy the following values:
   - From Azure AD: **Login URL**
   - **Certificate (Base64)** contents
1. Return to Docker Home, then paste the **Login URL** and **Certificate (Base64)** values.
1. Choose your domain from the drop-down.
1. Optional. Select a default team, if required by your org.
1. Review and select **Create connection**.

{{< /tab >}}
{{< tab name="Azure OpenID Connect (OIDC)" >}}

1. Return to Docker Home.
1. Paste the following values:
   - **Client ID**
   - **Client Secret**
   - **Azure AD Domain**
1. Optional. Select a default team, if required by your org.
1. Review and select **Create connection**.

{{< /tab >}}
{{< /tabs >}}

### Step 6: Test the connection

IdPs like Microsoft Entra and Okta may require that you assign a user to an application before testing SSO. You can review [Microsoft Entra](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/add-application-portal-setup-sso#test-single-sign-on)'s documentation and [Okta](https://help.okta.com/wf/en-us/content/topics/workflows/connector-reference/okta/actions/assignusertoapplicationforsso.htm)'s documentation to learn how to assign yourself or other users to an app.

After assigning yourself to an app:

1. Open an incognito browser window and sign in to Docker Home using your domain email address.
1. When redirected to your IdP's sign in page, authenticate with your domain email instead of using your Docker ID.

If you have multiple IdPs, choose the sign-in option **Continue with SSO**. If you're using the CLI, you must authenticate using a personal access token.

## Configure multiple IdPs

Docker supports multiple identity provider (IdP) configurations by letting you associate one domain with more than one IdP. Each connection must use the same domain, which lets users choose their IdP when they select **Continue with SSO** at sign in.

To add multiple IdPs:

1. Use the same domain for each connection.
1. Repeat steps 3-6 from the [Set up an SSO connection](connect.md#set-up-an-sso-connection) procedures on this page. Repeat these steps for each IdP your organization intends to use.

Because you must use the same domain for each IdP, you won't need to repeat steps to add and verify your domains.

## Enforce SSO

If SSO is not enforced, users can still sign in using Docker usernames and passwords. Enforcing SSO requires users to use SSO when signing into Docker, which centralizes authentication and enforces policies set by the IdP.

Before enforcing SSO, users accessing Docker through the CLI must [create a personal access token (PAT)](../../access-tokens/personal-access-tokens.md). The PAT replaces their username and password for authentication.

1. Sign in to [Docker Home](https://app.docker.com/) and select
   your organization or company.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the SSO connections table, select the **Action** menu, then **Enable enforcement**.
1. Follow the on-screen instructions.
1. Select **Turn on enforcement**.

When you enforce SSO, your users cannot modify their email address and
password, convert a user account to an organization, or set up 2FA through
Docker Hub. If you want to use 2FA, you must enable 2FA through your IdP.

## Next steps

- [Provision users](../../provisioning/index.md).
- [Enforce sign-in](../../../enterprise/security/enforce-sign-in/index.md).
- [Create personal access tokens](../../access-tokens/personal-access-tokens.md).
- [Troubleshoot SSO](troubleshoot-sso.md) issues.


---

# Manage SSO domains and connections

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

This page covers how to manage single sign-on (SSO) after initial setup,
including managing domains, connections, users, and provisioning
settings.

## Manage domains

### Add a domain

To add a domain to an existing SSO connection:

1. Sign in to [Docker Home](https://app.docker.com) and select your company or
organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the SSO connections table, select the **Actions** menu for your
connection, then select **Edit connection**.
1. Select **Next** to navigate to the domains section.
1. In the **Domains** section, select **Add domain**.
1. Enter the domain you want to add to the connection.
1. Select **Next** to confirm or change the connected organizations.
1. Select **Next** to confirm or change the default organization and
team provisioning selections.
1. Review the connection details and select **Update connection**.

### Remove a domain from an SSO connection

> [!IMPORTANT]
>
> If you use multiple identity providers with the same domain, you must remove the domain from each SSO connection individually.

1. Sign in to [Docker Home](https://app.docker.com) and select your company or organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the **SSO connections** table, select the **Actions** menu for your connection, then
**Edit connection**.
1. Select **Next** to navigate to the domains section.
1. In the **Domain** section, select the **X** icon next to the domain
you want to remove.
1. Select **Next** to confirm or change the connected organizations.
1. Select **Next** to confirm or change the default organization and
team provisioning selections.
1. Review the connection details and select **Update connection**.

> [!NOTE]
>
> When you re-add a domain, Docker assigns a new TXT record value. You must complete domain verification again with the new TXT record.

## Manage SSO connections

### View connections

To view all configured SSO connections:

1. Sign in to [Docker Home](https://app.docker.com) and select your company or organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. View all configured connections in the **SSO connections** table.

### Edit a connection

To modify an existing SSO connection:

1. Sign in to [Docker Home](https://app.docker.com) and select your company or organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the **SSO connections** table, select the **Actions** menu for your connection, then
**Edit connection**.
1. Follow the on-screen instructions to modify your connection settings.

### Delete a connection

To remove an SSO connection:

1. Sign in to [Docker Home](https://app.docker.com) and select your company or organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the **SSO connections** table, select the **Actions** menu for your connection, then
**Delete connection**.
1. Follow the on-screen instructions to confirm the deletion.

> [!WARNING]
>
> Deleting an SSO connection removes access for all users who authenticate through
that connection.

## Manage users and provisioning

Docker automatically provisions users through Just-in-Time (JIT) provisioning when they sign in via SSO. You can also manually manage users and configure different provisioning methods.

### How provisioning works

Docker supports the following provisioning methods:

- JIT provisioning (default): Users are automatically added to your organization
when they sign in via SSO
- SCIM provisioning: Sync users and groups from your identity provider to Docker
- Group mapping: Sync user groups from your identity provider with teams in your Docker organization
- Manual provisioning: Turn off automatic provisioning and manually invite users

For more information on provisioning methods, see [Provision users](../../provisioning/index.md).

### Add guest users

To invite users who don't authenticate through your identity provider:

1. Sign in to [Docker Home](https://app.docker.com/) and select
your organization.
1. Select **Members**.
1. Select **Invite**.
1. Follow the on-screen instructions to invite the user.

The user receives an email invitation and can create a Docker account or sign
in with their existing account.

### Remove users

To remove a user from your organization:

1. Sign in to [Docker Home](https://app.docker.com/) and select
your organization.
1. Select **Members**.
1. Find the user you want to remove and select the **Actions** menu next to their name.
1. Select **Remove** and confirm the removal.

The user loses access to your organization immediately upon removal.


---

# Troubleshoot single sign-on

*Sección: Security*

This page describes common single sign-on (SSO) errors and their solutions. Issues can stem from your identity provider (IdP) configuration or Docker settings.

## Check for errors

If you experience SSO issues, check both Docker and your identity provider for errors first.

### Check Docker error logs

1. Sign in to [Docker Home](https://app.docker.com/) and select your organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the SSO connections table, select the **Action** menu and then **View error logs**.
1. For more details on specific errors, select **View error details** next to an error message.
1. Note any errors you see on this page for further troubleshooting.

### Check identity provider errors

1. Review your IdP’s logs or audit trails for any failed authentication or provisioning attempts.
2. Confirm that your IdP’s SSO settings match the values provided in Docker.
3. If applicable, confirm that you have configured user provisioning correctly and that it is enabled in your IdP.
4. If applicable, verify that your IdP correctly maps Docker's required user attributes.
5. Try provisioning a test user from your IdP and verify if they appear in Docker.

For further troubleshooting, check your IdP's documentation or contact their support team.

## Groups are not formatted correctly

### Error message

When this issue occurs, the following error message is common:

```text
Some of the groups assigned to the user are not formatted as '<organization name>:<team name>'. Directory groups will be ignored and user will be provisioned into the default organization and team.
```

### Causes

- Incorrect group name formatting in your identity provider (IdP): Docker requires groups to follow the format `<organization>:<team>`. If the groups assigned to a user do not follow this format, they will be ignored.
- Non-matching groups between IdP and Docker organization: If a group in your IdP does not have a corresponding team in Docker, it will not be recognized, and the user will be placed in the default organization and team.

### Affected environments

- Docker single sign-on setup using IdPs such as Okta or Azure AD
- Organizations using group-based role assignments in Docker

### Steps to replicate

To replicate this issue:

1. Attempt to sign in to Docker using SSO.
2. The user is assigned groups in the IdP but does not get placed in the expected Docker Team.
3. Review Docker logs or IdP logs to find the error message.

### Solutions

Update group names in your IdP:

1. Go to your IdP's group management section.
2. Check the groups assigned to the affected user.
3. Ensure each group follows the required format: `<organization>:<team>`
4. Update any incorrectly formatted groups to match this pattern.
5. Save changes and retry signing in with SSO.

## User is not assigned to the organization

### Error message

When this issue occurs, the following error message is common:

```text
User '$username' is not assigned to this SSO organization. Contact your administrator. TraceID: XXXXXXXXXXXXX
```

### Causes

- User is not assigned to the organization: If Just-in-Time (JIT) provisioning is disabled, the user may not be assigned to your organization.
- User is not invited to the organization: If JIT is disabled and you do not want to enable it, the user must be manually invited.
- SCIM provisioning is misconfigured: If you use SCIM for user provisioning, it may not be correctly syncing users from your IdP.

### Solutions

**Enable JIT provisioning**

JIT is enabled by default when you enable SSO. If you have JIT disabled and need
to re-enable it:

1. Sign in to [Docker Home](https://app.docker.com/) and select your organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the SSO connections table, select the **Action** menu and then **Enable JIT provisioning**.
1. Select **Enable** to confirm.

**Manually invite users**

When JIT is disabled, users are not automatically added to your organization when they authenticate through SSO.
To manually invite users, see [Invite members](../../../accounts/organization/manage/members.md#invite-members).

**Configure SCIM provisioning**

If you have SCIM enabled, troubleshoot your SCIM connection using the following steps:

1. Sign in to [Docker Home](https://app.docker.com/) and select your organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the SSO connections table, select the **Action** menu and then **View error logs**. For more details on specific errors, select **View error details** next to an error message. Note any errors you see on this page.
1. Navigate back to **Identity & auth**, then **SSO and SCIM**, and verify your SCIM configuration:
   - Ensure that the SCIM Base URL and API Token in your IdP match those provided in Docker.
   - Verify that SCIM is enabled in both Docker and your IdP.
1. Ensure that the attributes being synced from your IdP match Docker's [supported attributes](../../provisioning/scim/provision-scim.md#supported-attributes) for SCIM.
1. Test user provisioning by trying to provision a test user through your IdP and verify if they appear in Docker.

## IdP-initiated sign in is not enabled for connection

### Error message

When this issue occurs, the following error message is common:

```text
IdP-Initiated sign in is not enabled for connection '$ssoConnection'.
```

### Causes

Docker does not support an IdP-initiated SAML flow. This error occurs when a user attempts to authenticate from your IdP, such as using the Docker SSO app tile on the sign in page.

### Solutions

**Authenticate from Docker apps**

The user must initiate authentication from Docker applications (Hub, Desktop, etc). The user needs to enter their email address in a Docker app and they will get redirected to the configured SSO IdP for their domain.

**Hide the Docker SSO app**

You can hide the Docker SSO app from users in your IdP. This prevents users from attempting to start authentication from the IdP dashboard. You must hide and configure this in your IdP.

## Not enough seats in organization

### Error message

When this issue occurs, the following error message is common:

```text
Not enough seats in organization '$orgName'. Add more seats or contact your administrator.
```

### Causes

This error occurs when the organization has no available seats for the user when provisioning via Just-in-Time (JIT) provisioning or SCIM.

### Solutions

**Add more seats to the organization**

Purchase additional Docker Business subscription seats. For details, see [Manage subscription seats](../../../accounts/organization/manage/manage-seats.md).

**Remove users or pending invitations**

Review your organization members and pending invitations. Remove inactive users or pending invitations to free up seats. For more details, see [Manage organization members](../../../accounts/organization/manage/members.md).

## Domain is not verified for SSO connection

### Error message

When this issue occurs, the following error message is common:

```text
Domain '$emailDomain' is not verified for your SSO connection. Contact your company administrator. TraceID: XXXXXXXXXXXXXX
```

### Causes

This error occurs if the IdP authenticated a user through SSO and the User Principal Name (UPN)
returned to Docker doesn’t match any of the verified domains associated to the
SSO connection configured in Docker.

### Solutions

**Verify UPN attribute mapping**

Ensure that the IdP SSO connection is returning the correct UPN value in the assertion attributes.

**Add and verify all domains**

Add and verify all domains and subdomains used as UPN by your IdP and associate them with your Docker SSO connection. For details, see [Configure single sign-on](connect.md).

## Unable to find session

### Error message

When this issue occurs, the following error message is common:

```text
We couldn't find your session. You may have pressed the back button, refreshed the page, opened too many sign-in dialogs, or there is some issue with cookies. Try signing in again. If the issue persists, contact your administrator.
```

### Causes

The following causes may create this issue:

- The user pressed the back or refresh button during authentication.
- The authentication flow lost track of the initial request, preventing completion.

### Solutions

**Do not disrupt the authentication flow**

Do not press the back or refresh button during sign-in.

**Restart authentication**

Close the browser tab and restart the authentication flow from the Docker application (Desktop, Hub, etc).

## Name ID is not an email address

### Error message

When this issue occurs, the following error message is common:

```text
The name ID sent by the identity provider is not an email address. Contact your company administrator.
```

### Causes

The following causes may create this issue:

- The IdP sends a Name ID (UPN) that does not comply with the email format required by Docker.
- Docker SSO requires the Name ID to be the primary email address of the user.

### Solutions

In your IdP, ensure the Name ID attribute format is correct:

1. Verify that the Name ID attribute format in your IdP is set to `EmailAddress`.
2. Adjust your IdP settings to return the correct Name ID format.


---

# Provision users

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

After configuring your SSO connection, the next step is to provision users. This process ensures that users can access your organization through automated user management.

This page provides an overview of user provisioning and the supported provisioning methods.

## What is provisioning?

Provisioning helps manage users by automating tasks like account creation, updates, and deactivation based on data from your identity provider (IdP). There are several methods for user provisioning, each offering benefits for different organizational needs:

| Provisioning method | Description | Default setting in Docker | Recommended for |
| :--- | :--- | :------------- | :--- |
| System for Cross-domain Identity Management (SCIM) | Continuously syncs user data between your IdP and Docker, ensuring user attributes remain updated without manual intervention | Disabled by default | Larger organizations or environments with frequent changes in user information or roles |
| Group mapping | Maps user groups from your IdP to specific roles and permissions within Docker, enabling fine-grained access control based on group membership | Disabled by default | Organizations requiring strict access control and role-based user management |
| Just-in-Time (JIT) | Automatically creates and provisions user accounts when they first sign in via SSO | Enabled by default | Organizations needing minimal setup, smaller teams, or low-security environments |
| Auto-provision | Adds users when email addresses match a verified domain | Disabled by default | Orgs without SSO that need to add existing Docker users by domain |

## Default provisioning setup

By default, Docker enables JIT provisioning when you configure an SSO connection. With JIT enabled, user accounts are automatically created the first time a user signs in using your SSO flow.

JIT provisioning may not provide sufficient control or security for some organizations. In such cases, SCIM or group mapping can be configured to give administrators more control over user access and attributes.

## SSO attributes

When a user signs in through SSO, Docker obtains several attributes from your IdP to manage the user's identity and permissions. These attributes include:

- Email address: The unique identifier for the user
- Full name: The user's complete name
- Groups: Optional. Used for group-based access control
- Docker Org: Optional. Specifies the organization the user belongs to
- Docker Team: Optional. Defines the team the user belongs to within the organization
- Docker Role: Optional. Determines the user's permissions within Docker
- Docker session minutes: Optional. Sets the session duration before users must re-authenticate with their IdP. Must be a positive integer greater than 0. If not provided, default session timeouts apply

> [!NOTE]
>
> Default session timeouts apply when Docker session minutes is not specified. Docker Desktop sessions expire after 90 days or 30 days of inactivity. Docker Hub and Docker Home sessions expire after 24 hours.

## SAML attribute mapping

If your organization uses SAML for SSO, Docker retrieves these attributes from the SAML assertion message. Different IdPs may use different names for these attributes.

| SSO Attribute	| SAML Assertion Message Attributes |
| :--- | :--- |
| Email address |	`"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"`, `"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn"`, `"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"`, `email` |
| Full name	| `"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"`, `name`, `"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"`, `"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"` |
| Groups (optional) |	`"http://schemas.xmlsoap.org/claims/Group"`, `"http://schemas.microsoft.com/ws/2008/06/identity/claims/groups"`, `Groups`, `groups` |
| Docker Org (optional)	| `dockerOrg` |
| Docker Team (optional) |	`dockerTeam` |
| Docker Role (optional) |	`dockerRole` |
| Docker session minutes (optional) | `dockerSessionMinutes`, must be a positive integer > 0 |

## Next steps

Choose the provisioning method that best fits your organization's needs:

{{< grid >}}


---

# Auto-provisioning

*Sección: Security*

Auto-provisioning automatically adds users to your organization when they sign in with email addresses that match your verified domains. You must verify a domain before enabling auto-provisioning.

> [!IMPORTANT]
>
> For domains that are part of an SSO connection, Just-in-Time (JIT) provisioning takes precedence over auto-provisioning when adding users to an organization.

### Overview

When auto-provisioning is enabled for a verified domain:

- Users who sign in to Docker with matching email addresses are automatically added to your organization.
- Auto-provisioning only adds existing Docker users to your organization, it doesn't create new accounts.
- Users experience no changes to their sign-in process.
- Company and organization owners receive email notifications when new users are added.
- You may need to [manage seats](../../accounts/organization/manage/manage-seats.md) to accommodate new users.

### Enable auto-provisioning

Auto-provisioning is configured per domain. To enable it:

1. Sign in to [Docker Home](https://app.docker.com) and select
   your company or organization.
1. Select **Identity & auth**, then **Domain management**.
1. Select the **Actions menu** next to the domain you want to enable
   auto-provisioning for.
1. Select **Enable auto-provisioning**.
1. Optional. If enabling auto-provisioning at the company level, select an
   organization.
1. Select **Enable** to confirm.

The **Auto-provisioning** column will update to **Enabled** for the domain.

### Disable auto-provisioning

To disable auto-provisioning for a user:

1. Sign in to [Docker Home](https://app.docker.com) and select
   your organization. If your organization is part of a company, select the company
   and configure the domain for the organization at the company level.
1. Select **Identity & auth**, then **Domain management**.
1. Select the **Actions menu** next to your domain.
1. Select **Disable auto-provisioning**.
1. Select **Disable** to confirm.

## Next steps

To choose a different method to provision users, you can set up:

- [SCIM provisioning](scim/index.md) for advanced user management.
- [Group mapping](scim/group-mapping.md) to assign users to teams automatically.


---

# Add and manage domains

*Sección: Security*

{{< summary-bar feature_name="Domain management" >}}

Domain management lets you add and verify domains for your organization, then enable auto-provisioning to automatically add users when they sign in with email addresses that match your verified domains. This approach simplifies user management, ensures consistent security settings, and reduces the risk of unmanaged users accessing Docker without visibility or control.

This page provides steps to add and delete domains, configure auto-provisioning, and audit uncaptured users.

## Add and verify a domain

Adding a domain requires verification to confirm ownership. The verification process uses DNS records to prove you control the domain.

### Add a domain

1. Sign in to [Docker Home](https://app.docker.com) and select
   your organization. If your organization is part of a company, select the company
   and configure the domain for the organization at the company level.
1. Select **Identity & auth**, then **Domain management**.
1. Select **Add a domain**.
1. Enter your domain and select **Add domain**.
1. In the pop-up modal, copy the **TXT Record Value** to verify your domain.

### Verify a domain

Verification confirms that you own the domain by adding a TXT record to your Domain Name System (DNS) host. It can take up to 72 hours for the DNS change to propagate. Docker automatically checks for the record and confirms ownership once the change is recognized.

> [!TIP]
>
> The record name field determines where the TXT record is added in your domain (root or subdomain). For root domains like `example.com`, use `@` or leave the record name empty, depending on your provider. Don't enter values like docker, `docker-verification`, `www`, or your domain name, as these may direct to the wrong place. Check your DNS provider's documentation to verify record name requirements.

Follow the steps for your DNS provider to add the **TXT Record Value**. If
your provider isn't listed, use the steps for "Other providers":

{{< tabs >}}
{{< tab name="AWS Route 53" >}}

1. Add your TXT record to AWS by following [Creating records by using the Amazon Route 53 console](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-creating.html).
1. Wait up to 72 hours for TXT record verification.
1. Return to the **Domain management** page of the
   **Identity & auth**, then **Domain management**, and select **Verify** next to
   your domain name.

{{< /tab >}}
{{< tab name="Google Cloud DNS" >}}

1. Add your TXT record to Google Cloud DNS by following [Verifying your domain with a TXT record](https://cloud.google.com/identity/docs/verify-domain-txt).
1. Wait up to 72 hours for TXT record verification.
1. Return to the **Domain management** page of the
   **Identity & auth**, then **Domain management**, and select **Verify** next to
   your domain name.

{{< /tab >}}
{{< tab name="GoDaddy" >}}

1. Add your TXT record to GoDaddy by following [Add a TXT record](https://www.godaddy.com/help/add-a-txt-record-19232).
1. Wait up to 72 hours for TXT record verification.
1. Return to the **Domain management** page of the
   **Identity & auth**, then **Domain management**, and select **Verify** next to
   your domain name.

{{< /tab >}}
{{< tab name="Other providers" >}}

1. Sign in to your domain host.
1. Add a TXT record to your DNS settings using the **TXT Record Value** from Docker.
1. Wait up to 72 hours for TXT record verification.
1. Return to the **Domain management** page of the
   **Identity & auth**, then **Domain management**, and select **Verify** next to
   your domain name.

{{< /tab >}}
{{< /tabs >}}

## Audit domains for uncaptured users

Domain audit identifies uncaptured users. Uncaptured users are Docker users who have authenticated using an email address associated with your verified domains but aren't members of your Docker organization.

### Limitations

Domain audit can't identify:

- Users who access Docker Desktop without authenticating
- Users who authenticate using an account that doesn't have an
  email address associated with one of your verified domains

To prevent unidentifiable users from accessing Docker Desktop, [enforce sign-in](../../enterprise/security/enforce-sign-in/index.md).

### Run a domain audit

1. Sign in to [Docker Home](https://app.docker.com) and choose your
   company.
1. Select **Identity & auth**, then **Domain management**.
1. In **Domain audit**, select **Export Users** to export a CSV file
   of uncaptured users.

The CSV file contains the following columns:

- Name: Docker user's display name
- Username: Docker ID of the user
- Email: Email address of the user

### Invite uncaptured users

You can bulk invite uncaptured users to your organization using the exported
CSV file. For more information on bulk inviting users, see
[Manage organization members](../../accounts/organization/manage/members.md).

## Auto-provisioning

[Auto-provisioning](auto-provisioning.md) uses verified domains to associate organization members with email address that match the verified domains. To override auto-provisioning, you can configure one of the two alternative methods:

- [Just-in-Time (JIT)](just-in-time.md) provisioning
- [System for Cross-domain Identity Management (SCIM)](scim/index.md)

## Delete a domain

Deleting a domain removes its TXT record value and disables any associated auto-provisioning.

> [!WARNING]
>
> Deleting a domain will disable auto-provisioning for that domain and remove verification. This action cannot be undone.

To delete a domain:

1. Sign in to [Docker Home](https://app.docker.com) and select
   your organization. If your organization is part of a company, select the company
   and configure the domain for the organization at the company level.
1. Select **Identity & auth**, then **Domain management**.
1. For the domain you want to delete, select the **Actions** menu, then
   **Delete domain**.
1. To confirm, select **Delete domain** in the pop-up modal.


---

# Just-in-Time provisioning

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

Just-in-Time (JIT) provisioning streamlines user onboarding by automatically creating and updating user accounts during SSO authentication. This eliminates manual account creation and ensures users have immediate access to your organization's resources. JIT verifies that users belong to the organization and assigns them to the appropriate teams based on your identity provider (IdP) configuration. When you create your SSO connection, JIT provisioning is turned on by default.

This page explains how JIT provisioning works, SSO authentication flows, and how to disable JIT provisioning.

## Prerequisites

Before you begin, you must have:

- SSO configured for your organization
- Administrator access to Docker Home and your identity provider

## SSO authentication with JIT provisioning enabled

When a user signs in with SSO and you have JIT provisioning enabled, the following steps occur automatically:

1. The system checks if a Docker account exists for the user's email address.
   - If an account exists: The system uses the existing account and updates the user's full name if necessary.
   - If no account exists: A new Docker account is created using basic user attributes (email, name, and surname). A unique username is generated based on the user's email, name, and random numbers to ensure all usernames are unique across the platform.

2. The system checks for any pending invitations to the SSO organization.
   - Invitation found: The invitation is automatically accepted.
   - Invitation includes a specific group: The user is added to that group within the SSO organization.

3. The system verifies if the IdP has shared group mappings during authentication.
   - Group mappings provided: The user is assigned to the relevant organizations and teams.
   - No group mappings provided: The system checks if the user is already part of the organization. If not, the user is added to the default organization and team configured in the SSO connection.

The following graphic provides an overview of SSO authentication with JIT enabled:

![JIT provisioning enabled workflow](../images/jit-enabled-flow.svg)

## SSO authentication with JIT provisioning disabled

When JIT provisioning is disabled, the following actions occur during SSO authentication:

1. The system checks if a Docker account exists for the user's email address.
   - If an account exists: The system uses the existing account and updates the user's full name if necessary.
   - If no account exists: A new Docker account is created using basic user attributes (email, name, and surname). A unique username is generated based on the user's email, name, and random numbers to ensure all usernames are unique across the platform.

2. The system checks for any pending invitations to the SSO organization.
   - Invitation found: If the user is a member of the organization or has a pending invitation, sign-in is successful, and the invitation is automatically accepted.
   - No invitation found: If the user is not a member of the organization and has no pending invitation, the sign-in fails, and an `Access denied` error appears. The user must contact an administrator to be invited to the organization.

With JIT disabled, group mapping is only available if you have [SCIM enabled](scim/#enable-scim-in-docker). If SCIM is not enabled, users won't be auto-provisioned to groups.

The following graphic provides an overview of SSO authentication with JIT disabled:

![JIT provisioning disabled workflow](../images/jit-disabled-flow.svg)

## Disable JIT provisioning

> [!WARNING]
>
> Disabling JIT provisioning may disrupt your users' access and workflows. With JIT disabled, users will not be automatically added to your organization. Users must already be a member of the organization or have a pending invitation to successfully sign in through SSO. To auto-provision users with JIT disabled, [use SCIM](./scim.md).

You may want to disable JIT provisioning for reasons such as the following:

- You have multiple organizations, have SCIM enabled, and want SCIM to be the source of truth for provisioning
- You want to control and restrict usage based on your organization's security configuration, and want to use SCIM to provision access

Users are provisioned with JIT by default. If you enable SCIM, you can disable JIT:

1. Go to [Docker Home](https://app.docker.com/) and select your organization from the top-left account drop-down.
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the **SSO connections** table, select the **Action** icon, then select **Disable JIT provisioning**.
1. Select **Disable** to confirm.

## Next steps

- Configure [SCIM provisioning](scim/index.md) for advanced user management.
- Set up [group mapping](scim/group-mapping.md) to automatically assign users to teams.
- Review [Troubleshoot provisioning](troubleshoot-provisioning.md).


---

# SCIM overview

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

Automate user management for your Docker organization using System for
Cross-domain Identity Management (SCIM). SCIM automatically provisions and
de-provisions users, synchronizes team memberships, and keeps your Docker
organization in sync with your identity provider.

This page shows you how to automate user provisioning and de-provisioning for
Docker using SCIM.

## Prerequisites

Before you begin, you must have:

- SSO configured for your organization
- Administrator access to Docker Home and your identity provider

## How SCIM works

SCIM automates user provisioning and de-provisioning for Docker through your
identity provider. After you enable SCIM, any user assigned to your
Docker application in your identity provider is automatically provisioned and
added to your Docker organization. When a user is removed from the Docker
application in your identity provider, SCIM deactivates and removes them from
your Docker organization.

In addition to provisioning and removal, SCIM also syncs profile updates like
name changes made in your identity provider. You can use SCIM alongside Docker's
default Just-in-Time (JIT) provisioning or on its own with JIT disabled.

SCIM automates:

- Creating users
- Updating user profiles
- Removing and deactivating users
- Re-activating users
- Group mapping

> [!NOTE]
>
> SCIM only manages users provisioned through your identity provider after
> SCIM is enabled. It cannot remove users who were manually added to your Docker
> organization before SCIM was set up.
>
> To remove those users, delete them manually from your Docker organization.
> For more information, see
> [Manage organization members](../../../accounts/organization/manage/members.md).

## Next steps

- [Migrate JIT to SCIM](migrate-scim.md) if users were provisioned with Just-in-Time (JIT) before you enabled SCIM.
- [Group mapping](group-mapping.md) to sync identity provider groups with members.
- [Troubleshoot provisioning](../troubleshoot-provisioning.md) for SCIM, JIT, and attribute issues.


---

# Group mapping

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

Group mapping automatically synchronizes user groups from your identity provider (IdP) with teams in your Docker organization. For example, when you add a developer to the "backend-team" group in your IdP, they're automatically added to the corresponding team in Docker

This page explains how group mapping works, and how to set up group mapping.

> [!TIP]
>
> Group mapping is ideal for adding users to multiple organizations or multiple teams within one organization. If you don't need to set up multi-organization or multi-team assignment, SCIM [user-level attributes](provision-scim.md#set-up-role-mapping) may be a better fit for your needs.

## Prerequisites

Before you begin, you must have:

- SSO configured for your organization
- Administrator access to Docker Home and your identity provider

## How group mapping works

Group mapping keeps your Docker Teams synchronized with your IdP groups through these key components:

- Authentication flow: When users sign in through SSO, your IdP shares user attributes with Docker including email, name, and group memberships.
- Automatic updates: Docker uses these attributes to create or update user profiles and manage team assignments based on IdP group changes.
- Unique identification: Docker uses email addresses as unique identifiers, so each Docker account must have a unique email address.
- Team synchronization: Users' team memberships in Docker automatically reflect changes made in your IdP groups.

## Set up group mapping

Group mapping setup involves configuring your identity provider to share group
information with Docker. This requires:

- Creating groups in your IdP using Docker's naming format
- Configuring attributes so your IdP sends group data during authentication
- Adding users to the appropriate groups
- Testing the connection to ensure groups sync properly

You can use group mapping with SSO only, or with both SSO and SCIM for enhanced
user lifecycle management.

### Group naming format

Create groups in your IdP using the format: `organization:team`.

For example:

- For the "developers" team in the "moby" organization: `moby:developers`
- For multi-organization access: `moby:backend` and `whale:desktop`

Docker creates teams automatically if they don't already exist when groups sync.

### Supported attributes

| Attribute | Description |
|:--------- | :---------- |
| `id` | Unique ID of the group in UUID format. This attribute is read-only. |
| `displayName` | Name of the group following the group mapping format: `organization:team`. |
| `members` | A list of users that are members of this group. |
| `members(x).value` | Unique ID of the user that is a member of this group. Members are referenced by ID. |

## Configure group mapping with SSO

Use group mapping with SSO connections that use the SAML authentication method.

> [!NOTE]
>
> Group mapping with SSO isn't supported with the Azure AD (OIDC) authentication method. SCIM isn't required for these configurations.

{{< tabs >}}
{{< tab name="Okta" >}}

The user interface for your IdP may differ slightly from the following steps. Refer to the [Okta documentation](https://help.okta.com/oie/en-us/content/topics/apps/define-group-attribute-statements.htm) to verify.

To set up group mapping:

1. Sign in to Okta and open your application.
1. Navigate to the **SAML Settings** page for your application.
1. In the **Group Attribute Statements (optional)** section, configure like the following:
   - **Name**: `groups`
   - **Name format**: `Unspecified`
   - **Filter**: `Starts with` + `organization:` where `organization` is the name of your organization
   The filter option will filter out the groups that aren't affiliated with your Docker organization.
1. Create your groups by selecting **Directory**, then **Groups**.
1. Add your groups using the format `organization:team` that matches the names of your organization(s) and team(s) in Docker.
1. Assign users to the group(s) that you create.

The next time you sync your groups with Docker, your users will map to the Docker groups you defined.

{{< /tab >}}
{{< tab name="Entra ID" >}}

The user interface for your IdP may differ slightly from the following steps. Refer to the [Entra ID documentation](https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/customize-application-attributes) to verify.

To set up group mapping:

1. Sign in to Entra ID and open your application.
1. Select **Manage**, then **Single sign-on**.
1. Select **Add a group claim**.
1. In the Group Claims section, select **Groups assigned to the application** with the source attribute **Cloud-only group display names (Preview)**.
1. Select **Advanced options**, then the **Filter groups** option.
1. Configure the attribute like the following:
   - **Attribute to match**: `Display name`
   - **Match with**: `Contains`
   - **String**: `:`
1. Select **Save**.
1. Select **Groups**, **All groups**, then **New group** to create your group(s).
1. Assign users to the group(s) that you create.

The next time you sync your groups with Docker, your users will map to the Docker groups you defined.

{{< /tab >}}
{{< /tabs >}}

## Configure group mapping with SCIM

Use group mapping with SCIM for more advanced user lifecycle management. Before you begin, make sure you [set up SCIM](provision-scim.md#enable-scim) first.

{{< tabs >}}
{{< tab name="Okta" >}}

The user interface for your IdP may differ slightly from the following steps. Refer to the [Okta documentation](https://help.okta.com/en-us/Content/Topics/users-groups-profiles/usgp-enable-group-push.htm) to verify.

To set up your groups:

1. Sign in to Okta and open your application.
1. Select **Applications**, then **Provisioning**, and **Integration**.
1. Select **Edit** to enable groups on your connection, then select **Push groups**.
1. Select **Save**. Saving this configuration will add the **Push Groups** tab to your application.
1. Create your groups by navigating to **Directory** and selecting **Groups**.
1. Add your groups using the format `organization:team` that matches the names of your organization(s) and team(s) in Docker.
1. Assign users to the group(s) that you create.
1. Return to the **Integration** page, then select the **Push Groups** tab to open the view where you can control and manage how groups are provisioned.
1. Select **Push Groups**, then **Find groups by rule**.
1. Configure the groups by rule like the following:
    - Enter a rule name, for example `Sync groups with Docker Hub`
    - Match group by name, for example starts with `docker:` or contains `:` for multi-organization
    - If you enable **Immediately push groups by rule**, sync will happen as soon as there's a change to the group or group assignments. Enable this if you don't want to manually push groups.

Find your new rule under **By rule** in the **Pushed Groups** column. The groups that match that rule are listed in the groups table on the right-hand side.

To push the groups from this table:

1. Select **Group in Okta**.
1. Select the **Push Status** drop-down.
1. Select **Push Now**.

{{< /tab >}}
{{< tab name="Entra ID" >}}

The user interface for your IdP may differ slightly from the following steps. Refer to the [Entra ID documentation](https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/customize-application-attributes) to verify.

Complete the following before configuring group mapping:

1. Sign in to Entra ID and go to your application.
1. In your application, select **Provisioning**, then **Mappings**.
1. Select **Provision Microsoft Entra ID Groups**.
1. Select **Show advanced options**, then **Edit attribute list**.
1. Update the `externalId` type to `reference`, then select the **Multi-Value** checkbox and choose the referenced object attribute `urn:ietf:params:scim:schemas:core:2.0:Group`.
1. Select **Save**, then **Yes** to confirm.
1. Go to **Provisioning**.
1. Toggle **Provision Status** to **On**, then select **Save**.

Next, set up group mapping:

1. Go to the application overview page.
1. Under **Provision user accounts**, select **Get started**.
1. Select **Add user/group**.
1. Create your group(s) using the `organization:team` format.
1. Assign the group to the provisioning group.
1. Select **Start provisioning** to start the sync.

To verify, select **Monitor**, then **Provisioning logs** to see that your groups were provisioned successfully. In your Docker organization, you can check that the groups were correctly provisioned and the members were added to the appropriate teams.

{{< /tab >}}
{{< /tabs >}}

Once complete, a user who signs in to Docker through SSO is automatically added to the organizations and teams mapped in the IdP.

> [!TIP]
>
> [Enable SCIM](provision-scim.md) to take advantage of automatic user provisioning and de-provisioning. If you don't enable SCIM users are only automatically provisioned. You have to de-provision them manually.

## Next steps

- [Assign roles](../../roles-and-permissions/core-roles.md) to members of your org.
- [Enforce sign in](/manuals/enterprise/security/enforce-sign-in.md), if needed.


---

# Migrate JIT to SCIM

*Sección: Security*

If you already have users provisioned through Just-in-Time (JIT) and want to
enable full SCIM lifecycle management, you need to migrate them. Users
originally created by JIT cannot be automatically de-provisioned through SCIM,
even after SCIM is enabled.

## Why migrate

Organizations using JIT provisioning may encounter limitations with user
lifecycle management, particularly around de-provisioning. Migrating to SCIM
provides:

- Automatic user de-provisioning when users leave your organization. This is
  the primary benefit for large organizations that need full automation.
- Continuous synchronization of user attributes
- Centralized user management through your identity provider
- Enhanced security through automated access control

> [!IMPORTANT]
>
> Users originally created through JIT provisioning cannot be automatically
> de-provisioned by SCIM, even after SCIM is enabled. To enable full lifecycle
> management including automatic de-provisioning through your identity provider,
> you must manually remove these users so SCIM can re-create them with proper
> lifecycle management capabilities.

This migration is most critical for larger organizations that require fully
automated user de-provisioning when employees leave the company.

## Prerequisites

Before migrating, ensure you have:

- SCIM configured and tested in your organization
- A maintenance window for the migration

> [!WARNING]
>
> This migration temporarily disrupts user access. Plan to perform this
> migration during a low-usage window and communicate the timeline to affected
> users.

## Prepare for migration

### Transfer ownership

Before removing users, ensure that any repositories, teams, or organization
resources they own are transferred to another administrator or service account.
When a user is removed from the organization, any resources they own may
become inaccessible.

1. Review repositories, organization resources, and team ownership for affected
   users.
2. Transfer ownership to another administrator.

> [!WARNING]
>
> If ownership is not transferred, repositories owned by removed users may
> become inaccessible when the user is removed. Ensure all critical resources
> are transferred before proceeding.

### Verify identity provider configuration

1. Confirm all JIT-provisioned users are assigned to the Docker application in
   your identity provider.
2. Verify identity provider group to Docker Team mappings are configured and
   tested.

Users not assigned to the Docker application in your identity provider are not
re-created by SCIM after removal.

### Export user records

Export a list of JIT-provisioned users from Docker Home:

1. Sign in to [Docker Home](https://app.docker.com) and select your
   organization.
2. Select **Members**.
3. Select **Export members** to download the member list as CSV for backup and
   reference.

Keep this CSV list of JIT-provisioned users as a rollback reference if needed.

## Complete the migration

### Disable JIT provisioning

> [!IMPORTANT]
>
> Before disabling JIT, ensure SCIM is fully configured and tested in your
> organization. Do not disable JIT until you have verified SCIM is working
> correctly.

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
2. Select **Identity & auth**, then **SSO and SCIM**.
3. In the SSO connections table, select the **Actions** menu for your connection.
4. Select **Disable JIT provisioning**.
5. Select **Disable** to confirm.

Disabling JIT prevents new users from being automatically added through SSO
during the migration.

### Remove JIT-origin users

> [!IMPORTANT]
>
> Users originally created through JIT provisioning cannot be automatically
> de-provisioned by SCIM, even after SCIM is enabled. To enable full lifecycle
> management including automatic de-provisioning through your identity provider,
> you must manually remove these users so SCIM can re-create them with proper
> lifecycle management capabilities.

This step is most critical for large organizations that require fully automated
user de-provisioning when employees leave the company.

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
2. Select **Members**.
3. Identify and remove JIT-provisioned users in manageable batches.
4. Monitor for any errors during removal.

> [!TIP]
>
> To efficiently identify JIT users, compare the member list exported before
> SCIM was enabled with the current member list. Users who existed before SCIM
> was enabled were likely provisioned via JIT.

### Verify SCIM re-provisioning

After removing JIT users, SCIM automatically re-creates user accounts:

1. In your identity provider system log, confirm "create app user" events for
   Docker.
2. In Docker Home under **Members**, confirm users reappear with SCIM provisioning.
3. Verify users are added to the correct teams via group mapping.

### Validate user access

Perform post-migration validation:

1. Select a subset of migrated users to test sign-in and access.
2. Verify team membership matches identity provider group assignments.
3. Confirm repository access is restored.
4. Test that de-provisioning works correctly by removing a test user from your
   identity provider.

Keep audit exports and logs for compliance purposes.

## Migration results

After completing the migration:

- All users in your organization are SCIM-provisioned
- User de-provisioning works reliably through your identity provider
- No new JIT users are created
- Consistent identity lifecycle management is maintained

## Troubleshoot migration issues

If a user fails to reappear after removal:

1. Check that the user is assigned to the Docker application in your identity
   provider.
2. Verify SCIM is enabled in both Docker and your identity provider.
3. Trigger a manual SCIM sync in your identity provider.
4. Check provisioning logs in your identity provider for errors.

For more troubleshooting guidance, see
[Troubleshoot provisioning](../troubleshoot-provisioning.md).

## Next steps

- Set up [Group mapping](group-mapping.md).
- [Assign roles](../../roles-and-permissions/core-roles.md) to members of your org.
- [Enforce sign in](/manuals/enterprise/security/enforce-sign-in.md), if needed.


---

# Set up SCIM provisioning

*Sección: Security*

{{< summary-bar feature_name="SSO" >}}

## Supported attributes

SCIM uses attributes (name, email, etc.) to sync user information between your
identity provider and Docker. Properly mapping these attributes in your identity
provider ensures that user provisioning works smoothly and prevents issues like
duplicate user accounts
when using single sign-on.

Docker supports the following SCIM attributes:

| Attribute         | Description                                                                       |
| :---------------- | :-------------------------------------------------------------------------------- |
| `userName`        | User's primary email address, used as the unique identifier                       |
| `name.givenName`  | User's first name                                                                 |
| `name.familyName` | User's surname                                                                    |
| `active`          | Indicates if a user is enabled or disabled, set to "false" to de-provision a user |

For additional details about supported attributes and SCIM, see
[Docker Hub API SCIM reference](../../../reference/api/hub/latest.md#tag/scim).

> [!IMPORTANT]
>
> By default, Docker uses Just-in-Time (JIT) provisioning for SSO. If SCIM is
> enabled, JIT values still take precedence and will overwrite attribute values
> set by SCIM. To avoid conflicts, make sure your JIT attribute values match
> your SCIM values.
>
> Alternatively, you can disable JIT provisioning to rely solely on SCIM.
> For details, see [Just-in-Time](../just-in-time.md).

## Enable SCIM in Docker

To enable SCIM:

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the **SSO connections** table, select the **Actions** icon for your
   connection, then select **Setup SCIM**.
1. Copy the **SCIM Base URL** and **API Token** and paste the values into your
   IdP.

## Enable SCIM in your IdP

The user interface for your identity provider may differ slightly from the
following steps. You can refer to the documentation for your identity provider
to verify. For additional details, see the documentation for your identity
provider:

- [Okta](https://help.okta.com/en-us/Content/Topics/Apps/Apps_App_Integration_Wizard_SCIM.htm)
- [Entra ID/Azure AD SAML 2.0](https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/user-provisioning)

> [!NOTE]
>
> Microsoft does not currently support SCIM and OIDC in the same non-gallery
> application in Entra ID. This page provides a verified workaround using a
> separate non-gallery app for SCIM provisioning. While Microsoft does not
> officially document this setup, it is widely used and supported in practice.

{{< tabs >}}
{{< tab name="Okta" >}}

### Step one: Enable SCIM

1. Sign in to Okta and select **Admin** to open the admin portal.
1. Open the application you created when you configured your SSO connection.
1. On the application page, select the **General** tab, then
   **Edit App Settings**.
1. Enable SCIM provisioning, then select **Save**.
1. Navigate to the **Provisioning**, then select **Edit SCIM Connection**.
1. To configure SCIM in Okta, set up your connection using the following
   values and settings:
   - SCIM Base URL: SCIM connector base URL (copied from Docker Home)
   - Unique identifier field for users: `email`
   - Supported provisioning actions: **Push New Users** and
     **Push Profile Updates**
   - Authentication Mode: HTTP Header
   - SCIM Bearer Token: HTTP Header Authorization Bearer Token
     (copied from Docker Home)
1. Select **Test Connector Configuration**.
1. Review the test results and select **Save**.

### Step two: Enable synchronization

1. In Okta, select **Provisioning**.
1. Select **To App**, then **Edit**.
1. Enable **Create Users**, **Update User Attributes**, and **Deactivate Users**.
1. Select **Save**.
1. Remove unnecessary mappings. The necessary mappings are:
   - Username
   - Given name
   - Family name
   - Email

Next, [set up role mapping](#set-up-role-mapping).

{{< /tab >}}
{{< tab name="Entra ID (OIDC)" >}}

Microsoft does not support SCIM and OIDC in the same non-gallery application.
You must create a second non-gallery application in Entra ID for SCIM
provisioning.

### Step one: Create a separate SCIM app

1. In the Azure Portal, go to **Microsoft Entra ID** >
   **Enterprise Applications** > **New application**.
1. Select **Create your own application**.
1. Name your application and choose
   **Integrate any other application you don't find in the gallery**.
1. Select **Create**.

### Step two: Configure SCIM provisioning

1. In your new SCIM application, go to **Provisioning** > **Get started**.
1. Set **Provisioning Mode** to **Automatic**.
1. Under **Admin Credentials**:
   - **Tenant URL**: Paste the **SCIM Base URL** from Docker Home.
   - **Secret Token**: Paste the **SCIM API token** from Docker Home.
1. Select **Test Connection** to verify.
1. Select **Save** to store credentials.

Next, [set up role mapping](#set-up-role-mapping).

{{< /tab >}}
{{< tab name="Entra ID (SAML 2.0)" >}}

1. In the Azure Portal, go to **Microsoft Entra ID** >
   **Enterprise Applications**, and select your Docker SAML app.
1. Select **Provisioning** > **Get started**.
1. Set **Provisioning Mode** to **Automatic**.
1. Under **Admin Credentials**:
   - **Tenant URL**: Paste the **SCIM Base URL** from Docker Home.
   - **Secret Token**: Paste the **SCIM API token** from Docker Home.
1. Select **Test Connection** to verify.
1. Select **Save** to store credentials.

Next, [set up role mapping](#set-up-role-mapping).

{{< /tab >}}
{{< /tabs >}}

## Set up role mapping

You can assign [Docker roles](../../roles-and-permissions/index.md) to
users by adding optional SCIM attributes in your IdP. These attributes override
default role and team values set in your SSO configuration.

> [!NOTE]
>
> Role mappings are supported for both SCIM and Just-in-Time (JIT)
> provisioning. For JIT, role mapping applies only when the user is first
> provisioned.

The following table lists the supported optional user-level attributes:

| Attribute    | Possible values                          | Notes                                                                                                                                                                                                                                                            |
| ------------ | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `dockerRole` | `member`, `editor`, or `owner`           | If not set, the user defaults to the `member` role. Setting this attribute overrides the default.<br><br>For role definitions, see [Roles and permissions](../../roles-and-permissions/index.md).                                        |
| `dockerOrg`  | Docker `organizationName` (e.g., `moby`) | Overrides the default organization configured in your SSO connection.<br><br>If unset, the user is provisioned to the default organization. If `dockerOrg` and `dockerTeam` are both set, the user is provisioned to the team within the specified organization. |
| `dockerTeam` | Docker `teamName` (e.g., `developers`)   | Provisions the user to the specified team in the default or specified organization. If the team doesn't exist, it is automatically created.<br><br>You can still use [group mapping](group-mapping.md) to assign users to multiple teams across organizations.   |

The external namespace used for these attributes is: `urn:ietf:params:scim:schemas:extension:docker:2.0:User`.
This value is required in your identity provider when creating custom SCIM attributes for Docker.

{{< tabs >}}
{{< tab name="Okta" >}}

### Step one: Set up role mapping in Okta

1. Setup [SSO](../../authentication/single-sign-on/connect.md) and SCIM first.
1. In the Okta admin portal, go to **Directory**, select **Profile Editor**,
   and then **User (Default)**.
1. Select **Add Attribute** and configure the values for the role, organization,
   or team you want to add. Exact naming isn't required.
1. Return to the **Profile Editor** and select your application.
1. Select **Add Attribute** and enter the required values. The **External Name**
   and **External Namespace** must be exact.
   - The external name values for organization/team/role mapping are
     `dockerOrg`, `dockerTeam`, and `dockerRole` respectively, as listed in the previous table.
   - The external namespace is the same for all of them:
     `urn:ietf:params:scim:schemas:extension:docker:2.0:User`.
1. After creating the attributes, navigate to the top of the page and select
   **Mappings**, then **Okta User to YOUR APP**.
1. Go to the newly created attributes and map the variable names to the external
   names, then select **Save Mappings**. If you're using JIT provisioning, continue
   to the following steps.
1. Navigate to **Applications** and select **YOUR APP**.
1. Select **General**, then **SAML Settings**, and **Edit**.
1. Select **Step 2** and configure the mapping from the user attribute to the
   Docker variables.

### Step two: Assign roles by user

1. In the Okta Admin portal, select **Directory**, then **People**.
1. Select **Profile**, then **Edit**.
1. Select **Attributes** and update the attributes to the desired values.

### Step three: Assign roles by group

1. In the Okta Admin portal, select **Directory**, then **People**.
1. Select **YOUR GROUP**, then **Applications**.
1. Open **YOUR APPLICATION** and select the **Edit** icon.
1. Update the attributes to the desired values.

If a user doesn't already have attributes set up, users who are added to the
group will inherit these attributes upon provisioning.

{{< /tab >}}
{{< tab name="Entra ID/Azure AD (SAML 2.0 and OIDC)" >}}

### Step one: Configure attribute mappings

1. Complete the [SCIM provisioning setup](provision-scim.md#enable-scim-in-docker).
1. In the Azure Portal, open **Microsoft Entra ID** >
   **Enterprise Applications**, and select your SCIM application.
1. Go to **Provisioning** > **Mappings** >
   **Provision Azure Active Directory Users**.
1. Add or update the following mappings:
   - `userPrincipalName` -> `userName`
   - `mail` -> `emails.value`
   - Optional. Map `dockerRole`, `dockerOrg`, or `dockerTeam` using one of the
     [mapping methods](provision-scim.md#set-up-role-mapping).
1. Remove any unsupported attributes to prevent sync errors.
1. Optional. Go to **Mappings** > **Provision Azure Active Directory Groups**:
   - If group provisioning causes errors, set **Enabled** to **No**.
   - If enabling, test group mappings carefully.
1. Select **Save** to apply mappings.

### Step two: Choose a role mapping method

You can map `dockerRole`, `dockerOrg`, or `dockerTeam` using one of the
following methods:

#### Expression mapping

Use this method if you only need to assign Docker roles like `member`, `editor`,
or `owner`.

1. In the **Edit Attribute** view, set the mapping type to **Expression**.
1. In the **Expression** field:
   1. If your App Roles match Docker roles exactly, use:
      SingleAppRoleAssignment([appRoleAssignments])
   1. If they don't match, use a switch expression: `Switch(SingleAppRoleAssignment([appRoleAssignments]), "My Corp Admins", "owner", "My Corp Editors", "editor", "My Corp Users", "member")`
1. Set:
   - **Target attribute**: `urn:ietf:params:scim:schemas:extension:docker:2.0:User:dockerRole`
   - **Match objects using this attribute**: No
   - **Apply this mapping**: Always
1. Save your changes.

> [!WARNING]
>
> You can't use `dockerOrg` or `dockerTeam` with this method. Expression mapping
> is only compatible with one attribute.

#### Direct mapping

Use this method if you need to map multiple attributes (`dockerRole` +
`dockerTeam`).

1. For each Docker attribute, choose a unique Entra extension attribute
   (`extensionAttribute1`, `extensionAttribute2`, etc.).
1. In the **Edit Attribute** view:
   - Set mapping type to **Direct**.
   - Set **Source attribute** to your selected extension attribute.
   - Set **Target attribute** to one of:
     - `dockerRole: urn:ietf:params:scim:schemas:extension:docker:2.0:User:dockerRole`
     - `dockerOrg: urn:ietf:params:scim:schemas:extension:docker:2.0:User:dockerOrg`
     - `dockerTeam: urn:ietf:params:scim:schemas:extension:docker:2.0:User:dockerTeam`
   - Set **Apply this mapping** to **Always**.
1. Save your changes.

To assign values, you'll need to use the Microsoft Graph API.

### Step three: Assign users and groups

For either mapping method:

1. In the SCIM app, go to **Users and Groups** > **Add user/group**.
1. Select the users or groups to provision to Docker.
1. Select **Assign**.

If you're using expression mapping:

1. Go to **App registrations** > your SCIM app > **App Roles**.
1. Create App Roles that match Docker roles.
1. Assign users or groups to App Roles under **Users and Groups**.

If you're using direct mapping:

1. Go to [Microsoft Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)
   and sign in as a tenant admin.
1. Use Microsoft Graph API to assign attribute values. Example PATCH request:

```bash
PATCH https://graph.microsoft.com/v1.0/users/{user-id}
Content-Type: application/json

{
  "extensionAttribute1": "owner",
  "extensionAttribute2": "moby",
  "extensionAttribute3": "developers"
}
```

> [!NOTE]
>
> You must use a different extension attribute for each SCIM field.

{{< /tab >}}
{{< /tabs >}}

See the documentation for your IdP for additional details:

- [Okta](https://help.okta.com/en-us/Content/Topics/users-groups-profiles/usgp-add-custom-user-attributes.htm)
- [Entra ID/Azure AD](https://learn.microsoft.com/en-us/azure/active-directory/app-provisioning/customize-application-attributes#provisioning-a-custom-extension-attribute-to-a-scim-compliant-application)

## Test SCIM provisioning

After completing role mapping, you can test the configuration manually.

{{< tabs >}}
{{< tab name="Okta" >}}

1. In the Okta admin portal, go to **Directory > People**.
1. Select a user you've assigned to your SCIM application.
1. Select **Provision User**.
1. Wait a few seconds, then check the Docker
   **Members** in [Docker Home](https://app.docker.com).
1. If the user doesn't appear, review logs in **Reports > System Log** and
   confirm SCIM settings in the app.

{{< /tab >}}
{{< tab name="Entra ID/Azure AD (OIDC and SAML 2.0)" >}}

1. In the Azure Portal, go to **Microsoft Entra ID** > **Enterprise Applications**,
   and select your SCIM app.
1. Go to **Provisioning** > **Provision on demand**.
1. Select a user or group and choose **Provision**.
1. Confirm that the user appears in the Docker
   **Members** in [Docker Home](https://app.docker.com).
1. If needed, check **Provisioning logs** for errors.

{{< /tab >}}
{{< /tabs >}}

## Disable SCIM

If SCIM is disabled, any user provisioned through SCIM will remain in the
organization. Future changes for your users will not sync from your IdP.
User de-provisioning is only possible when manually removing the user from the
organization.

To disable SCIM:

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Identity & auth**, then **SSO and SCIM**.
1. In the **SSO connections** table, select the **Actions** icon.
1. Select **Disable SCIM**.

## Next steps

- Set up [Group mapping](group-mapping.md).
- [Troubleshoot provisioning](../troubleshoot-provisioning.md).


---

# Troubleshoot provisioning

*Sección: Security*

This page helps troubleshoot common user provisioning issues including user roles, attributes, and unexpected account behavior with SCIM and Just-in-Time (JIT) provisioning.

## SCIM attribute values are overwritten or ignored

### Error message

Typically, this scenario does not produce an error message in Docker or your
IdP. This issue usually surfaces as incorrect role or team assignment.

### Causes

- JIT provisioning is enabled, and Docker is using values from your IdP's
  SSO sign in flow to provision the user, which overrides
  SCIM-provided attributes.
- SCIM was enabled after the user was already provisioned via JIT, so SCIM
  updates don't take effect.

### Affected environments

- Docker organizations using SCIM with SSO
- Users provisioned via JIT prior to SCIM setup

### Steps to replicate

1. Enable JIT and SSO for your Docker organization.
1. Sign in to Docker as a user via SSO.
1. Enable SCIM and set role/team attributes for that user.
1. SCIM attempts to update the user's attributes, but the role or team
   assignment does not reflect changes.

### Solutions

#### Disable JIT provisioning (recommended)

1. Sign in to [Docker Home](https://app.docker.com/).
1. Select **Identity & auth**, then **SSO and SCIM**.
1. Find the relevant SSO connection.
1. Select the **actions menu** and choose **Edit**.
1. Disable **Just-in-Time provisioning**.
1. Save your changes.

With JIT disabled, Docker uses SCIM as the source of truth for user creation
and role assignment.

**Keep JIT enabled and match attributes**

If you prefer to keep JIT enabled:

- Make sure your IdP's SSO attribute mappings match the values being sent
  by SCIM.
- Avoid configuring SCIM to override attributes already set via JIT.

This option requires strict coordination between SSO and SCIM attributes
in your IdP configuration.

## SCIM updates don't apply to existing users

### Causes

User accounts were originally created manually or via JIT, and SCIM is not
linked to manage them.

### Solution

SCIM only manages users that it provisions. To allow SCIM to manage an
existing user:

1. Remove the user manually from [Docker Home](https://app.docker.com) under **Members**.
1. Trigger provisioning from your IdP.
1. SCIM will re-create the user with correct attributes.

> [!WARNING]
>
> Deleting a user removes their resource ownership (e.g., repositories).
> Transfer ownership before removing the user.


---

# Docker organization roles and permissions

*Sección: Security*

{{< summary-bar feature_name="General admin" >}}

Roles determine what members can do in your Docker organization. When you
invite a user or create a team, you assign a role that grants permissions
for repositories, teams, and organization settings.

Docker provides two role types. Users and teams get either a core role or a
custom role, but not both.

## Core roles

Core roles are Docker's built-in Member, Editor, and Owner roles. Their
permissions are predefined. Use core roles when Docker's permission sets match
your organization's needs.

## Custom roles

Custom roles are permission sets you build by selecting individual
permissions, such as billing or team management. Use custom roles when you
need a combination that core roles don't offer. For example, you may create a custom role for a billing
administrator or a security auditor, or when you want to grant
least-privilege access.

Custom roles require a Docker Business subscription.

## Roles and team permissions

Roles apply organization-wide. Team permissions apply to specific
repositories. The two systems work together: a user's role sets their
organization-wide access and team membership can extend their access to
individual repositories.

## Next steps

{{< grid >}}


---

# Docker core roles and permissions

*Sección: Security*

{{< summary-bar feature_name="General admin" >}}

Docker organizations use built-in Member, Editor, and Owner roles with
predefined permissions. This reference compares their permissions across
Docker products. To assign a different combination of permissions, use
[custom roles](custom-roles/index.md)
instead.

## Core roles

Docker organizations have three core roles:

- Owner provides full administrative access. Owners can manage all
  organization settings, including repositories, teams, members, billing,
  and security features.
- Editor has partial administrative access. Editors can create, edit, and
  delete repositories. They can also manage team permissions for
  repositories.
- Member has basic, non-administrative access. Members can view
  other organization members and pull images from repositories they have
  access to.

A company owner has the same organization-management permissions as an
organization owner. Content and registry permissions, such as repository
pull and push, don't apply to company owners. For more information, see
[Company overview](../../accounts/company/index.md).

## Permissions reference

### Content and registry

These permissions apply organization-wide.

| Permission                                            | Member | Editor | Owner |
| :---------------------------------------------------- | :----- | :----- | :---- |
| Explore images and extensions                         | ✅     | ✅     | ✅    |
| Star, favorite, vote, and comment on content          | ✅     | ✅     | ✅    |
| Pull images                                           | ✅     | ✅     | ✅    |
| Create and publish an extension                       | ✅     | ✅     | ✅    |
| Become a Verified, Official, or Open Source publisher | ❌     | ❌     | ✅    |
| Edit and delete publisher repository logos            | ❌     | ✅     | ✅    |
| Configure DVP analytics settings                      | ❌     | ✅     | ✅    |
| Observe content engagement as a publisher             | ❌     | ❌     | ✅    |
| Create public and private repositories                | ❌     | ✅     | ✅    |
| Disable public repositories                           | ❌     | ✅     | ✅    |
| Edit and delete repositories                          | ❌     | ✅     | ✅    |
| Manage tags                                           | ❌     | ✅     | ✅    |
| View repository activity                              | ❌     | ❌     | ✅    |
| Set up Automated builds                               | ❌     | ❌     | ✅    |
| Edit build settings                                   | ❌     | ❌     | ✅    |
| View teams                                            | ✅     | ✅     | ✅    |
| Assign team permissions to repositories               | ❌     | ✅     | ✅    |
| Manage OIDC connections                               | ❌     | ✅     | ✅    |

You can grant repository permissions beyond a member's organization role:

- Role permissions: Applied organization-wide (member or editor)
- Team permissions: Additional permissions for specific repositories

To extend access to private repositories, configure team permissions.
Custom roles can grant organization-wide permissions to manage repositories
(create, edit, delete) but don't grant pull access to private repositories.
Use team permissions for that.

### Organization management

| Permission                                                        | Member | Editor | Owner |
| :---------------------------------------------------------------- | :----- | :----- | :---- |
| Create teams                                                      | ❌     | ❌     | ✅    |
| Manage teams (including delete)                                   | ❌     | ❌     | ✅    |
| Configure the organization's settings (including linked services) | ❌     | ❌     | ✅    |
| Add organizations to a company                                    | ❌     | ❌     | ✅    |
| Invite members                                                    | ❌     | ❌     | ✅    |
| Manage members                                                    | ❌     | ❌     | ✅    |
| Manage member roles and permissions                               | ❌     | ❌     | ✅    |
| View member activity                                              | ❌     | ❌     | ✅    |
| Export and reporting                                              | ❌     | ❌     | ✅    |
| Image Access Management                                           | ❌     | ❌     | ✅    |
| Registry Access Management                                        | ❌     | ❌     | ✅    |
| Namespace access control                                          | ❌     | ❌     | ✅    |
| Set up Single Sign-On (SSO) and SCIM                              | ❌     | ❌     | ✅ \* |
| Require Docker Desktop sign-in                                    | ❌     | ❌     | ✅ \* |
| Manage billing information (for example, billing address)         | ❌     | ❌     | ✅    |
| Manage payment methods (for example, credit card or invoice)      | ❌     | ❌     | ✅    |
| View billing history                                              | ❌     | ❌     | ✅    |
| Manage subscriptions                                              | ❌     | ❌     | ✅    |
| Manage seats                                                      | ❌     | ❌     | ✅    |
| Upgrade and downgrade plans                                       | ❌     | ❌     | ✅    |

> [!TIP]
>
> For more granular access control,
> [upgrade to a Docker Business plan](https://www.docker.com/pricing?ref=Docs&refAction=DocsEnterpriseCoreRoles)
> to use [custom roles](custom-roles/index.md).

_\* If not part of a company_

### Docker Scout

| Permission                                            | Member | Editor | Owner |
| :---------------------------------------------------- | :----- | :----- | :---- |
| View and compare analysis results                     | ✅     | ✅     | ✅    |
| Upload analysis records                               | ✅     | ✅     | ✅    |
| Activate and deactivate Docker Scout for a repository | ❌     | ✅     | ✅    |
| Create environments                                   | ❌     | ❌     | ✅    |
| Manage registry integrations                          | ❌     | ❌     | ✅    |

### Docker Build Cloud

| Permission                 | Member | Editor | Owner |
| -------------------------- | :----- | :----- | :---- |
| Use a cloud builder        | ✅     | ✅     | ✅    |
| Create and remove builders | ✅     | ✅     | ✅    |
| Configure builder settings | ✅     | ✅     | ✅    |
| Buy minutes                | ❌     | ❌     | ✅    |
| Manage subscription        | ❌     | ❌     | ✅    |

## Next steps

- [Custom roles](custom-roles/index.md):
  Create tailored permission sets on a Docker Business plan
- [Manage organization members](../../accounts/organization/manage/members.md):
  Invite users and assign roles
- [Company overview](../../accounts/company/index.md): Understand company
  owner permissions versus organization owner permissions


---

# Custom roles and permissions overview

*Sección: Security*

{{< summary-bar feature_name="Custom roles" >}}

Custom roles are permission sets that you choose to grant access to users
or teams based on specific use cases. Use custom roles when you need
specialized roles, department-specific access, or least-privilege grants.

If Docker's predefined permission sets meet your needs, use
[core roles](../index.md)
instead.

## Prerequisites

- A Docker Business subscription
- Owner permissions in your Docker organization

## Creating custom roles

To create a custom role, you select permissions from organization management,
Docker Hub, billing, AI Governance, Docker Hardened Images, and Docker
Offload. You then assign custom roles you created to individual users or to teams.

## Next steps

{{< grid >}}


---

# Manage custom roles in Docker Home

*Sección: Security*

{{< summary-bar feature_name="Custom roles" >}}

Create custom roles, manage their permissions, and assign them to users
and teams. Use a custom role to grant only the permissions a user or
team needs. For a full list of permissions, see the
[custom roles permissions reference](permissions-reference.md).

## Create a custom role

Before you can assign a custom role, create one:

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Roles**, then **Create role**.
1. Define the role:
   - Provide a **Label**
   - Enter a unique **Name** identifier. The identifier is permanent.
   - Add an optional **Description**
1. Set permissions for the role by expanding permission categories and
   selecting the checkboxes for permissions. For a full list of available
   permissions, see the
   [custom roles permissions reference](permissions-reference.md).
1. Select **Review** to review the configuration and selected permissions.
1. Select **Create**.

After you create a custom role, you can
[assign it to users or teams](#assign-custom-roles).

## Edit a custom role

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Roles**.
1. Find your custom role in the list, then select the **Actions** menu.
1. Select **Edit**.
1. Edit any of the following settings:
   - **Label**
   - **Description**
   - **Permissions**
1. Select **Save**.

## Assign custom roles

{{< tabs >}}
{{< tab name="Individual users" >}}

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Members**.
1. Locate the member you want to assign a custom role to, then select the
   **Actions** menu.
1. Select **Change role**.
1. From the **Select a role** drop-down list, select your custom role.
1. Select **Save**.

{{< /tab >}}
{{< tab name="Bulk users" >}}

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Members**.
1. Use the checkboxes in the username column to select the users you want
   to assign a custom role to.
1. Select **Change role**.
1. From the **Select a role** drop-down list, select your custom role or
   a core role.
1. Select **Save**.

{{< /tab >}}
{{< tab name="Teams" >}}

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Teams**.
1. Locate the team you want to assign a custom role to, then select the
   **Actions** menu.
1. Select **Assign role**.
1. Select your custom role, then select **Assign**.

The role column updates to the newly assigned role.

{{< /tab >}}
{{< /tabs >}}

## View role assignments

To see which users and teams are assigned to roles:

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Roles**.
1. In the roles list, view the **Users** and **Teams** columns for
   assignment counts.
1. Select a role to view its permissions and assignments in detail.

## Reassign custom roles

{{< tabs >}}
{{< tab name="Individual users" >}}

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Members**.
1. Locate the member you want to reassign, then select the **Actions**
   menu.
1. Select **Change role**.
1. From the **Select a role** drop-down list, select the new role.
1. Select **Save**.

{{< /tab >}}
{{< tab name="Bulk users" >}}

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Members**.
1. Use the checkboxes in the username column to select the users you want
   to reassign.
1. Select **Change role**.
1. From the **Select a role** drop-down list, select the new role.
1. Select **Save**.

{{< /tab >}}
{{< tab name="Teams" >}}

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Teams**.
1. Locate the team, then select the **Actions** menu.
1. Select **Change role**.
1. From the drop-down list, select a role, then select **Save**.

{{< /tab >}}
{{< /tabs >}}

## Delete a custom role

> [!IMPORTANT]
>
> Before you delete a custom role, reassign every user and team that uses
> it to a different role.

1. Sign in to [Docker Home](https://app.docker.com).
1. Select **Roles**.
1. Find your custom role in the list, then select the **Actions** menu.
1. If the role has assigned users or teams:
   - On the **Members** page, change the role for every user assigned to
     this custom role
   - On the **Teams** page, reassign every team that has this custom role
1. When no users or teams are assigned, return to **Roles**.
1. Find your custom role and select the **Actions** menu.
1. Select **Delete**.
1. In the confirmation window, select **Delete** to confirm.

## Next steps

- [Custom roles permissions reference](permissions-reference.md): Review
  permissions you can grant to a custom role
- [Core roles and permissions](../core-roles.md):
  Compare built-in Member, Editor, and Owner permissions
- [Manage organization members](../../../accounts/organization/manage/members.md):
  Invite and manage users in your organization


---

# Custom role permissions reference

*Sección: Security*

{{< summary-bar feature_name="Custom roles" >}}

Custom roles use permissions from organization management, Docker Hub,
billing, AI Governance, Docker Hardened Images, and Docker Offload. Use
the following tables to [create or edit a custom role](manage.md).

## Organization management

| Permission                        | Description                                                                                     |
| :-------------------------------- | :---------------------------------------------------------------------------------------------- |
| View teams                        | View teams and team members                                                                     |
| Manage teams                      | Create, update, and delete teams and team members                                               |
| Manage registry access            | Control which registries members can access                                                     |
| Manage image access               | Set policies for which images members can pull and use                                          |
| Update organization information   | Update organization information such as name and location                                       |
| Member management                 | Manage organization members, invites, and roles                                                 |
| View custom roles                 | View existing custom roles and their permissions                                                |
| Manage custom roles               | Full access to custom role management and assignment                                            |
| Manage organization access tokens | Create, update, and delete repositories in this org. Push/pull or registry actions not included |
| View activity logs                | Access organization audit logs and activity history                                             |
| View usage reports                | Download organization usage reports (pulls, storage)                                            |
| View domains                      | View domains and domain audit settings                                                          |
| Manage domains                    | Manage verified domains and domain audit settings                                               |
| View SSO and SCIM                 | View single sign-on and user provisioning configurations                                        |
| Manage SSO and SCIM               | Full access to SSO and SCIM management                                                          |
| Manage Desktop settings           | Configure Docker Desktop settings policies and view usage reports                               |
| View OIDC connections             | View OIDC connections and their configuration                                                   |
| Manage OIDC connections           | View, create, edit, and delete OIDC connections                                                 |

## Docker Hub

| Permission                         | Description                                                                                  |
| :--------------------------------- | :------------------------------------------------------------------------------------------- |
| View repositories                  | View repository details and contents                                                         |
| Manage repositories                | Full repository management including settings, webhooks, privacy, Dockerfile, immutable tags |
| Manage repository team permissions | Add and remove teams from a repository, and manage team access level                         |

## Billing

| Permission     | Description                                      |
| :------------- | :----------------------------------------------- |
| View billing   | View organization billing information            |
| Manage billing | Complete access to managing organization billing |

## AI Governance

| Permission            | Description                                          |
| :-------------------- | :--------------------------------------------------- |
| View policies         | View existing AI Governance policies and their rules |
| Manage policies       | Full access to AI Governance policy management       |
| View audit logs       | View audit events for the organization               |
| Manage audit settings | Update audit configuration for the organization      |

## DHI (Docker Hardened Images)

| Permission         | Description                                      |
| :----------------- | :----------------------------------------------- |
| Create DHI mirrors | Create Docker Hardened Image mirror repositories |

## Docker Offload

| Permission        | Description                                    |
| :---------------- | :--------------------------------------------- |
| Offload Read-Only | View Offload account status, leases, and zones |

## Next steps

- [Manage custom roles](manage.md): Create, assign, and delete custom
  roles
- [Core roles and permissions](../core-roles.md):
  Compare built-in Member, Editor, and Owner permissions


---

# Docker security announcements

*Sección: Security*

[Subscribe to security RSS feed](/security/security-announcements/index.xml)

## Docker Desktop 4.86.0 security update: CVE-2026-17106

A vulnerability in Docker Desktop was fixed on August 10 in the [4.86.0](../desktop/release-notes.md#4860) release:

- Addressed CVE-2026-17106, a destination-escape flaw in `docker container cp`. 

## Docker Desktop 4.71.0 security update: CVE-2026-5843

A vulnerability in Docker Desktop was fixed on April 27 in the [4.71.0](../desktop/release-notes.md#4710) release:

- Addressed [CVE-2026-5843](https://www.cve.org/cverecord?id=CVE-2026-5843), container-to-host code execution in the Docker Model Runner MLX inference backend.

## Docker Desktop 4.68.0 security update: CVE-2026-5817

A vulnerability in Docker Desktop was fixed on April 7 in the [4.68.0](../desktop/release-notes.md#4680) release:

- Addressed [CVE-2026-5817](https://www.cve.org/cverecord?id=CVE-2026-5817), container-to-host code execution in the Docker Model Runner vllm-metal inference backend.

## Docker Desktop 4.67.0 security update: CVE-2026-33990

A vulnerability in Docker Desktop was fixed on March 30 in the [4.67.0](../desktop/release-notes.md#4670) release:

- Addressed [CVE-2026-33990](https://www.cve.org/cverecord?id=CVE-2026-33990), SSRF in Docker Model Runner OCI Registry Client

## Docker Desktop 4.62.0 security update: CVE-2026-28400

A vulnerability in Docker Desktop was fixed on February 23 in the [4.62.0](../desktop/release-notes.md#4620) release:

- Addressed [CVE-2026-28400](https://www.cve.org/cverecord?id=CVE-2026-28400), runtime flag injection in Docker Model Runner.

## Docker Desktop 4.62.0 security update: CVE-2026-2664

A vulnerability in Docker Desktop was fixed on February 23 in the [4.62.0](../desktop/release-notes.md#4620) release:

- Fixed [CVE-2026-2664](https://www.cve.org/cverecord?id=CVE-2026-2664), out of bounds read in gRPC-FUSE kernel module.

## Docker Desktop 4.54.0 security update: CVE-2025-13743

A vulnerability in Docker Desktop was fixed on December 4 in the [4.54.0](../desktop/release-notes.md#4540) release:

- Fixed [CVE-2025-13743](https://www.cve.org/cverecord?id=CVE-2025-13743) where Docker Desktop diagnostics bundles were found to include expired Hub PATs in log output due to error object serialization.

## Docker Desktop 4.49.0 security update: CVE-2025-9164

A vulnerability in Docker Desktop for Windows was fixed on October 23 in the [4.49.0](../desktop/release-notes.md#4490) release:

- Fixed [CVE-2025-9164](https://www.cve.org/cverecord?id=CVE-2025-9164) where the Docker Desktop for Windows installer was vulnerable to DLL hijacking due to insecure DLL search order. The installer searches for required DLLs in the user's Downloads folder before checking system directories, allowing local privilege escalation through malicious DLL placement.

## Docker Desktop 4.47.0 security update: CVE-2025-10657

A vulnerability in Docker Desktop was fixed on September 25 in the [4.47.0](../desktop/release-notes.md#4470) release:

- Fixed [CVE-2025-10657](https://www.cve.org/CVERecord?id=CVE-2025-10657) where the Enhanced Container Isolation [Docker Socket command restrictions](../enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#command-restrictions) feature was not working properly in Docker Desktop 4.46.0 only (the configuration for it was being ignored).

## Docker Desktop 4.44.3 security update: CVE-2025-9074

_Last updated August 20, 2025_

A vulnerability in Docker Desktop was fixed on August 20 in the [4.44.3](../desktop/release-notes.md#4443) release:

- Fixed [CVE-2025-9074](https://www.cve.org/CVERecord?id=CVE-2025-9074) where a malicious container running on Docker Desktop could access the Docker Engine and launch additional containers without requiring the Docker socket to be mounted. This could allow unauthorized access to user files on the host system. Enhanced Container Isolation (ECI) does not mitigate this vulnerability.

## Docker Desktop 4.44.0 security update: CVE-2025-23266

_Last updated July 31, 2025_

We are aware of [CVE-2025-23266](https://nvd.nist.gov/vuln/detail/CVE-2025-23266), a critical vulnerability affecting the NVIDIA Container Toolkit in CDI mode up to version 1.17.7. Docker Desktop includes version 1.17.8, which is not impacted. However, older versions of Docker Desktop that bundled earlier toolkit versions may be affected if CDI mode was manually enabled. Upgrade to Docker Desktop 4.44 or later to ensure you're using the patched version.

## Docker Desktop 4.43.0 security update: CVE-2025-6587

_Last updated July 03, 2025_

A vulnerability in Docker Desktop was fixed on July 03 in the [4.43.0](../desktop/release-notes.md#4430) release:

- Fixed [CVE-2025-6587](https://www.cve.org/CVERecord?id=CVE-2025-6587) where sensitive system environment variables were included in Docker Desktop diagnostic logs, allowing for potential secret exposure.

## Docker Desktop 4.41.0 Security Update: CVE-2025-3224, CVE-2025-4095, and CVE-2025-3911

_Last updated May 15, 2025_

Three vulnerabilities in Docker Desktop were fixed on April 28 in the [4.41.0](../desktop/release-notes.md#4410) release.

- Fixed [CVE-2025-3224](https://www.cve.org/CVERecord?id=CVE-2025-3224) allowing an attacker with access to a user machine to perform an elevation of privilege when Docker Desktop updates.
- Fixed [CVE-2025-4095](https://www.cve.org/CVERecord?id=CVE-2025-4095) where Registry Access Management (RAM) policies were not enforced when using a MacOS configuration profile, allowing users to pull images from unapproved registries.
- Fixed [CVE-2025-3911](https://www.cve.org/CVERecord?id=CVE-2025-3911) allowing an attacker with read access to a user's machine to obtain sensitive information from Docker Desktop log files, including environment variables configured for running containers.

We strongly encourage you to update to Docker Desktop [4.41.0](../desktop/release-notes.md#4410).

## Docker Desktop 4.34.2 Security Update: CVE-2024-8695 and CVE-2024-8696

_Last updated September 13, 2024_

Two remote code execution (RCE) vulnerabilities in Docker Desktop related to Docker Extensions were reported by [Cure53](https://cure53.de/) and were fixed on September 12 in the [4.34.2](../desktop/release-notes.md#4342) release.

- [CVE-2024-8695](https://www.cve.org/cverecord?id=CVE-2024-8695): A remote code execution (RCE) vulnerability via crafted extension description/changelog could be abused by a malicious extension in Docker Desktop before 4.34.2. [Critical]
- [CVE-2024-8696](https://www.cve.org/cverecord?id=CVE-2024-8696): A remote code execution (RCE) vulnerability via crafted extension publisher-url/additional-urls could be abused by a malicious extension in Docker Desktop before 4.34.2. [High]

No existing extensions exploiting the vulnerabilities were found in the Extensions Marketplace. The Docker Team will be closely monitoring and diligently reviewing any requests for publishing new extensions.

We strongly encourage you to update to Docker Desktop [4.34.2](../desktop/release-notes.md#4342). If you are unable to update promptly, you can [disable Docker Extensions](../extensions/settings-feedback.md#turn-on-or-turn-off-extensions) as a workaround.

## Deprecation of password logins on CLI when SSO enforced

_Last updated July, 2024_

When [SSO enforcement](authentication/single-sign-on/connect.md) was first introduced, Docker provided a grace period to continue to let passwords be used on the Docker CLI when authenticating to Docker Hub. This was allowed so organizations could more easily use SSO enforcement. It is recommended that administrators configuring SSO encourage users using the CLI [to switch over to Personal Access Tokens](authentication/single-sign-on/index.md#prerequisites) in anticipation of this grace period ending.

On September 16, 2024, the grace period ended and passwords can no longer authenticate to Docker Hub via the Docker CLI when SSO is enforced. Affected users are required to switch over to using PATs to continue signing in.

At Docker, we want the experience to be the most secure for our developers and organizations and this deprecation is an essential step in that direction.

## SOC 2 Type 2 attestation and ISO 27001 certification

_Last updated June, 2024_

Docker is pleased to announce that we have received our SOC 2 Type 2 attestation and ISO 27001 certification with no exceptions or major non-conformities.

Security is a fundamental pillar to Docker's operations, which is embedded into our overall mission and company strategy. Docker's products are core to our user community and our SOC 2 Type 2 attestation and ISO 27001 certification demonstrate Docker's ongoing commitment to security to our user base.

For more information, see the [Blog announcement](https://www.docker.com/blog/docker-announces-soc-2-type-2-attestation-iso-27001-certification/).

## Docker Security Advisory: Multiple Vulnerabilities in runc, BuildKit, and Moby

_Last updated February 2, 2024_

We at Docker prioritize the security and integrity of our software and the trust of our users. Security researchers at Snyk Labs identified and reported four security vulnerabilities in the container ecosystem. One of the vulnerabilities, [CVE-2024-21626](https://scout.docker.com/v/CVE-2024-21626), concerns the runc container runtime, and the other three affect BuildKit ([CVE-2024-23651](https://scout.docker.com/v/CVE-2024-23651), [CVE-2024-23652](https://scout.docker.com/v/CVE-2024-23652), and [CVE-2024-23653](https://scout.docker.com/v/CVE-2024-23653)). We want to assure our community that our team, in collaboration with the reporters and open source maintainers, has been diligently working on coordinating and implementing necessary remediations.

We are committed to maintaining the highest security standards. We have published patched versions of runc, BuildKit, and Moby on January 31 and released an update for Docker Desktop on February 1 to address these vulnerabilities. Additionally, our latest BuildKit and Moby releases included fixes for [CVE-2024-23650](https://scout.docker.com/v/CVE-2024-23650) and [CVE-2024-24557](https://scout.docker.com/v/CVE-2024-24557), discovered respectively by an independent researcher and through Docker's internal research initiatives.

|                        | Versions Impacted       |
| :--------------------- | :---------------------- |
| `runc`                 | <= 1.1.11               |
| `BuildKit`             | <= 0.12.4               |
| `Moby (Docker Engine)` | <= 25.0.1 and <= 24.0.8 |
| `Docker Desktop`       | <= 4.27.0               |

### What should I do if I'm on an affected version?

If you are using affected versions of runc, BuildKit, Moby, or Docker Desktop, make sure to update to the latest versions, linked in the following table:

|                        | Patched Versions                                                                                                                  |
| :--------------------- | :-------------------------------------------------------------------------------------------------------------------------------- |
| `runc`                 | >= [1.1.12](https://github.com/opencontainers/runc/releases/tag/v1.1.12)                                                          |
| `BuildKit`             | >= [0.12.5](https://github.com/moby/buildkit/releases/tag/v0.12.5)                                                                |
| `Moby (Docker Engine)` | >= [25.0.2](https://github.com/moby/moby/releases/tag/v25.0.2) and >= [24.0.9](https://github.com/moby/moby/releases/tag/v24.0.9) |
| `Docker Desktop`       | >= [4.27.1](../desktop/release-notes.md#4271)                                                                               |

If you are unable to update to an unaffected version promptly, follow these best practices to mitigate risk:

- Only use trusted Docker images (such as [Docker Official Images](../docker-hub/image-library/trusted-content.md#docker-official-images)).
- Don't build Docker images from untrusted sources or untrusted Dockerfiles.
- If you are a Docker Business customer using Docker Desktop and unable to update to v4.27.1, make sure to enable [Hardened Docker Desktop](../enterprise/security/hardened-desktop/index.md) features such as:
  - [Enhanced Container Isolation](../enterprise/security/hardened-desktop/enhanced-container-isolation/index.md), which mitigates the impact of CVE-2024-21626 in the case of running containers from malicious images.
  - [Image Access Management](../enterprise/security/hardened-desktop/image-access-management.md), and [Registry Access Management](../enterprise/security/hardened-desktop/registry-access-management.md), which give organizations control over which images and repositories their users can access.
- For CVE-2024-23650, CVE-2024-23651, CVE-2024-23652, and CVE-2024-23653, avoid using BuildKit frontend from an untrusted source. A frontend image is usually specified as the #syntax line on your Dockerfile, or with `--frontend` flag when using the `buildctl build` command.
- To mitigate CVE-2024-24557, make sure to either use BuildKit or disable caching when building images. From the CLI this can be done via the `DOCKER_BUILDKIT=1` environment variable (default for Moby >= v23.0 if the Buildx plugin is installed) or the `--no-cache flag`. If you are using the HTTP API directly or through a client, the same can be done by setting `nocache` to `true` or `version` to `2` for the [/build API endpoint](https://docs.docker.com/reference/api/engine/version/v1.44/#tag/Image/operation/ImageBuild).

### Technical details and impact

#### CVE-2024-21626 (High)

In runc v1.1.11 and earlier, due to certain leaked file descriptors, an attacker can gain access to the host filesystem by causing a newly-spawned container process (from `runc exec`) to have a working directory in the host filesystem namespace, or by tricking a user to run a malicious image and allow a container process to gain access to the host filesystem through `runc run`. The attacks can also be adapted to overwrite semi-arbitrary host binaries, allowing for complete container escapes. Note that when using higher-level runtimes (such as Docker or Kubernetes), this vulnerability can be exploited by running a malicious container image without additional configuration or by passing specific workdir options when starting a container. The vulnerability can also be exploited from within Dockerfiles in the case of Docker.

_The issue has been fixed in runc v1.1.12._

#### CVE-2024-23651 (High)

In BuildKit <= v0.12.4, two malicious build steps running in parallel sharing the same cache mounts with subpaths could cause a race condition, leading to files from the host system being accessible to the build container. This will only occur if a user is trying to build a Dockerfile of a malicious project.

_The issue has been fixed in BuildKit v0.12.5._

#### CVE-2024-23652 (High)

In BuildKit <= v0.12.4, a malicious BuildKit frontend or Dockerfile using `RUN --mount` could trick the feature that removes empty files created for the mountpoints into removing a file outside the container from the host system. This will only occur if a user is using a malicious Dockerfile.

_The issue has been fixed in BuildKit v0.12.5._

#### CVE-2024-23653 (High)

In addition to running containers as build steps, BuildKit also provides APIs for running interactive containers based on built images. In BuildKit <= v0.12.4, it is possible to use these APIs to ask BuildKit to run a container with elevated privileges. Normally, running such containers is only allowed if special `security.insecure` entitlement is enabled both by buildkitd configuration and allowed by the user initializing the build request.

_The issue has been fixed in BuildKit v0.12.5._

#### CVE-2024-23650 (Medium)

In BuildKit <= v0.12.4, a malicious BuildKit client or frontend could craft a request that could lead to BuildKit daemon crashing with a panic.

_The issue has been fixed in BuildKit v0.12.5._

#### CVE-2024-24557 (Medium)

In Moby <= v25.0.1 and <= v24.0.8, the classic builder cache system is prone to cache poisoning if the image is built FROM scratch. Also, changes to some instructions (most important being `HEALTHCHECK` and `ONBUILD`) would not cause a cache miss. An attacker with knowledge of the Dockerfile someone is using could poison their cache by making them pull a specially crafted image that would be considered a valid cache candidate for some build steps.

_The issue has been fixed in Moby >= v25.0.2 and >= v24.0.9._

### How are Docker products affected?

#### Docker Desktop

Docker Desktop v4.27.0 and earlier are affected. Docker Desktop v4.27.1 was released on February 1 and includes runc, BuildKit, and dockerd binaries patches. In addition to updating to this new version, we encourage all Docker users to diligently use Docker images and Dockerfiles and ensure you only use trusted content in your builds.

As always, you should check Docker Desktop system requirements for your operating system ([Windows](../desktop/setup/install/windows-install.md#system-requirements), [Linux](../desktop/setup/install/linux/index.md#general-system-requirements), [Mac](../desktop/setup/install/mac-install.md#system-requirements)) before updating to ensure full compatibility.

#### Docker Build Cloud

Any new Docker Build Cloud builder instances will be provisioned with the latest Docker Engine and BuildKit versions and will, therefore, be unaffected by these CVEs. Updates have also been rolled out to existing Docker Build Cloud builders.

_No other Docker products are affected by these vulnerabilities._

### Advisory links

- Runc
  - [CVE-2024-21626](https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv)
- BuildKit
  - [CVE-2024-23650](https://github.com/moby/buildkit/security/advisories/GHSA-9p26-698r-w4hx)
  - [CVE-2024-23651](https://github.com/moby/buildkit/security/advisories/GHSA-m3r6-h7wv-7xxv)
  - [CVE-2024-23652](https://github.com/moby/buildkit/security/advisories/GHSA-4v98-7qmw-rqr8)
  - [CVE-2024-23653](https://github.com/moby/buildkit/security/advisories/GHSA-wr6v-9f75-vh2g)
- Moby
  - [CVE-2024-24557](https://github.com/moby/moby/security/advisories/GHSA-xw73-rw38-6vjc)

## Text4Shell CVE-2022-42889

_Last updated October 2022_

[CVE-2022-42889](https://nvd.nist.gov/vuln/detail/CVE-2022-42889) has been discovered in the popular Apache Commons Text library. Versions of this library up to but not including 1.10.0 are affected by this vulnerability.

We strongly encourage you to update to the latest version of [Apache Commons Text](https://commons.apache.org/proper/commons-text/download_text.cgi).

### Scan images on Docker Hub

Docker Hub security scans triggered after 1200 UTC 21 October 2021 are now
correctly identifying the Text4Shell CVE. Scans before this date do not
currently reflect the status of this vulnerability. Therefore, we recommend that
you trigger scans by pushing new images to Docker Hub to view the status of
the Text4Shell CVE in the vulnerability report. For detailed instructions, see [Scan images on Docker Hub](../docker-hub/repos/manage/vulnerability-scanning.md).

### Docker Official Images impacted by CVE-2022-42889

A number of [Docker Official Images](../docker-hub/image-library/trusted-content.md#docker-official-images) contain the vulnerable versions of
Apache Commons Text. The following lists Docker Official Images that
may contain the vulnerable versions of Apache Commons Text:

- [bonita](https://hub.docker.com/_/bonita)
- [Couchbase](https://hub.docker.com/_/couchbase)
- [Geonetwork](https://hub.docker.com/_/geonetwork)
- [neo4j](https://hub.docker.com/_/neo4j)
- [sliverpeas](https://hub.docker.com/_/sliverpeas)
- [solr](https://hub.docker.com/_/solr)
- [xwiki](https://hub.docker.com/_/xwiki)

We have updated
Apache Commons Text in these images to the latest version. Some of these images may not be
vulnerable for other reasons. We recommend that you also review the guidelines published on the upstream websites.

## Log4j 2 CVE-2021-44228

_Last updated December 2021_

The [Log4j 2 CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228) vulnerability in Log4j 2, a very common Java logging library, allows remote code execution, often from a context that is easily available to an attacker. For example, it was found in Minecraft servers which allowed the commands to be typed into chat logs as these were then sent to the logger. This makes it a very serious vulnerability, as the logging library is used so widely and it may be simple to exploit. Many open source maintainers are working hard with fixes and updates to the software ecosystem.

The vulnerable versions of Log4j 2 are versions 2.0 to version 2.14.1 inclusive. The first fixed version is 2.15.0. We strongly encourage you to update to the [latest version](https://logging.apache.org/log4j/2.x/download.html) if you can. If you are using a version before 2.0, you are also not vulnerable.

You may not be vulnerable if you are using these versions, as your configuration
may already mitigate this, or the things you
log may not include any user input. This may be difficult to validate however
without understanding all the code paths that may log in detail, and where they
may get input from. So you probably will want to upgrade all code using
vulnerable versions.

> CVE-2021-45046
>
> As an update to
> [CVE-2021-44228](https://nvd.nist.gov/vuln/detail/CVE-2021-44228), the fix made in version 2.15.0 was
> incomplete. Additional issues have been identified and are tracked with
> [CVE-2021-45046](https://nvd.nist.gov/vuln/detail/CVE-2021-45046) and
> [CVE-2021-45105](https://nvd.nist.gov/vuln/detail/CVE-2021-45105).
> For a more complete fix to this vulnerability, we recommended that you update to 2.17.0 where possible.

### Scan images on Docker Hub

Docker Hub security scans triggered after 1700 UTC 13 December 2021 are now
correctly identifying the Log4j 2 CVEs. Scans before this date do not
currently reflect the status of this vulnerability. Therefore, we recommend that
you trigger scans by pushing new images to Docker Hub to view the status of
Log4j 2 CVE in the vulnerability report. For detailed instructions, see [Scan images on Docker Hub](../docker-hub/repos/manage/vulnerability-scanning.md).

## Docker Official Images impacted by Log4j 2 CVE

_Last updated December 2021_

A number of [Docker Official Images](../docker-hub/image-library/trusted-content.md#docker-official-images) contain the vulnerable versions of
Log4j 2 CVE-2021-44228. The following table lists Docker Official Images that
may contained the vulnerable versions of Log4j 2. We updated Log4j 2 in these images to the latest version. Some of these images may not be
vulnerable for other reasons. We recommend that you also review the guidelines published on the upstream websites.

| Repository                                              | Patched version                | Additional documentation                                                                                                |
| :------------------------------------------------------ | :----------------------------- | :---------------------------------------------------------------------------------------------------------------------- |
| [couchbase](https://hub.docker.com/_/couchbase)         | 7.0.3                          | [Couchbase blog](https://blog.couchbase.com/what-to-know-about-the-log4j-vulnerability-cve-2021-44228/)                 |
| [Elasticsearch](https://hub.docker.com/_/elasticsearch) | 6.8.22, 7.16.2                 | [Elasticsearch announcement](https://www.elastic.co/blog/new-elasticsearch-and-logstash-releases-upgrade-apache-log4j2) |
| [Flink](https://hub.docker.com/_/flink)                 | 1.11.6, 1.12.7, 1.13.5, 1.14.2 | [Flink advice on Log4j CVE](https://flink.apache.org/2021/12/10/log4j-cve.html)                                         |
| [Geonetwork](https://hub.docker.com/_/geonetwork)       | 3.10.10                        | [Geonetwork GitHub discussion](https://github.com/geonetwork/core-geonetwork/issues/6076)                               |
| [lightstreamer](https://hub.docker.com/_/lightstreamer) | Awaiting info                  | Awaiting info                                                                                                           |
| [logstash](https://hub.docker.com/_/logstash)           | 6.8.22, 7.16.2                 | [Elasticsearch announcement](https://www.elastic.co/blog/new-elasticsearch-and-logstash-releases-upgrade-apache-log4j2) |
| [neo4j](https://hub.docker.com/_/neo4j)                 | 4.4.2                          | [Neo4j announcement](https://community.neo4j.com/t/log4j-cve-mitigation-for-neo4j/48856)                                |
| [solr](https://hub.docker.com/_/solr)                   | 8.11.1                         | [Solr security news](https://solr.apache.org/security.html#apache-solr-affected-by-apache-log4j-cve-2021-44228)         |
| [sonarqube](https://hub.docker.com/_/sonarqube)         | 8.9.5, 9.2.2                   | [SonarQube announcement](https://community.sonarsource.com/t/sonarqube-sonarcloud-and-the-log4j-vulnerability/54721)    |
| [storm](https://hub.docker.com/_/storm)                 | Awaiting info                  | Awaiting info                                                                                                           |

> [!NOTE]
>
> Although [xwiki](https://hub.docker.com/_/xwiki) images may be detected as vulnerable
> by some scanners, the authors believe the images are not vulnerable by Log4j 2
> CVE as the API jars do not contain the vulnerability.
> The [Nuxeo](https://hub.docker.com/_/nuxeo)
> image is deprecated and will not be updated.


---

# Subscription and billing

*Sección: Subscription Billing*

A Docker plan is a subscription tied to a personal account, an organization
account, or a specific product. When you upgrade a plan, you expand your
usage entitlements and feature sets. You can also top up some plans,
extending usage without changing your plan type.

## Docker plans

The following table summarizes the available plans.

| Plans | Billing model | Types |
| --- | --- | --- |
| [Docker](plans/docker.md) | Flat-rate plans for personal and organization accounts | Docker Personal, Docker Pro, Docker Team, Docker Business |
| [Docker Hardened Images (DHI)](plans/dhi.md) | Graduated security features for hardened container images | DHI Community, DHI Select, DHI Enterprise |
| [Gordon](plans/gordon.md) | Prepaid usage for the Gordon AI agent | Gordon Plus, Gordon Max, Gordon Ultra |
| [AI Governance](plans/ai-governance.md) | Purchase set amount of licenses | AI Governance |
| [Docker Verified Publisher (DVP)](plans/docker-verified-publisher.md) | Annual plans based on consuming domains | DVP Starter, DVP Growth |

Docker plans that upgrade your account (Docker Pro, Team, and Business) cover
most use cases. Some product plans require an upgraded Docker account. Others
let you subscribe without one. For details, see
[Plans](plans/index.md).

## Top up your plan

Plans come with usage entitlements that can be extended without upgrading to
a different plan.

| Unit | Description | Examples |
| --- | --- | --- |
| Seats | Each seat extends entitlements to one more member. | Docker Team, Docker Business |
| Licenses | Access to specific products or features. | AI Governance, Docker Offload |
| Minutes | Cloud build capacity, sold in blocks and consumed within the billing period. | Docker Build Cloud |
| Repositories | Additional container repositories covered by security scanning and analysis features. | DHI |
| Consuming domains | Additional consuming domains tracked in publisher analytics, sold in blocks of 25. | DVP Starter, DVP Growth |

## Manage your plans

To subscribe to a new plan or upgrade an active plan, see
[Manage plans](manage/plans.md). See
[Docker plans](plans/docker.md) to learn about
Docker Team, Business, and Pro. You can also
<a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_index_sales" class="link" rel="noopener">contact sales</a>.

To update payment methods, review usage and credits, or download invoices, see
[Manage billing](manage/index.md).

## Next steps

{{< grid >}}


---

# Docker Desktop license agreement

*Sección: Subscription Billing*

Docker Desktop is licensed under the [Docker Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement). When you download and install Docker Desktop, you're asked to agree to these terms.

The Docker Subscription Service Agreement states:

- Docker Desktop is free for:
  - Small businesses (fewer than 250 employees AND less than $10 million in annual revenue)
  - Personal use
  - Education
  - Non-commercial open source projects
- Docker Desktop requires a paid subscription for:
  - Professional use in larger organizations
  - Government entities
  - Commercial use beyond the free tier limits
- Paid subscriptions that include Docker Desktop:
  - Docker Pro, Team, and Business subscriptions

## Understanding licensing terms

For detailed information about how these terms may affect your organization, see:

- [Subscription updates blog post](https://www.docker.com/blog/updating-product-subscriptions/)
- [Docker subscription FAQs](https://www.docker.com/pricing/faq) to learn how this may affect companies using Docker Desktop.

> [!NOTE]
>
> The licensing and distribution terms for Docker and Moby open-source projects, such as Docker Engine, aren't changing.

Docker Desktop is built using open-source software. For information about the licensing of open-source components in Docker Desktop, select the whale menu > **About Docker Desktop** > **Acknowledgements**.

## Open source components

Docker Desktop distributes some components that are licensed under the
GNU General Public License. [Download the source code for these components here](https://download.docker.com/opensource/License.tar.gz).


---

# Use 3D Secure authentication for Docker billing

*Sección: Subscription Billing*

Docker supports 3D Secure (3DS), an extra layer of authentication required
for certain credit card payments. If your bank or card issuer requires 3DS, you
may need to verify your identity before your payment can be completed.

## How it works

When a 3DS check is triggered during checkout, your bank or card issuer
may ask you to verify your identity. This can include:

- Entering a one-time password sent to your phone
- Approving the charge through your mobile banking app
- Answering a security question or using biometrics

The exact verification steps depend on your financial institution's
requirements.

## When you need to verify

You may be asked to verify your identity when performing any of the following
actions:

- Starting a [paid subscription](plans.md)
- Changing your [billing cycle](details.md#billing-cycle) from monthly to annual
- [Upgrading your subscription](plans.md#upgrade-plans)
- [Adding seats](../../accounts/organization/manage/manage-seats.md) to an existing
  subscription

If 3DS is required and your payment method supports it, the verification prompt
will appear during checkout.

## Troubleshooting payment verification

If you're unable to complete your payment due to 3DS:

1. Retry your transaction. Make sure you're completing the verification
   prompt in the same browser tab.
1. Use a different payment method.
1. Contact your bank to confirm whether it's blocking the payment or the 3DS
   verification attempt.

> [!NOTE]
>
> Disabling ad blockers or browser extensions that block pop-ups can help
> the 3DS prompt display correctly.


---

# Manage billing

*Sección: Subscription Billing*

You manage Docker plans, payment methods, invoices, credits, and taxes from
Docker Home. Billing is scoped to the account you
select. To manage billing:

1. Sign in to [Docker Home](https://app.docker.com/), then choose your
   personal account or organization.
1. Select **Billing**.
1. Select the page you want in the sidebar, or stay on **Overview**.

To add or upgrade a plan, see
[Manage plans](plans.md). To compare
plan types, see [Plans](../plans/index.md).

## Overview

When you select **Billing**, you are taken to the **Overview** page, where you review active plans, payment
method, and subscription totals for that account. From there you add
self-serve products, manage a plan you already have, or open another
billing page in the sidebar.

## Invoices

The billing **Invoices** page lists invoices issued when a plan renews or
changes. You can open an invoice, check payment status, and download a
copy. 

## Usage

The billing **Usage** page helps you compare usage-based charges across
billing periods. You can track usage by changing the period, product,
and how the product is metered.

## Costs

The billing **Costs** page aggregates all costs by billing period. It
breaks down charges by resource (the product accruing a charge), the
status of your billing period, and costs to date.

## Credits

The billing **Credits** page shows credits applied to your costs. If you
received a promotional credit, you can see how it applies to your bill
from this page.

## Next steps

{{< grid >}}


---

# Update your billing details

*Sección: Subscription Billing*

You can update your billing contact information, address, and notification email at any time. Existing invoices, whether paid or unpaid, cannot be updated. Changes only apply to future invoices.

## Update billing details

You can update your billing details for Docker individual accounts and Docker organization accounts using the same procedures.

To update your billing information from **Settings** in Docker Home:

1. Sign in to [Docker Home](https://app.docker.com/) and select your personal or organization
   account.
1. Select **Billing**, then go to **Settings**.
1. Select **Edit** to make your changes.
1. Verify your information, then select **Save as default**.

For more information on changing your default payment method, see [Change default payment method](payment-method.md#change-default-payment-method).

## Billing notifications

Docker sends invoices and other billing-related communications
to the billing account's email address. These communications include:

- Confirmations, such as new subscriptions, paid invoices
- Notifications for card failure and card expiration errors
- Reminders for subscription renewal

## Billing cycle

Billing cycles are defined on a per-plan basis. Depending on the product you
subscribe to, your cycle can be monthly, annual, or another cadence. For
plan-specific billing cycle details, see [Plans](../plans/index.md).


---

# Billing and invoice history

*Sección: Subscription Billing*

Docker issues an invoice each time a subscription to a Docker plan renews or changes. You can track invoices issued to your account so you can review the plans you've
subscribed to over time, check payment status, and download records as
needed.

## View billing history

Personal accounts and organization accounts use the same steps to view billing
history. To view your billing history:

1. Sign in to [Docker Home](https://app.docker.com/) and select your personal
   account or organization account.
1. Select **Billing**, then **Invoices**.
1. View an individual invoice by selecting:
   - **Invoice number** to open invoice details in your browser
   - **Download** to download a copy of your invoice.

> [!NOTE]
>
> If you want to view your organization account's
> billing history, you must be an organization owner.

## Understand your invoice

Your invoice includes the following information:

| Invoice field  | Description                                                                                   |
| -------------- | --------------------------------------------------------------------------------------------- |
| Invoice number | A unique identifier for the invoice                                                           |
| Date of issue  | The date Docker generated the invoice                                                         |
| Due date       | The date your payment is due                                                                  |
| Bill to        | Your billing name, address, and contact information                                           |
| Line items     | The description, quantity (if applicable), unit price, and amount for each item on your order |
| Subtotal       | The total amount before any discounts                                                         |
| Total          | The subtotal after any discounts, matching the amount due                                     |
| Amount due     | The total amount you owe, in USD                                                              |
| Pay online     | A link to pay an unpaid invoice online                                                        |

The information in the **Bill to** section comes from your billing
information.

- Not all fields are required.
- You can't change a paid or unpaid invoice.
- Updating your billing information
  doesn't update an existing invoice.

If you want different billing information reflected in your invoice, update your billing information before your renewal date, when
Docker finalizes your invoice. For more information, see [Update billing information](details.md).

## View renewal date

Renewal dates are set on a per-plan basis, so check each plan individually if you subscribe to more than one. Depending on the product, your billing cycle can be monthly, annual, or another cadence. For plan-specific renewal and billing cycle details, see [Plans](../plans/index.md).

## Pay by invoice

> [!TIP]
>
> To pay by invoice,
> [upgrade to a Docker Team or Docker Business plan](https://www.docker.com/pricing?ref=Docs&refAction=DocsBillingPaymentMethod)
> and choose an annual subscription.

Pay by invoice requires upfront payment for your first subscription period
using a payment card or ACH bank transfer. At renewal, Docker emails you an
invoice to pay manually instead of charging your default payment method.

- To add pay by invoice as a payment method, contact your Docker sales
  representative.
- You can only pay by invoice by choosing it as a payment method when
  subscribing to Docker Team or Docker Business plans.
- Pay by invoice isn't available for subscription upgrades or changes.


---

# Add or update a payment method

*Sección: Subscription Billing*

Docker supports several payment methods for paid personal accounts and
organizations. This page describes supported payment types, how to manage
payments from [Docker Home](https://app.docker.com/), and how to set up pay by
invoice.

## Supported payment types

You can add or update a payment method at any time. All charges are in United
States dollars (USD). Docker supports the following payment methods:

| Category      | Payment type                                                            |
| ------------- | ----------------------------------------------------------------------- |
| Cards         | Visa, MasterCard, American Express, Discover, JCB, Diners, UnionPay     |
| Wallets       | Stripe Link                                                             |
| Bank accounts | Automated Clearing House (ACH) transfer with a verified US bank account |

Some payment methods require additional setup before changing it to your default payment method. For example:

- Verify a
  [bank account](#verify-a-bank-account) before choosing it as a payment method.
- Use an existing Stripe Link account, or enter your card information to set up
  Stripe Link.

## Manage payment method

Paid personal accounts and organizations follow the same procedures to add,
update, or remove payment methods.

### Add payment method

You can add multiple payment methods in the billing portal. When you add a new payment method, you set it as a new default payment method.

1. Sign in to [Docker Home](https://app.docker.com/).
1. Select your username for a personal account, or select your organization
   name for an organization.
1. Select **Billing** to go to the billing portal, then **Change** in the **Payment method** tile.
1. From the **Change payment method** modal, choose to add a card, a US bank account, or a Stripe Link payment.
   - To pay with a card, enter your card information.
   - To pay with a US bank account, verify your **Email** and **Full name**.
     - If your bank is listed, select your bank's name.
     - If your bank is not listed, select **Search for your bank**.
   - To pay through Stripe Link, select an existing payment method, then select
     **Use this card**.
1. For first-time setup, enter your billing information.
1. Finish adding the payment method by selecting **Save as default**.

### Change default payment method

After adding one or more payment methods, you can set one as a default method.

1. From **Billing**, go to the **Payment method** tile.
1. Select **Change** to open the **Change payment method** modal, then select **Change** next to your current default method.
1. Choose the payment method you want to set as default.
1. Verify your information, then select **Save as default**.

### Remove payment method

You can only remove secondary payment methods. To remove a secondary payment method:

1. From **Billing**, go to the **Payment method** tile.
1. Select **Change** to open the **Change payment method** modal.
1. Select the **Actions** menu next to the payment method you want to remove, then select **Remove**.
1. Verify your billing details, then select **Save as default**.

To remove your default payment method, first set a different payment method as default, or [downgrade to a free subscription](../plans/docker.md#cancel-a-docker-plan).

## Enable and disable pay by invoice

> [!TIP]
> Do you need to pay by invoice? [Upgrade to a Docker Business or Docker Team plan](https://www.docker.com/pricing?ref=Docs&refAction=DocsBillingPaymentMethod) and choose the annual subscription.

Pay by invoice requires you to pay upfront for your first subscription period using a payment card or ACH bank transfer. At renewal time, instead of automatic payment, you'll receive an invoice via
email that you must pay manually.

Follow these steps to enable or disable pay by invoice:

1. Sign in to [Docker Home](https://app.docker.com/) and select your
   organization.
2. Select **Billing**, then **Payment methods**.
3. Select **Pay by invoice**, then select the pay by invoice toggle to enable or disable.
4. Confirm your billing contact details. If you need to change them, select
   **Change** and enter your new details.

Pay by invoice is not available for
subscription upgrades or changes.

## Verify a bank account

You can verify your bank account with instant verification for supported banks. You must sign in to your US bank account when adding your bank as a payment method:

1. From **Billing**, go to the **Payment method** tile and select **Change**.
1. Choose **US bank account** as your payment method.
1. Verify your **Email** and **Full name**.
1. Search for your bank, then select it to initiate the sign-in flow.
1. Review the terms and conditions. This agreement
   allows Docker to debit payments from your connected bank account.
1. Select **Agree and continue**.
1. Select an account to link and verify, then select **Connect account**.

When the account is verified, a success message appears.

## Failed payments

If your payment fails, select **Pay now** to retry the payment through Stripe.

You have a grace period of 15 days, including the due date, when your payment
fails. Docker attempts to collect the payment three times using the following
schedule:

- 3 days after the due date
- 5 days after the previous attempt
- 7 days after the previous attempt

Docker also sends an email notification
`Action Required - Credit Card Payment Failed` with an attached unpaid invoice
after each failed payment attempt.

If the invoice remains unpaid after the grace period, the
subscription downgrades to a free subscription and all paid features are
disabled.

## Pay by invoice

> [!TIP]
>
> To pay by invoice,
> [upgrade to a Docker Team or Docker Business plan](https://www.docker.com/pricing?ref=Docs&refAction=DocsBillingPaymentMethod)
> and choose an annual subscription.

Pay by invoice requires upfront payment for your first subscription period
using a payment card or ACH bank transfer. At renewal, Docker emails you an
invoice to pay manually instead of charging your default payment method.

- To add pay by invoice as a payment method, contact your Docker sales representative.
- You can only pay by invoice by choosing it as a payment method when subscribing to Docker Team or Docker Business plans. 
- Pay by invoice isn't available for subscription upgrades or changes.


---

# Manage plans

*Sección: Subscription Billing*

You can add and manage your plans from the billing portal in Docker Home. Within the billing portal, you use the product catalog to view
self-serve Docker products, while the Overview page shows your active plans with options to upgrade or cancel.

## Set up a new plan

You can purchase Docker Team, Docker Business, and other products through the product catalog:

1. Sign in to [Docker Home](https://app.docker.com/), then choose your personal
   account or your organization account.
1. Go to **Billing**.
1. Select **Browse products**.
   - The **Products** page contains products and upgrades available for self-serve.
   - Some products in the catalog may apply to personal accounts, organization accounts, or both.
   - Each product tile uses an account-type flag so you know the difference.
1. Select **View plans**, then choose the plan you want to add to your Docker subscription.
1. Verify your billing details, continue to payment, and complete checkout.
   - Optional. To add a VAT number, select the **I'm purchasing as a business**
     checkbox and enter your Tax ID.
   - Your VAT number must include your country prefix. For example, enter
     `DE123456789` for a German VAT number.

To upgrade to Docker Pro, go to the
<a href="https://www.docker.com/pricing/" id="dkr_docs_pricing_manage_pro" class="link" rel="noopener">Docker pricing page</a>
and select **Buy now**.

## Upgrade plans

You can upgrade active plans from the billing Overview page.

1. Sign in to [Docker Home](https://app.docker.com/), then choose your personal
   account or your organization account.
1. Go to **Billing** to view the Overview page.
   - The Overview page contains your active plans and payment details.
   - **Active plans** contains information about plan type, renewal cadence, and usage.
1. Top up or upgrade from the **Active plans** section.
   - **Active plans** is where you complete all management actions.
   - Depending on the plan type, you can select the action menu button or the **Manage** button to choose from available actions.
1. Verify your billing details, continue to payment, and complete checkout.

> [!TIP]
> Billing cycle details vary from plan to plan. Learn more about usage, downgrading, or canceling plans
> from the relevant
> [product page](../plans/index.md).

## View your credits

Docker displays available account credits in the billing portal. Credits
offset eligible usage automatically before Docker charges your payment
method. To review credit balance and applied credits, see
[Credits](index.md#credits).

Credits apply to
[Docker Agentic Platform](../plans/docker-agentic-platform.md).
When you sign up for Docker Agentic Platform, Docker adds a one-time
promotional credit to your account. This credit is non-recurring,
doesn't expire, and applies to cloud compute usage only. It doesn't
apply to inference, which you pay for through your own API keys.

## Sales-led products

Some products are sales-led. You must
<a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_plans_manage" class="link" rel="noopener">contact sales</a> to opt in.

## Next steps

- [Learn about available plans](../plans/index.md)
- [Set up payment information](payment-method.md)
- [View invoices](history.md)
- To learn more about managing your billing details, see [Billing](../index.md).
- To learn about sales tax and VAT, see
  [Taxes](tax-certificate.md).


---

# Sales tax exemption and VAT

*Sección: Subscription Billing*

Depending on your location, Docker may collect sales tax or VAT on your
subscription. Tax relief is the same idea in both cases, but the process
differs:

- United States customers request exemption by submitting a tax exemption
  certificate through Docker Support. The billing portal has no self-serve
  tax ID field for US customers.
- Customers in VAT countries enter a tax ID or VAT number themselves when they
  purchase a Docker plan.

## United States tax exemption

US customers submit a support ticket with a valid tax exemption certificate
to receive tax-exempt status. Docker reviews the certificate and applies the
exemption to your billing profile. You can apply for tax-exempt status:

- Before you purchase, submit your certificate and wait for Docker to approve
  it. After approval, you can purchase without sales tax.
- If you were charged sales tax, open a support ticket to coordinate with
  Docker Support on exempt status.

### Prerequisites

Before submitting your certificate, confirm the following:

- Customer name matches the name on the certificate.
- The certificate lists Docker, Inc. as the seller or vendor, with all
  relevant fields completed.
- The certificate is signed, dated, and not expired.
- You've included the Docker ID or namespace(s) for all accounts the
  certificate applies to.

> [!TIP]
>
> You can use the same certificate for multiple namespaces when applicable.

### Contact information

Use the following contact information on your certificate:

```text
Docker, Inc.
3790 El Camino Real #1052
Palo Alto, CA 94306
(415) 941-0376
```

### Submit a tax exemption certificate

1. [Submit a Docker Support ticket](https://hub.docker.com/support/contact?topic=Billing&subtopic=Tax%20information)
   to start the tax certificate registration process.
1. Enter **Tax certificate** as the support ticket **Subject**.
1. In the **Details** field, enter **Submitting a tax certificate**.
1. Follow the instructions that appear for submitting a tax certificate.
1. Complete all required fields on the support form.
1. In the file upload section, add the tax certificate by dragging and dropping
   the file, or selecting **Browse files**.
1. Select **Submit**.

Docker Support contacts you if additional information is required. Docker sends
an email confirmation after applying the tax exemption status to your account.

## Add a VAT number or tax ID

When you select a VAT-applicable country during checkout, a tax ID field
appears. Customers in VAT countries enter their tax ID or VAT number
during checkout without opening a support ticket.

Your VAT number must include your country prefix. For example, enter
`DE123456789` for a German VAT number.

> [!NOTE]
>
> The tax ID field appears during checkout only when you select
> **I'm purchasing as a business**. It doesn't appear when you edit an
> existing payment method or billing details in billing settings.

Add a VAT number or tax ID when you
[set up a new plan](plans.md#set-up-a-new-plan).


---

# Plans

*Sección: Subscription Billing*

> [!TIP]
> Interested in pricing details? Check out the
> <a href="https://www.docker.com/pricing/" id="dkr_docs_index_pricing" class="link" rel="noopener">pricing page</a> to compare plans.

Docker plans attach to a personal account, an organization, or a specific
product. Personal plans (Docker Personal and Docker Pro) upgrade an individual
account. Organization plans (Docker Team and Docker Business) upgrade an
organization. Product add-ons add usage or features without changing that
account's Docker plan type: Gordon increases usage on a personal account, and
DHI, AI Governance, and DVP add product features on an organization.

Topping up extends a plan's entitlements, such as seats, licenses, or
minutes, without changing the plan type. For the units you can top up, see
[Top up your plan](../index.md#top-up-your-plan).

Each plan page covers usage entitlements, billing cycle, and management
options. To add or upgrade a plan, see
[Manage plans](../manage/plans.md).

## Product catalog

{{< grid >}}


---

# AI Governance plan

*Sección: Subscription Billing*

[AI Governance](../../ai/sandboxes/governance/index.md) lets organization owners enforce policies for members across supported Docker AI products, like [Docker Sandbox](../../ai/sandboxes/index.md). When you add an AI Governance plan, you work with your Docker sales representative to determine the number of licenses needed, which are applied to your account.

> [!TIP]
> To subscribe to AI Governance, <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_plans_aigov" class="link" rel="noopener">contact sales</a>.

## Usage

AI Governance lets organization owners enforce [organization policies](../../ai/sandboxes/governance/access-controls/organization.md) for license-holding members. Organization policies override a license-holding member's local policies.

You can [assign AI Governance licenses](../../accounts/organization/manage/manage-licenses.md) to any organization member, even if they don't occupy a Docker Team or Docker Business seat. For best practice, review available licenses as you add new members since members without an AI Governance license can still use Docker AI products.

## Billing cycle

AI Governance plan pricing is based on the number of licenses purchased. To add or remove licenses, contact your Docker sales representative.


---

# DHI plans

*Sección: Subscription Billing*

[Docker Hardened Images (DHI)](../../dhi/index.md) are secure, minimal, production-ready container images maintained by Docker.

- DHI Community is free and available to every developer.
- DHI Select is a paid plan for organizations that need compliance-ready images and SLA-backed patching. You can self-serve it in the billing portal.
- DHI Enterprise is for organizations with advanced security and customization requirements. To subscribe, <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_plans_dhi_enterprise" class="link" rel="noopener">contact sales</a>.

For a full plan comparison, see the [Docker pricing page](https://www.docker.com/pricing/).

## Usage

DHI Community gives you access to hardened base images from a public registry at no cost or additional setup. Any organization can pull hardened base images directly from `dhi.io`.

When you upgrade from DHI Community to DHI Select, you purchase a set number of repositories that are mirrored into your organization's namespace. Entitlements are scoped to the organization account that you assign them to during checkout. All organization members can then pull from those mirrored repositories.

DHI Enterprise extends DHI Select with unlimited customizations, optional full catalog access, the Hardened System Packages repository, and an Extended Lifecycle Support add-on.

For details on setting up and managing repositories, see [Get started with DHI Select and Enterprise](../../dhi/how-to/select-enterprise.md).

## Billing cycle

DHI Select is an annual plan billed per repository from the date your plan starts. Repositories added mid-cycle are prorated for the remainder of the billing period. You can add more repositories to your DHI Select plan by going to **Active plans** in the billing portal. For steps, see [Manage plans](../manage/plans.md#upgrade-plans).

## Disable auto-renewal

If you want to revert your plan to DHI Community, you must disable auto-renewal. Disabling auto-renewal is deferred to the end of the current billing cycle and your repository access remains active until then. To disable auto-renewal:

1. Sign in to [Docker Home](https://app.docker.com/) and go to **Billing**.
1. From **Active plans**, select **Manage** next to **Hardened Images**.
1. Select **Disable auto-renewal**.

## Remove repositories

You may also remove repositories from your plan. Repository removals are deferred to the end of the current billing cycle. You can remove repositories at any time, but you cannot stop a plan mid-cycle to receive a partial refund. Repository access remains active until the cycle ends.

To remove repositories:

1. Sign in to [Docker Home](https://app.docker.com/) and go to **Billing**.
1. From **Active plans**, select **Manage** next to **Hardened Images**.
    - Select **Remove repositories** to adjust your repository count.
    - To keep your current repository count after renewal, select **Cancel scheduled change**. 
    - Cancellations and repository removals take effect at the end of the current annual billing cycle.

If you're subscribed to DHI Enterprise, reach out to your sales representative to change your DHI plan.


---

# Docker Agentic Platform plans

*Sección: Subscription Billing*

> [!TIP]
> Docker Agentic Platform signups receive a one-time promotional
> credit toward cloud compute usage. To review your balance, see
> [Credits](../manage/index.md#credits).

[Docker Agentic Platform](https://agentic-platform.docker.com/) is a
pay-as-you-go plan for running agent and tool workloads in isolated
sandboxes with Docker-managed cloud infrastructure. You pay for the usage you accrue without a recurring
subscription fee.

## Usage

> [!NOTE]
> Docker Agentic Platform is available only on Docker Personal and
> Docker Pro accounts.

Docker Agentic Platform requires bringing your own API keys for inference. Your inference provider
handles those costs.

After you subscribe, your invoice reflects metered, pay-as-you-go
compute usage. Docker meters compute usage in seconds, based on sandbox
runtime and the vCPU plus memory configuration you choose at setup.
Different sandbox configurations can produce different costs.

You can track usage and pricing from the
[Usage & billing](https://agentic-platform.docker.com/usage) page in Agentic Platform.

To track usage for Docker Agentic Platform from Docker Home:

1. Sign in to [Docker Home](https://app.docker.com/), then choose your
   account.
1. Go to **Billing** to view the Overview page, then go to **Active
   plans**.
1. Select **Manage** next to **Docker Agentic Platform**.
1. View the estimated totals and usage for the current pay period.

## Billing cycle

Docker Agentic Platform is billed monthly on the day you subscribe.
Your invoice reflects compute usage accrued during the previous period.
For example:

- If you subscribed on September 10, you are billed on October 10.
- Your invoice from October 10 reflects accrued usage from September 10
  through October 9.
- Your invoice can take up to 24 hours after your billing date to
  appear.

## Cancel a plan

Canceling Docker Agentic Platform disables subscription renewal at the
start of the next plan period. Docker bills you for usage at the end of
the plan period.

1. Sign in to [Docker Home](https://app.docker.com/) and go to
   **Billing**.
1. From **Active plans**, select **Manage** next to
   **Docker Agentic Platform**.
1. Select **Cancel subscription**.
1. Review your usage, then select **Cancel subscription** to confirm.

## Next steps

- To add or cancel a plan, see
  [Manage plans](../manage/plans.md)
- To track usage across plans, see
  [Usage](../manage/index.md#usage)


---

# Docker Verified Publisher plans

*Sección: Subscription Billing*

[Docker Verified Publisher (DVP)](../../docker-hub/repos/manage/trusted-content/dvp-program.md)
is a program for commercial publishers who distribute content on Docker
Hub. DVP Starter and DVP Growth are paid organization plans that add
publisher analytics and reporting to verified publisher status.

- DVP Starter includes a verified publisher badge, prioritized search
  ranking, [Docker Scout](../../scout/index.md) vulnerability
  scanning, and weekly and monthly summary reports.
- DVP Growth includes everything in DVP Starter, plus trends,
  domain-level reports, and benchmark reports, with 25 consuming
  domains included.

For a plan comparison, see the
[DVP landing page](https://hub.docker.com/publisher-program).

> [!TIP]
> DVP plans require an approved application before you can subscribe.
> See [Apply for DVP Starter or Growth](#apply-for-dvp-starter-or-growth).

## Usage

Organizations can hold a DVP plan and DVP entitlements apply per organization
namespace. If you operate multiple namespaces, each one needs its own DVP
application. If you only have a Docker Personal or Docker Pro account, you can
create an organization when you apply.

Consuming domains are unique company domains that pull your images.
On DVP Growth, you can add more consuming domains in increments of
25 from the billing portal. For steps, see
[Add consuming domains](#add-consuming-domains).

For details on the reports available to verified publishers, see
[Insights and analytics](../../docker-hub/repos/manage/trusted-content/insights-analytics.md).

## Apply for DVP Starter or Growth

To add DVP Starter or DVP Growth, you must apply for a DVP plan. After Docker
approves your application, complete checkout to subscribe.

1. Go to the [DVP landing page](https://hub.docker.com/publisher-program).
   The page contains information about DVP Starter and DVP Growth.
1. Select **Apply for DVP**. Sign in if prompted.
1. Select an existing organization namespace, or create a new one if
   needed.
1. Fill in the content you want to publish and select DVP Starter or
   DVP Growth.
1. Submit your application for review with **Submit application**.
1. After approval, Docker emails you a checkout link. Open the link,
   then select DVP Starter or DVP Growth.
1. Verify your billing details, continue to payment, and complete
   checkout.

> [!IMPORTANT]
> Docker emails a checkout link after it approves your application.
> You're charged when you complete payment.

## Add consuming domains

On a DVP Growth plan, you can add consuming domains from the billing
portal:

1. Sign in to [Docker Home](https://app.docker.com/) and go to
   **Billing**.
1. From **Active plans**, select **Manage** next to **Docker Verified
   Publisher**.
1. Select **Add consuming domains** under **Consuming Domains**.
1. Select the number of consuming domains you want to add to your
   subscription.
1. Verify your billing details, continue to payment, and complete
   checkout.

## Billing cycle

DVP Starter and DVP Growth are billed annually. You can upgrade from
DVP Starter to DVP Growth without a new application. Upgrades take
effect immediately.

On DVP Growth, consuming domain add-ons are prorated from the purchase
date through the rest of your billing period, and they expire at the
end of your annual subscription. You can reduce your add-on count at
any time. Removals take effect at the end of the current billing cycle.

> [!IMPORTANT]
> No mid-cycle refunds are issued when you reduce consuming domain
> add-ons or end a DVP plan.

## Disable auto-renewal

To end a DVP plan, disable automatic renewal. Your plan stays active
until the end of the billing period and then expires. To disable
auto-renewal:

1. Sign in to [Docker Home](https://app.docker.com/) and go to
   **Billing**.
1. From **Active plans**, select **Manage** next to **Docker Verified
   Publisher**.
1. Select **Disable auto-renewal**.
1. Optional. To remove consuming domains, select **Remove consuming
   domains**, then choose the number to remove.


---

# Docker plans

*Sección: Subscription Billing*

Docker plans refer to plans that upgrade your account type from the basic free plan to a paid plan. Paid Docker plans come with higher usage limits, commercial
licensing, and expanded feature sets.

- Docker Personal is free for individual developers. Docker Pro adds unlimited private repositories, Docker Build Cloud, and commercial Docker Desktop use.
- Docker Team and Docker Business are plans for organizations, with Team adding audit logs and role-based access control, and Business adding SSO, SCIM, hardened Docker Desktop, and image access management.

To upgrade to Docker Pro, go to the
<a href="https://www.docker.com/pricing/" id="dkr_docs_pricing_docker_pro" class="link" rel="noopener">Docker pricing page</a>
and select **Buy now**.
To upgrade to Docker Team or Docker Business, see [Manage plans](../manage.md).

## Usage

Docker Personal and Docker Pro are Docker plans for individual account types while Docker Team and Docker Business are Docker plans for organization account types. For a full feature and pricing breakdown, see the
<a href="https://www.docker.com/pricing/" id="dkr_docs_index_pricing_docker_plans" class="link" rel="noopener">Docker pricing page</a>. 

> [!TIP]
> If you're upgrading from a Personal plan to a Team plan
> and want to keep your username,
> [convert your user account into an organization](../../accounts/organization/setup/convert-account.md).

## Billing cycle

Docker individual and organization plans are billed at a flat rate per user per month, with monthly or
annual billing options.
Upgrading your plan immediately extends access to all features
and entitlements.

### Organization seats

For Docker Team and Docker Business, you can purchase more seats for new members to extend access to your paid Docker plan. To add or remove seats from your Docker plan:

1. Sign in to [Docker Home](https://app.docker.com/), then choose your organization account.
1. Go to **Billing** to view the Overview page, then go to **Active plans**.
1. From the Docker Team or Docker Business tile, select the action menu.
   - Select **Add seats** or **Remove seats** from the drop-down menu.
   - When you add or remove seats, review your current seats against your new total seats.
   - When you remove seats, you must remove members from your organization.
1. Verify your billing details, continue to payment, and complete checkout.

To learn how to manage seats from Docker Home, see
[Manage seats](../../accounts/organization/manage/manage-seats.md).

### Docker Offload licenses

[Docker Offload](../../offload/index.md) licenses are available for Docker Team and Docker Business plans. Once assigned to your account, organization owners can [manage license assignments](../../accounts/organization/manage/manage-licenses.md) in Docker Home.

To add Docker Offload licenses, you must <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_plans_docker_offload" class="link" rel="noopener">contact sales</a>.

### Docker Build Cloud minutes

Each plan includes a base allocation of [Docker Build Cloud](../../build-cloud/index.md) build minutes per
month. Base minutes reset on an annual or monthly cadence, and don't accumulate. Additional purchased
minutes expire at the end of your billing period.

To purchase additional minutes:

1. From [Docker Home](https://app.docker.com/), choose your organization.
1. Select Build Cloud, then Build minutes.
1. From the **Minute breakdown** table, select **Add minutes**.
1. Choose your additional minute amount.
1. Verify your billing details, continue to payment, and complete checkout.

Your additional minutes appear on the Build minutes page immediately.

### Testcontainers Cloud minutes

Each plan includes a base allocation of Testcontainers Cloud runtime minutes
per month. Base minutes reset monthly and don't accumulate.

You can add Testcontainers Cloud runtime minutes in two ways:

- <a href="https://www.docker.com/pricing/contact-sales/" id="dkr_docs_cs_plans_docker_testcontainers" class="link" rel="noopener">Contact sales</a> to
  pre-purchase runtime minutes at $3 per 100 minutes. Pre-purchased minutes
  expire at the end of your billing period.
- Use on-demand runtime minutes at $4 per 100 minutes, billed at the end of
  each monthly cycle.

## Cancel a Docker plan

> [!NOTE]
> If you have a sales-assisted Docker Business plan,
> you must contact your account manager to cancel.

You can cancel at any time before your renewal date, but you can't pause or delay a plan. If an invoice isn't paid by the due date, there's a 15-day grace period starting from the due date. While the unused portion is not refundable, you still retain access to paid features until the end of the current billing cycle. 

> [!NOTE]
>
> Billing periods are calculated in UTC (Coordinated Universal Time). If you're in a timezone behind UTC, for example US Pacific Time is UTC−7/−8, canceling or making changes late in your local day may fall into the next billing day in UTC.

Canceling your paid plans may have implications for collaborators or organization members:

- Docker Pro private repository collaborators are removed and additional private repositories are locked.
- Docker Team or Docker Business members provisioned through SCIM without a password will be locked out. Remove SSO connections and verified domains if your organization uses single sign-on.
- For paid individual and organization plans, you must convert private repositories to fit your new plan limits.

Canceling a paid plan returns your account to Docker Personal or a basic organization account.
To cancel your plan:

1. Sign in to [Docker Home](https://app.docker.com/) and go to **Billing**.
2. From **Active plans**, select the action menu next to your Docker plan.
3. Select **Cancel plan** and complete the feedback survey.


---

# Gordon plans

*Sección: Subscription Billing*

[Gordon](../../ai/gordon/index.md) is an AI assistant for Docker workflows. For pricing details, see the [Gordon product page](https://www.docker.com/products/gordon/).

- Gordon Base is included at no cost with Docker plans. It covers everyday Docker workflow questions with a baseline monthly usage allowance.
- Gordon Plus is for developers who use Gordon regularly. It increases your monthly usage allowance above Base.
- Gordon Max is for power users who rely on Gordon throughout their workflow. It offers a significantly higher usage allowance than Plus.
- Gordon Ultra is for developers with the highest usage needs. It provides the maximum monthly allowance available on a self-serve plan.

To upgrade to a Gordon paid plan, see [Manage plans](../manage/plans.md).

## Usage

Gordon usage is measured in questions. When you upgrade from Gordon Base to a paid plan, your usage multiplies the Base allowance. Usage is capped across three time windows: 4-hour, daily, and monthly. For full limit details, see [Gordon usage limits](../../ai/gordon/usage-limits.md).

> [!IMPORTANT]
> Gordon plans apply to personal Docker accounts only. If you purchase a Gordon
> plan while signed in with an organization account, the plan applies
> to your personal account automatically.

## Billing cycle

Gordon plans are billed monthly at the first of the month. If you purchase after the first of the month, your invoice reflects prorated charges for the remaining days in the cycle. Subscribing to a Gordon plan charges you at the time of purchase. When you upgrade your Gordon plan, usage limits are immediately effective after payment. 

## Downgrade or disable auto-renewal

When you downgrade a Gordon plan, the change takes effect on the 1st of the following month. Disabling auto-renewal for a Gordon plan returns your paid Gordon plan to Gordon Base in the same pattern. For example, if you downgrade from Gordon Ultra to Gordon Plus on April 15:

- From April 15 through April 30, you retain Ultra access and usage limits.
- On May 1, you are charged the Gordon Plus plan rate and Gordon Plus usage limits take effect.

To downgrade or disable auto-renewal:

1. Sign in to [Docker Home](https://app.docker.com/) and go to **Billing**.
1. From **Active plans**, select **Manage** next to your Gordon plan.
1. Select **Downgrade plan** to switch to a lower tier, or **Disable auto renewal** to end your plan after the current billing cycle.

> [!IMPORTANT]
> Docker does not issue refunds or credits
> for remaining days in the current cycle.


---

# Get support for Docker products

*Sección: Support*

Docker offers multiple support channels depending on your subscription level and needs.

## Paid subscription support

All Docker Pro, Team, and Business subscribers receive email support for Docker products.

### Support response times

- Docker Pro: 3 business day response
- Docker Team: 2 business day response, 24×5 availability
- Docker Business: 1 business day response, 24×5 availability

Docker Verified Publisher (DVP) organizations follow the response times for their
Docker Pro, Team, or Business subscription. Without one of those subscriptions,
the following response times apply:

- DVP Starter: 3 business day response
- DVP Growth: 2 business day response, 24×5 availability

> [!TIP]
>
> Premium Support with faster response times and 24×7 availability is available as an add-on for [Docker Business subscribers](https://www.docker.com/pricing?ref=Docs&refAction=DocsSupport).

### Support severity levels

| Level    | Description                                                                                                                                                                |
| :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Critical | Widespread or company-wide service outage affecting many customers or all users within a single organization. Business operations are halted with no workaround available. |
| High     | Team or department-level impact preventing significant users from accessing core functionality. Severe business impact with no workaround exists.                          |
| Medium   | Individual user or small group impact causing partial loss of functionality. Business operations continue, often with workarounds available but reduced productivity.      |

### Request support

> [!TIP]
>
> Before reaching out for support, review the troubleshooting documentation for your product.

If you have a paid Docker subscription, [contact the Support team](https://hub.docker.com/support/contact/).

## Community support

All Docker users can seek support through community resources, where Docker or the community respond on a best effort basis:

- [Docker Community Forums](https://forums.docker.com/)
- [Docker Community Slack](http://dockr.ly/comm-slack)

## Docker Desktop support

Docker Desktop support is available with a paid subscription.

### Scope of support

{{< tabs >}}
{{< tab name="Covered">}}

Docker Desktop support includes:

- Account management and billing
- Configuration and installation issues
- Desktop updates
- Sign-in issues
- Push or pull issues, including rate limiting
- Application crashes or unexpected behavior
- Automated builds
- Basic product 'how to' questions

**Windows-specific:**

- Turning on virtualization in BIOS
- Turning on Windows features
- Running inside [certain VM or VDI environments](../desktop/setup/vm-vdi.md) (Docker Business only)

{{< /tab >}}
{{< tab name="Not covered">}}

Docker Desktop support excludes:

- Unsupported operating systems, including beta/preview versions
- Running containers of a different architecture using emulation
- Docker Engine, Docker CLI, or other bundled Linux components
- Kubernetes
- Features labeled as experimental
- System/Server administration activities
- Desktop as a production runtime
- Scale deployment/multi-machine installation
- Routine product maintenance (data backup, disk space, log rotation)
- Third-party applications not provided by Docker
- Altered or modified Docker software
- Hardware malfunction, abuse, or improper use
- Versions older than the latest release (except Docker Business)
- Training, customization, and integration
- Running multiple instances on a single machine

> [!NOTE]
>
> Support for [running Docker Desktop in a VM or VDI environment](../desktop/setup/vm-vdi.md) is only available to Docker Business customers.

{{< /tab >}}
{{< /tabs >}}

### Supported versions

- Docker Business: Versions up to six months older than the latest version (fixes applied to latest version only)
- Docker Pro and Team: Latest version only

### Number of machines

- Docker Pro: One machine
- Docker Team: Number of machines equal to subscription seats
- Docker Business: Unlimited machines

### Supported operating systems

- [Mac system requirements](../desktop/setup/install/mac-install.md#system-requirements)
- [Windows system requirements](../desktop/setup/install/windows-install.md#system-requirements)
- [Linux system requirements](../desktop/setup/install/linux/index.md#system-requirements)

### Community resources

- [Docker Desktop issue tracker](https://github.com/docker/desktop-feedback)

### Diagnostic data and privacy

When uploading diagnostics, the bundle may contain personal data such as usernames and IP addresses. Diagnostics bundles are only accessible to Docker, Inc. employees directly involved in diagnosing issues.

By default, Docker, Inc. deletes uploaded diagnostics bundles after 30 days. You may request removal of a diagnostics bundle by specifying the diagnostics ID or your GitHub ID. Docker, Inc. only uses the data to investigate specific user issues but may derive high-level (non-personal) metrics.

For more information, see [Docker Data Processing Agreement](https://www.docker.com/legal/data-processing-agreement).


---

# Manage unassociated machines

*Sección: Unassociated Machines*

{{< restricted title="About unassociated machines" >}}
Unassociated machines is a private feature that may not be available to all
accounts.
{{< /restricted >}}

Docker administrators can identify, view, and manage Docker Desktop machines
that are likely associated with their organization but aren't currently linked
to user accounts. This self-service capability helps you understand Docker
Desktop usage across your organization and streamline user onboarding without
IT involvement.

## Prerequisites

- Docker Business or Team subscription
- Organization owner access to your Docker organization

## About unassociated machines

Unassociated machines are Docker Desktop instances that Docker has identified
as likely belonging to your organization based on usage patterns, but the users
are not signed in to Docker Desktop with an account that is part of your
organization.

## How Docker identifies unassociated machines

Docker uses telemetry data to identify which machines likely belong to your
organization:

- Domain matching: Users signed in with email domains associated with your
  organization
- Registry patterns: Analysis of container registry access patterns that
  indicate organizational usage

## View unassociated machines

To see detailed information about unassociated machines:

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.

The machine list displays:

- Machine ID (Docker-generated identifier)
- The registry address used to predict whether a user is part of your
  organization
- User email (only displays if the user is signed into Docker Desktop while
  using it)
- Docker Desktop version
- Operating system (OS)
- Last activity date
- Sign-in enforced status

You can:

- Export the list as CSV
- Take actions on individual or multiple machines

## Enable sign-in enforcement for unassociated machines

> [!NOTE]
>
> Sign-in enforcement for unassociated machines is different from
> the [organization-level sign-in enforcement](/enterprise/security/enforce-sign-in/)
> available through `registry.json` and configuration profiles. This sign-in
> enforcement only requires users to sign in so admins can identify who is
> using the machine, meaning users can sign in with any email address. For more
> stringent security controls that limit sign-ins to users who are already part
> of your organization, see [Enforce sign-in](/enterprise/security/enforce-sign-in/).

Sign-in enforcement helps you identify who is using unassociated machines in
your organization. When you enable enforcement, users on these machines will
be required to sign in to Docker Desktop. Once they sign in, their email
addresses will appear in the Unassociated list, allowing you to then add them
to your organization.

You can enable sign-in enforcement using two methods:

- For all unassociated machines in your organization
- For individual unassociated machines

> [!IMPORTANT]
>
> Sign-in enforcement only takes effect after Docker Desktop is restarted.
> Users can continue using Docker Desktop until their next restart.

### Enable sign-in enforcement for all unassociated machines

To enable sign-in enforcement for all unassociated machines:

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.
1. Turn on the **Enforce sign-in** toggle.
1. In the pop-up modal, select **Require sign-in** to confirm.

The **Sign-in required** status will update for all unassociated machines to
**Yes**.

> [!NOTE]
>
> When you enable sign-in enforcement for all unassociated machines, any new
> machines detected in the future will automatically have sign-in enforcement
> enabled. Sign-in enforcement requires Docker Desktop version 4.41 or later.
> Users with older versions will not be prompted to sign in and can continue
> using Docker Desktop normally until they update. Their status shows
> as **Pending** until they update to version 4.41 or later.

### Enable sign-in enforcement for individual unassociated machines

To enable sign-in enforcement for individual unassociated machines:

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.
1. Locate the machine you want to enable sign-in enforcement for.
1. Select the **Actions** menu and choose **Turn on sign-in enforcement**.
1. In the pop-up modal, select **Require sign-in** to confirm.

The **Sign-in required** status will update for the individual machine to
**Yes**.

> [!NOTE]
>
> Sign-in enforcement requires Docker Desktop version 4.41 or later. Users
> with older versions will not be prompted to sign in and can continue using
> Docker Desktop normally until they update. Their status shows as **Pending**
> until they update to version 4.41 or later.

### What happens when users sign in

After you enable sign-in enforcement:

1. Users must restart Docker Desktop. Enforcement only takes effect after
   restart.
1. When users open Docker Desktop, they see a sign-in prompt. They must sign
   in to continue using Docker Desktop.
1. User email addresses appear in the **Unassociated** list.
1. You can add users to your organization.

Users can continue using Docker Desktop immediately after signing in, even
before being added to your organization.

## Add unassociated machines to your organization

When users in your organization use Docker without signing in, their machines
appear in the **Unassociated** list. You can add these users to your
organization in two ways:

- Automatic addition:
  - Auto-provisioning: If you have verified domains with auto-provisioning
    enabled, users who sign in with a matching email domain will automatically
    be added to your organization. For more information on verifying domains and
    auto-provisioning, see [Domain management](/security/provisioning/domain-management).
  - SSO user provisioning: If you have SSO configured with
    [Just-in-Time provisioning](../security/provisioning/just-in-time.md),
    users who sign in through your SSO connection will automatically be added
    to your organization.
- Manual addition: If you don't have auto-provisioning or SSO set up, or if a
  user's email domain doesn't match your configured domains, their email will
  appear in the **Unassociated** list where you can choose to add them directly.

> [!NOTE]
>
> If you add users and do not have enough seats in your organization, a
> pop-up will appear prompting you to **Get more seats**.

### Add individual users

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.
1. Locate the machine you want to add to your organization.
1. Select the **Actions** menu and choose **Add to organization**.
1. In the pop-up modal, select **Add user**.

### Bulk add users

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.
1. Use the **checkboxes** to select the machines you want to add to your
   organizations.
1. Select the **Add to organization** button.
1. In the pop-up modal, select **Add users** to confirm.

## Disable sign-in enforcement

### Disable for all unassociated machines

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.
1. Turn off the **Enforce sign-in** toggle.
1. In the pop-up modal, select **Turn off sign-in requirement** to confirm.

The **Sign-in required** status will update for all unassociated machines to
**No**.

### Disable for specific unassociated machines

1. Sign in to [Docker Home](https://app.docker.com) and select your organization.
1. Select **Docker Desktop**, then **Unassociated**.
1. Locate the machine you want to disable sign-in enforcement for.
1. Select the **Actions** menu and choose **Turn off sign-in enforcement**.
1. In the pop-up modal, select **Turn off sign-in requirement** to confirm.

The **Sign-in required** status will update for the individual machine to
**No**.


---

# Home

*Sección: Docker*

Docker Documentation helps you learn Docker, install Docker products, and find
reference material for everyday development and operations tasks.

## Browse docs by area

- [Get started](/get-started/): Run an application, sandbox an AI agent, or
  roll out Docker.
- [Guides](/guides/): Follow task-focused walkthroughs for common workflows.
- [Manuals](/manuals/): Install, configure, and use Docker products.
- [Reference](/reference/): Browse CLI, API, and file format documentation.

{{< whats-new >}}

## Common questions

- [How do I get started with Docker?](/get-started/)
- [How do I containerize an application?](/get-started/tutorials/run-an-app/)
- [Can I run my AI agent in a sandbox?](/get-started/tutorials/run-an-agent/)
- [What are Docker Hardened Images?](/dhi/)
- [Why should I use Docker Compose?](/compose/)


---

# Automated traffic detection

*Sección: Docker*

This page is used to identify automated traffic.


---

# Manuals

*Sección: Docker*

This section contains user guides on how to install, set up, configure, and use
Docker products.

## AI and agents

All the Docker AI tools in one easy-to-access location.

{{< grid items=ai-and-agents >}}

## Application development

End-to-end developer solutions for innovative teams.

{{< grid items=application-development >}}

## Supply chain security

Security guardrails and image analysis for your software supply chain.

{{< grid items=supply-chain-security >}}

## Accounts and admin

Manage Docker accounts, administration, subscriptions, billing, and security.

{{< grid items=platform >}}

## Enterprise

Targeted at IT administrators with help on deploying Docker Desktop at scale with configuration guidance on security related features.

{{< grid items=enterprise >}}


---

# Docker AI overview

*Sección: Docker*

Docker provides tools for working with AI across your development workflow.
Each tool serves a different purpose.

## Which tool do I need?

| I want to...                                                    | Use                                                      | CLI command      |
| --------------------------------------------------------------- | -------------------------------------------------------- | ---------------- |
| Get AI help with Docker tasks (containers, images, Dockerfiles) | [Gordon](./ai/gordon/)                                   | `docker ai`      |
| Run AI models locally with an OpenAI-compatible API             | [Model Runner](./ai/model-runner/)                       | `docker model`   |
| Connect AI tools to external services via MCP                   | [MCP Catalog and Toolkit](./ai/mcp-catalog-and-toolkit/) | `docker mcp`     |
| Build and orchestrate custom multi-agent teams                  | [Docker Agent](./ai/docker-agent/)                       | `docker agent`   |
| Run coding agents in isolated environments                      | [Docker Sandboxes](./ai/sandboxes/)                      | `sbx`            |

## How these tools relate

**Gordon** is Docker's built-in AI assistant. It helps with Docker-specific
tasks like debugging containers, writing Dockerfiles, and managing images. You
interact with it through Docker Desktop or the `docker ai` command.

**Docker Agent** is an open-source framework for defining teams of AI agents
in YAML. You configure agents with specific roles, models, and tools, then
run them from your terminal. Docker Agent is a general-purpose agent runtime,
not specific to Docker tasks.

**Docker Sandboxes** provides isolated microVM environments for running coding
agents. It supports multiple agents including Claude Code, Codex, Copilot,
Devin, Gemini, and Docker Agent. Sandboxes is the isolation layer — the agents
themselves are separate tools.

**Model Runner** lets you run LLMs locally. Other tools like Docker Agent can
use Model Runner as a model provider.

**MCP Catalog and Toolkit** manages connections between AI tools and external
services using the Model Context Protocol. Gordon, Docker Agent, and
third-party tools can all use MCP servers configured through the Toolkit.


---

# Release notes for Docker Home, the Admin Console, billing, security, and subscription features

*Sección: Docker*

This page provides details on new features, enhancements, known issues, and bug fixes across Docker Home, the Admin Console, billing, security, and subscription functionalities.

## 2026-02-13

### New

- Administrators can now control whether organization members can push content
  to their personal namespaces on Docker Hub with [namespace access
  control](enterprise/security/hardened-desktop/namespace-access.md).
- Administrators can now prevent creating public repositories within
  organization namespaces using the [Disable public
  repositories](docker-hub/settings.md#disable-creation-of-public-repos) setting.

## 2026-01-27

### New

- Administrators can now use an allow list with [Image Access
  Management](enterprise/security/hardened-desktop/image-access-management.md)
  to approve specific repositories that bypass image access controls.

## 2025-01-30

### New

- Installing Docker Desktop via the PKG installer is now generally available.
- Enforcing sign-in via configuration profiles is now generally available.

## 2024-12-10

### New

- New Docker subscriptions are now available. For more information, see [Docker
  subscriptions and features](https://www.docker.com/pricing?ref=Docs&refAction=DocsPlatformReleaseNotes) and [Announcing
  Upgraded Docker Plans: Simpler, More Value, Better Development and
  Productivity](https://www.docker.com/blog/november-2024-updated-plans-announcement/).

## 2024-11-18

### New

- Administrators can now:
  - Enforce sign-in with [configuration profiles](enterprise/security/enforce-sign-in/methods.md#configuration-profiles-method-mac-only) (Early Access).
  - Enforce sign-in for more than one organization at a time (Early Access).
  - Deploy Docker Desktop for Mac in bulk with the [PKG installer](enterprise/enterprise-deployment/pkg-install-and-configure.md) (Early Access).
  - [Use Desktop Settings Management via the Docker Admin Console](enterprise/security/hardened-desktop/settings-management/configure-admin-console.md) (Early Access).

### Bug fixes and enhancements

- Enhance Container Isolation (ECI) has been improved to:
  - Permit admins to [turn off Docker socket mount restrictions](enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#allowing-all-containers-to-mount-the-docker-socket).
  - Support wildcard tags when using the [`allowedDerivedImages` setting](enterprise/security/hardened-desktop/enhanced-container-isolation/config.md#docker-socket-mount-permissions-for-derived-images).

## 2024-11-11

### New

- [Personal access tokens](/security/access-tokens/personal-access-tokens/) (PATs) now support expiration dates.

## 2024-10-15

### New

- Beta: You can now create [organization access tokens](/security/for-admins/access-tokens/) (OATs) to enhance security for organizations and streamline access management for organizations in the Docker Admin Console.

## 2024-08-29

### New

- Deploying Docker Desktop via the [MSI installer](enterprise/enterprise-deployment/msi-install-and-configure.md) is now generally available.
- Two new methods to [enforce sign-in](enterprise/security/enforce-sign-in/index.md) (Windows registry key and `.plist` file) are now generally available.

## 2024-08-24

### New

- Administrators can now view [organization Insights](accounts/organization/insights.md).

## 2024-07-17

### New

- You can now centrally access and manage Docker products in [Docker Home](https://app.docker.com).


---

# Docker's product release lifecycle

*Sección: Docker*

This page details Docker's product release lifecycle and how Docker defines each stage. It also provides information on the product retirement process. Features and products may progress through some or all of these phases. 

>[!NOTE]
>
>Our [Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement) governs your use of Docker and covers details of eligibility, content, use, payments and billing, and warranties. This document is not a contract and all use of Docker’s services are subject to Docker’s [Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement).

## Lifecycle stage

| Lifecycle stage  | Customer availability | Support availability | Limitations | Retirement |
| --- | --- | ---- | ---| ---|
|[Experimental](#experimental)| Limited availability | Community support |Software may have limitations, bugs and/or stability concerns | Can be discontinued without notice |
|[Beta](#beta) | All or those involved in a Beta Feedback Program | Community support | Software may have limitations, bugs and/or stability concerns | Can be discontinued without notice |
| [Early Access (EA)](#early-access-ea) | All or those involved in an Early Access Feedback Program | Full | Software may have limitations, bugs and/or stability concerns.  These limitations will be documented. | Follows the [retirement process](#retirement-process) |
| [General Availability (GA)](#general-availability-ga) | All | Full | Few or no limitations for supported use cases | Follows the [retirement process](#retirement-process) |

### Experimental

Experimental offerings are features that Docker is currently experimenting with. Customers who access experimental features have the opportunity to test, validate, and provide feedback on future functionality. This helps us focus our efforts on what provides the most value to our customers.

**Customer availability:** Availability of experimental features is limited. A portion of users may have access to none, one or many experimental features. 

**Support:** Support for experimental features is best effort via Community support channels and forums.

**Limitations:** Experimental features may have potentially significant limitations such as functional limitations, performance limitations, and API limitations. Features and programmatic interfaces may change at any time without notice.

**Retirement:** During the experimental period, Docker will determine whether to continue an offering through its lifecycle. We reserve the right to change the scope of or discontinue an Experimental product or feature at any point in time without notice, as outlined in our [Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement).

### Beta

Beta offerings are initial releases of potential future products or features. Customers who participate in our beta programs have the opportunity to test, validate, and provide feedback on future functionality. This helps us focus our efforts on what provides the most value to our customers.

**Customer availability:** Participation in beta releases is by invitation or via use of clearly identified beta features in product. Beta invitations may be public or private.

**Support:** Support for beta features is best effort via Community support channels and forums.

**Limitations:** Beta releases may have potentially significant limitations such as functional limitations, performance limitations, and API limitations. Features and programmatic interfaces may change at any time without notice.

**Retirement:** During the beta period, Docker will determine whether to continue an offering through its lifecycle. We reserve the right to change the scope of or discontinue a Beta product or feature at any point in time without notice, as outlined in our [Subscription Service Agreement](https://www.docker.com/legal/docker-subscription-service-agreement).

### Early Access (EA)

Early Access offerings are products or features that may have potential feature limitations and are enabled for specific user groups as part of an incremental roll-out strategy. They are ready to be released to the world, pending some fine tuning.

**Customer availability:** Early Access functionality can be rolled out to all customers or specific segments of users in addition to or in place of existing functionality.

**Support:** Early Access offerings are provided with the same level of support as General Availability features and products.

**Limitations:** Early Access releases may have potentially significant limitations such as functional limitations, performance limitations, and API limitations, though these limitations will be documented. Breaking changes to features and programmatic interfaces will follow the [retirement process](#retirement-process) outlined below.

**Retirement:** In the event we retire an Early Access product before General Availability, we will strive to follow the [retirement process](#retirement-process) outlined below.

### General Availability (GA)

General Availability offerings are fully functional products or features that are openly accessible to all Docker customers.

**Customer availability:** All Docker users have access to GA offerings according to their subscription levels.

**Limitations:** General Availability features and products will have few or no limitations for supported use cases.

**Support:** All GA offerings are fully supported, as described in our [support page](https://www.docker.com/support/).

**Retirement:** General Availability offerings follow the [retirement process](#retirement-process) outlined below.


## Retirement process

The decision to retire or deprecate features follows a rigorous process including understanding the demand, use, impact of feature retirement and, most importantly, customer feedback. Our goal is to invest resources in areas that will add the most value for the most customers

Docker is committed to being clear, transparent, and proactive when interacting with our customers, especially about changes to our platform. To that end, we will make best efforts to follow these guidelines when retiring functionality:

- **Advance notice:** For retirement of major features or products, we will attempt to notify customers at least 6 months in advance.
- **Viable alternatives:**  Docker will strive to provide viable alternatives to our customers when retiring functionality. These may be alternative offerings from Docker or recommended alternatives from 3rd party providers. Where possible and appropriate, Docker will automatically migrate customers to alternatives for retired functionality.
- **Continued support:** Docker commits to providing continued support for functionality until its retirement date.

We may need to accelerate the timeline for retirement of functionality in extenuating circumstances, such as essential changes necessary to protect the integrity of our platform or the security of our customers and others. In these cases, it is important that those changes occur as quickly as possible.

Similarly, integrated third party software or services may need to be retired due to the third-party decision to change or retire their solution. In these situations, the pace of retirement will be out of our control.

However, even under these circumstances, we will provide as much advance notice as possible.


---

# Deprecated and retired Docker products and features

*Sección: Docker*

This document provides an overview of Docker features, products, and
open-source projects that have been deprecated, retired, or transitioned.

> [!NOTE]
>
> This page does not cover deprecated and removed Docker Engine features.
> For a detailed list of deprecated Docker Engine features, refer to the
> [Docker Engine Deprecated Features documentation](/manuals/engine/deprecated.md).

## Products and features

Support for these deprecated or retired features is no longer provided by
Docker, Inc. The projects that have been transitioned to third parties continue
to receive updates from their new maintainers.

### Docker Machine

Docker Machine was a tool for provisioning and managing Docker hosts across
various platforms, including virtual machines and cloud providers. It is no
longer maintained, and users are encouraged to use [Docker Desktop](desktop/index.md)
or [Docker Engine](engine/index.md) directly on supported platforms.
Machine's approach to creating and configuring hosts has been superseded by
more modern workflows that integrate more closely with Docker Desktop.

### Docker Toolbox

Docker Toolbox was used on older systems where Docker Desktop could not run. It
bundled Docker Machine, Docker Engine, and Docker Compose into a single
installer. Toolbox is no longer maintained and is effectively replaced by
[Docker Desktop](desktop/index.md) on current systems. References to
Docker Toolbox occasionally appear in older documentation or community
tutorials, but it is not recommended for new installations.

### Docker Cloud integrations

Docker previously offered integrations for Amazon's Elastic Container Service
(ECS) and Azure Container Instances (ACI) to streamline container workflows.
These integrations have been deprecated, and users should now rely on native
cloud tools or third-party solutions to manage their workloads. The move toward
platform-specific or universal orchestration tools reduced the need for
specialized Docker Cloud integrations.

You can still view the relevant documentation for these integrations in the
[Compose CLI repository](https://github.com/docker-archive/compose-cli/tree/main/docs).

### Docker Enterprise Edition

Docker Enterprise Edition (EE) was Docker's commercial platform for deploying
and managing large-scale container environments. It was acquired by Mirantis in
2019, and users looking for enterprise-level functionality can now explore
Mirantis Kubernetes Engine or other products offered by Mirantis. Much of the
technology and features found in Docker EE have been absorbed into the Mirantis
product line.

> [!TIP]  
> For information about enterprise-level features offered by Docker today,
> see the [Docker Business subscription](https://www.docker.com/pricing?ref=Docs&refAction=DocsRetired).

### Docker Data Center and Docker Trusted Registry

Docker Data Center (DDC) was an umbrella term that encompassed Docker Universal
Control Plane (UCP) and Docker Trusted Registry (DTR). These components
provided a full-stack solution for managing containers, security, and registry
services in enterprise environments. They are now under the Mirantis portfolio
following the Docker Enterprise acquisition. Users still encountering
references to DDC, UCP, or DTR should refer to Mirantis's documentation for
guidance on modern equivalents.

### Dev Environments

Dev Environments was a feature introduced in Docker Desktop that allowed
developers to spin up development environments quickly. It was deprecated and removed from Docker Desktop version 4.42 and later. Similar workflows can be achieved through
Docker Compose or by creating custom configurations tailored to specific
project requirements.

### Docker Desktop sandboxes

Docker Desktop sandboxes let users run AI coding agents in isolated microVMs
through the `docker sandbox` command. The `docker sandbox` plugin was removed
in Docker Desktop 4.80.0. Use the standalone
[`sbx` CLI](ai/sandboxes/index.md) instead.

### Docker Scout features

The following Docker Scout features have been retired or deprecated. For
details, see the [Scout platform release notes](scout/release-notes/platform.md).

- Health scores and Scout Everywhere: graded Docker Hub images from A to F
  based on policy compliance, surfaced across Docker Hub. Retired July 1, 2026.
- Sysdig integration: detected images running in your cluster via the Sysdig API.
  Retired July 1, 2026.
- GitHub source code management integration: linked images to their source
  repository and automated base-image updates via PRs. Retired July 1, 2026.
  For base-image updates, use
  [GitHub Dependabot](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuring-dependabot-version-updates)
  with `package-ecosystem: "docker"`. For image-to-source linkage, build with
  `--provenance=mode=max`. This retirement doesn't affect the
  [`docker/scout-action`](https://github.com/docker/scout-action) GitHub Action
  for CI pipelines.
- Slack integration: sent vulnerability and policy compliance notifications to
  Slack channels. Retired July 30, 2026.
- Notifications: alerted users to newly disclosed CVEs in-product and by
  email. Retired September 1, 2026. To surface CVE and policy results without
  push notifications, integrate `docker scout cves` or `docker scout policy`
  into your CI pipeline.
- Native Amazon ECR integration: automatically analyzed images pushed to ECR
  registries using a CloudFormation stack. Retired September 1, 2026. Docker
  Scout still supports ECR through
  [`docker scout watch`](scout/integrations/registry.md).
- Native Azure Container Registry integration: automatically analyzed images
  pushed to ACR registries using an ARM template. Retired September 1, 2026.
  Docker Scout still supports ACR through
  [`docker scout watch`](scout/integrations/registry.md).
- Policies page in the Dashboard: the `docker scout policy`
  CLI continues to work. Retired September 1, 2026. See
  [Evaluate policies](scout/policy/local.md).
- SonarQube integration: surfaced SonarQube quality gate results as a Docker
  Scout policy. Retired September 1, 2026.

### GitHub Copilot extension

The Docker for GitHub Copilot extension integrated Docker capabilities with
GitHub Copilot Chat, helping developers containerize applications, generate
Docker assets, and analyze vulnerabilities through conversational prompts. The
extension was available in early access on the GitHub Marketplace. GitHub
[deprecated Copilot Extensions](https://github.blog/changelog/2025-09-24-deprecate-github-copilot-extensions-github-apps/)
which led to the retirement of the Docker for GitHub Copilot extension. If
you're looking for AI-assisted Docker workflows, explore the Docker MCP Toolkit
and MCP Catalog, or use Gordon in Docker Desktop and the Docker CLI.

### Enhanced Service Account add-ons

Enhanced Service Account add-ons provided tiered pull rate limits for automated
workflows and service accounts accessing Docker Hub.

Docker recommends transitioning to [Organization Access Tokens
(OATs)](security/access-tokens/organization-access-tokens.md), which provide secure,
programmatic access to Docker Hub with granular repository permissions, token
expiration, and better security auditing. OATs are included with Docker Team
and Business subscriptions and offer similar functionality without requiring
separate add-on purchases.

### Docker Hub Automated Builds

Docker Hub Automated Builds was a feature of Docker Hub that allowed building
Docker images from source code in an external repository and automatically pushing
the built image to your Docker repositories. This feature has been deprecated and
will be removed on April 1, 2027.

### Docker Content Trust (DCT)

Docker Content Trust (DCT) and the Notary v1 service at `notary.docker.io` are
being fully retired. If you've never set `DOCKER_CONTENT_TRUST=1` or used
`docker trust` commands, this change doesn't affect you. The service shuts down
completely on December 8, 2026, following brownout windows in July and August.
For the timeline, migration guidance, and modern alternatives such as
Sigstore/Cosign and Notation, see the [Docker Content Trust retirement and
migration blog post](https://www.docker.com/blog/docker-content-trust-retirement-and-migration-guidance/).


## Open source projects

Several open-source projects originally maintained by Docker have been
archived, discontinued, or transitioned to other maintainers or organizations.

### Registry (now CNCF Distribution)

The Docker Registry served as the open-source implementation of a container
image registry. It was donated to the Cloud Native Computing Foundation (CNCF)
in 2019 and is maintained under the name "Distribution." It remains a
cornerstone for managing and distributing container images.

[CNCF Distribution](https://github.com/distribution/distribution)

### Docker Compose v1 (replaced by Compose v2)

Docker Compose v1 (`docker-compose`), a Python-based tool for defining
multi-container applications, has been superseded by Compose v2 (`docker
compose`), which is written in Go and integrates with the Docker CLI. Compose
v1 is no longer maintained, and users should migrate to Compose v2.

[Compose v2 Documentation](compose/index.md)

### Docker SBOM CLI plugin

The Docker SBOM CLI plugin provided the `docker sbom` command for generating
and viewing software bill of materials (SBOMs) for container images. The plugin
is discontinued. Use [`docker scout sbom`](/reference/cli/docker/scout/sbom/)
for SBOM generation and inspection.

[See Docker SBOM CLI plugin release notes for migration guidance](https://github.com/docker/sbom-cli-plugin/releases/tag/v0.7.0)

### InfraKit

InfraKit was an open-source toolkit designed to manage declarative
infrastructure and automate container deployments. It has been archived, and
users are encouraged to explore tools such as Terraform for infrastructure
provisioning and orchestration.

[InfraKit GitHub Repository](https://github.com/docker/infrakit)

### Docker Notary (now CNCF Notary)

Docker Notary was a system for signing and verifying the authenticity of
container content. It was donated to the CNCF in 2017 and continues to be
developed as "Notary." Users seeking secure content verification should consult
the CNCF Notary project.

[CNCF Notary](https://github.com/notaryproject/notary)

### SwarmKit

SwarmKit powers Docker Swarm mode by providing orchestration for container
deployments. While Swarm mode remains functional, development has slowed in
favor of Kubernetes-based solutions. Individuals evaluating container
orchestration options should investigate whether SwarmKit meets modern workload
requirements.

[SwarmKit GitHub Repository](https://github.com/docker/swarmkit)


---

# Testcontainers Cloud

*Sección: Docker*




---

# Testcontainers

*Sección: Docker*

Testcontainers is a set of open source libraries that provides easy and lightweight APIs for bootstrapping local development and test dependencies with real services wrapped in Docker containers.
Using Testcontainers, you can write tests that depend on the same services you use in production without mocks or in-memory services.

{{< grid items=intro >}}

## Quickstart

### Supported languages

Testcontainers provide support for the most popular languages, and Docker sponsors the development of the following Testcontainers implementations:

- [Go](https://golang.testcontainers.org/quickstart/)
- [Java](https://java.testcontainers.org/quickstart/junit_5_quickstart/)

The rest are community-driven and maintained by independent contributors.

### Prerequisites

Testcontainers requires a Docker-API compatible container runtime.
During development, Testcontainers is actively tested against recent versions of Docker on Linux, as well as against Docker Desktop on Mac and Windows.
These Docker environments are automatically detected and used by Testcontainers without any additional configuration being necessary.

It is possible to configure Testcontainers to work for other Docker setups, such as a remote Docker host or Docker alternatives.
However, these are not actively tested in the main development workflow, so not all Testcontainers features might be available
and additional manual configuration might be necessary.

If you have further questions about configuration details for your setup or whether it supports running Testcontainers-based tests,
contact the Testcontainers team and other users from the Testcontainers community on [Slack](https://slack.testcontainers.org/).

{{< grid items=quickstart >}}

## Guides

Explore hands-on Testcontainers guides to learn how to use Testcontainers
with different languages and popular frameworks:

- [Getting started with Testcontainers for .NET](/guides/testcontainers-dotnet-getting-started/)
- [Getting started with Testcontainers for Go](/guides/testcontainers-go-getting-started/)
- [Getting started with Testcontainers for Java](/guides/testcontainers-java-getting-started/)
- [Getting started with Testcontainers for Node.js](/guides/testcontainers-nodejs-getting-started/)
- [Getting started with Testcontainers for Python](/guides/testcontainers-python-getting-started/)
- [Testing a Spring Boot REST API with Testcontainers](/guides/testcontainers-java-spring-boot-rest-api/)
- [Testcontainers container lifecycle management](/guides/testcontainers-java-lifecycle/)
- [Replace H2 with a real database for testing](/guides/testcontainers-java-replace-h2/)
- [Configuration of services running in a container](/guides/testcontainers-java-service-configuration/)
- [Testing an ASP.NET Core web app](/guides/testcontainers-dotnet-aspnet-core/)
- [Testing Spring Boot Kafka Listener](/guides/testcontainers-java-spring-boot-kafka/)
- [Testing REST API integrations using MockServer](/guides/testcontainers-java-mockserver/)
- [Testing AWS service integrations using LocalStack](/guides/testcontainers-java-aws-localstack/)
- [Testing Quarkus applications with Testcontainers](/guides/testcontainers-java-quarkus/)
- [Working with jOOQ and Flyway using Testcontainers](/guides/testcontainers-java-jooq-flyway/)
- [Testing REST API integrations using WireMock](/guides/testcontainers-java-wiremock/)
- [Securing Spring Boot with Keycloak and Testcontainers](/guides/testcontainers-java-keycloak-spring-boot/)
- [Testing Micronaut REST API with WireMock](/guides/testcontainers-java-micronaut-wiremock/)
- [Testing Micronaut Kafka Listener](/guides/testcontainers-java-micronaut-kafka/)
