Raised: $0
0% of monthly goal Help us cross the finish line!
Goal: $12,000
Raised: $0 Goal: $12,000
0% of monthly goal Help us cross the finish line!
Sponsor DDEV

Podman and Docker Rootless in DDEV

January 8, 2026 12 min read

Edit this page
DDEV logo with Podman and Docker logos

TL;DR: DDEV now supports Podman and Docker Rootless in DDEV HEAD (coming in v1.25.0). Jump to setup instructions: Linux/WSL2 · macOS · Windows

Note: This support is experimental. Report issues on the DDEV issue tracker.

Table of Contents

Understanding Docker and Podman

Open Source Alternatives to Docker Desktop

A common misconception is that Podman is the only open-source alternative to Docker Desktop. This is not true. There are several fully open-source alternatives available on every platform:

  • Docker Engine - The original open-source Docker, free to use
  • Rancher Desktop - Open source container management with choice of dockerd or containerd
  • Lima - Linux virtual machines
  • Colima - Container runtime with minimal setup (built on Lima)
  • Podman Desktop - GUI for Podman with Docker compatibility

All of these work with DDEV. The main reason to choose Podman specifically is if your organization forbids Docker entirely or if you want rootless operation by default.

Why Choose Podman?

Podman is rootless by default, making it the simplest option for secure container environments. Traditional Docker requires root daemons, which can be a security concern in corporate environments with strict policies. (Note that DDEV is targeted at local development, where there are few risks of specialized attacks using this vector anyway.)

Podman’s rootless approach runs the daemon without elevated privileges:

  • No root daemon on the system, only a rootless daemon in userspace
  • Container processes cannot access root-owned files
  • Reduced attack surface if a container is compromised

While DDEV already runs containers as unprivileged users, Podman eliminates the need for a root daemon entirely.

Why Choose Docker Rootless?

Docker Rootless provides the same security benefits as Podman Rootless while maintaining full Docker compatibility. It runs the daemon without root privileges, offering:

  • No root daemon on the system
  • Container processes cannot access root-owned files
  • Reduced attack surface if a container is compromised

Unlike Podman which is rootless by default, Docker Rootless requires special setup to enable. Choose this option if you want to stay with Docker but need rootless security.

Key aim: Linux and WSL2 users

The primary focus for this article is Linux and WSL2 (we have test coverage for Linux only for now). Most features and configurations are well-tested on these platforms.

Installing Podman

Install Podman using your distribution’s package manager. See the official Podman installation guide for Linux.

Note: Some distributions may have outdated Podman versions. This is the case with Ubuntu 24.04, which has Podman 4.9.3. We require Podman 5.0 or newer for the best experience, because we didn’t have success with Podman 4.x in our automated tests, but you can still use Podman 4.x ignoring the warning on ddev start.

You can also install Podman Desktop if you prefer a GUI.

For more information, see the Podman tutorials.

Installing Docker CLI

Podman provides a Docker-compatible API, which means you can use the Docker CLI as a frontend for Podman. This approach offers several benefits:

  • Use familiar docker commands while Podman handles the actual container operations
  • Switch between different container runtimes using Docker contexts
  • Maintain compatibility with scripts and tools that expect the docker command
  1. Set up Docker’s repository

  2. Install only the CLI:

    # Ubuntu/Debian
    sudo apt-get install docker-ce-cli
    # Fedora
    sudo dnf install docker-ce-cli

    Note: You don’t need to install docker-ce (the Docker engine).

Configuring Podman Rootless

This is the recommended configuration for most users.

  1. Prepare the system:

    # Add subuid and subgid ranges if they don't exist for the current user
    grep "^$(id -un):\|^$(id -u):" /etc/subuid >/dev/null 2>&1 || sudo usermod --add-subuids 100000-165535 $(whoami)
    grep "^$(id -un):\|^$(id -u):" /etc/subgid >/dev/null 2>&1 || sudo usermod --add-subgids 100000-165535 $(whoami)
    # Propagate changes to subuid and subgid
    podman system migrate
    # Debian requires setting unprivileged_userns_clone
    if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
      if [ "1" != "$(cat /proc/sys/kernel/unprivileged_userns_clone)" ]; then
        echo 'kernel.unprivileged_userns_clone=1' | sudo tee -a /etc/sysctl.d/60-rootless.conf
        sudo sysctl --system
      fi
    fi
    # Fedora requires setting max_user_namespaces
    if [ -f /proc/sys/user/max_user_namespaces ]; then
      if [ "0" = "$(cat /proc/sys/user/max_user_namespaces)" ]; then
        echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.d/60-rootless.conf
        sudo sysctl --system
      fi
    fi
    # Allow privileged port access if needed
    if [ -f /proc/sys/net/ipv4/ip_unprivileged_port_start ]; then
      if [ "1024" = "$(cat /proc/sys/net/ipv4/ip_unprivileged_port_start)" ]; then
        echo 'net.ipv4.ip_unprivileged_port_start=0' | sudo tee -a /etc/sysctl.d/60-rootless.conf
        sudo sysctl --system
      fi
    fi

    For more details, see the Arch Linux Wiki.

  2. Enable the Podman socket and verify it’s running:

    systemctl --user enable --now podman.socket
    
    # You should see `/run/user/1000/podman/podman.sock` (the number may vary):
    ls $XDG_RUNTIME_DIR/podman/podman.sock
    
    # You can also check the socket path with:
    podman info --format '{{.Host.RemoteSocket.Path}}'

    For more details, see the Podman socket activation documentation.

  3. Configure Docker API to use Podman:

    # View existing contexts
    docker context ls
    
    # Create Podman rootless context
    docker context create podman-rootless \
        --description "Podman (rootless)" \
        --docker host="unix://$XDG_RUNTIME_DIR/podman/podman.sock"
    
    # Switch to the new context
    docker context use podman-rootless
    
    # Verify it works
    docker ps

    For more details, see Podman rootless tutorial

  4. Proceed with DDEV installation.

Podman Rootless Performance Optimization

Podman Rootless is significantly slower than Docker. See these resources:

To improve performance, install fuse-overlayfs and configure the overlay storage driver:

Install fuse-overlayfs:

# Ubuntu/Debian
sudo apt-get install fuse-overlayfs
# Fedora
sudo dnf install fuse-overlayfs

Configure storage:

mkdir -p ~/.config/containers
cat << 'EOF' > ~/.config/containers/storage.conf
[storage]
driver = "overlay"
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
EOF

Warning: If you already have Podman containers, images, or volumes, you’ll need to reset Podman for this change to take effect:

podman system reset

This removes all existing containers, images, and volumes (similar to docker system prune -a).

Configuring Podman Rootful

Rootless Podman is recommended for most users. However, if you need rootful Podman, the setup differs from rootless in two key ways:

  1. User group permissions: configure group permissions to allow non-root users to access the rootful socket

  2. Socket activation and paths:

    # Enable rootful socket (requires sudo)
    sudo systemctl enable --now podman.socket
    
    # Socket path for rootful
    ls /var/run/podman/podman.sock

    Compare to rootless:

    # Rootless socket (no sudo)
    systemctl --user enable --now podman.socket
    
    # Socket path for rootless
    ls $XDG_RUNTIME_DIR/podman/podman.sock

Setting Up Docker Rootless

Docker Rootless on Linux offers rootless security with full Docker compatibility.

  1. Follow the official Docker Rootless installation guide.

  2. Configure system:

    # Allow privileged port access if needed
    if [ -f /proc/sys/net/ipv4/ip_unprivileged_port_start ]; then
      if [ "1024" = "$(cat /proc/sys/net/ipv4/ip_unprivileged_port_start)" ]; then
        echo 'net.ipv4.ip_unprivileged_port_start=0' | sudo tee -a /etc/sysctl.d/60-rootless.conf
        sudo sysctl --system
      fi
    fi
    # Allow loopback connections (needed for working Xdebug)
    # See https://github.com/moby/moby/issues/47684#issuecomment-2166149845
    mkdir -p ~/.config/systemd/user/docker.service.d
    cat << 'EOF' > ~/.config/systemd/user/docker.service.d/override.conf
    [Service]
    Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_DISABLE_HOST_LOOPBACK=false"
    EOF
  3. Enable the Docker socket, and verify it’s running:

    systemctl --user enable --now docker.socket
    
    # You should see `/run/user/1000/docker.sock` (the number may vary):
    ls $XDG_RUNTIME_DIR/docker.sock
  4. Configure Docker API to use Docker rootless:

    # View existing contexts
    docker context ls
    
    # Create rootless context if it doesn't exist
    docker context inspect rootless >/dev/null 2>&1 || \
        docker context create rootless \
            --description "Rootless runtime socket" \
            --docker host="unix://$XDG_RUNTIME_DIR/docker.sock"
    
    # Switch to the context
    docker context use rootless
    
    # Verify it works
    docker ps
  5. Proceed with DDEV installation.

  6. Docker Rootless requires no-bind-mounts mode

    Docker Rootless has a limitation with bind mounts that affects DDEV. You must enable no-bind-mounts mode:

    ddev config global --no-bind-mounts=true

    Why this is needed:

    Docker Rootless sets ownership for bind mounts to root inside containers. This is a known issue:

    The root user inside the container maps to your host user, but many services will not run as root:

    • nginx runs as root without problems
    • MySQL/MariaDB need extra configuration
    • Apache and PostgreSQL will not run as root

    Podman Rootless fixes this with the --userns=keep-id option, which keeps user IDs the same. Docker Rootless does not have this option.

    The no-bind-mounts mode fixes this by using Mutagen for the web container.

macOS

macOS users can use Podman and Podman Desktop, but setup has its own challenges. Docker Rootless is not available on macOS.

Installing Podman

Install Podman using Homebrew:

brew install podman

Or install Podman Desktop if you prefer a GUI.

For more information, see the official Podman installation guide for macOS and Podman tutorials.

Installing Docker CLI

Podman provides a Docker-compatible API, which means you can use the Docker CLI as a frontend for Podman. This approach offers several benefits:

  • Use familiar docker commands while Podman handles the actual container operations
  • Switch between different container runtimes using Docker contexts
  • Maintain compatibility with scripts and tools that expect the docker command
brew install docker

Configuring Podman

  1. Initialize and start the Podman machine:

    # check `podman machine init -h` for more options
    podman machine init --memory 8192
    podman machine start

    Example output from podman machine start:

    ~ % podman machine start
    Starting machine "podman-machine-default"
    
    This machine is currently configured in rootless mode. If your containers
    require root permissions (e.g. ports < 1024), or if you run into compatibility
    issues with non-podman clients, you can switch using the following command:
    
    	podman machine set --rootful
    
    API forwarding listening on: /var/folders/x3/r1wk89cd3_x0yb_21dgnj53m0000gn/T/podman/podman-machine-default-api.sock
    
    The system helper service is not installed; the default Docker API socket
    address can't be used by podman. If you would like to install it, run the following commands:
    
            sudo /opt/homebrew/Cellar/podman/5.7.1/bin/podman-mac-helper install
            podman machine stop; podman machine start
    
    You can still connect Docker API clients by setting DOCKER_HOST using the
    following command in your terminal session:
    
            export DOCKER_HOST='unix:///var/folders/x3/r1wk89cd3_x0yb_21dgnj53m0000gn/T/podman/podman-machine-default-api.sock'
    
    Machine "podman-machine-default" started successfully
  2. Configure Docker CLI to use Podman. Choose one of two approaches:

    Option 1: Create a Docker context (recommended, more flexible):

    # Create Podman context (path to socket may vary)
    # Use the socket path from `podman machine start` output
    docker context create podman-rootless \
        --description "Podman (rootless)" \
        --docker host="unix:///var/folders/x3/r1wk89cd3_x0yb_21dgnj53m0000gn/T/podman/podman-machine-default-api.sock"
    
    # Switch to the new context
    docker context use podman
    
    # Verify it works
    docker ps

    This approach uses Docker contexts to switch between different container runtimes without modifying system sockets. This is more flexible if you want to use multiple Docker providers.

    Option 2: Use the default Docker socket (simpler, but less flexible):

    # Install podman-mac-helper
    # Use the command from `podman machine start` output
    sudo /opt/homebrew/Cellar/podman/5.7.1/bin/podman-mac-helper install
    podman machine stop
    podman machine start
    
    # Verify it works
    docker ps
  3. Proceed with DDEV installation.

  4. Handle privileged ports (<1024):

    Podman on macOS cannot bind to privileged ports (80/443). Configure DDEV to use unprivileged ports:

    ddev config global --router-http-port=8080 \
        --router-https-port=8443

    Note: switching to rootful mode with podman machine set --rootful --user-mode-networking=false doesn’t help with privileged ports because the --user-mode-networking=false flag is not supported on macOS (it’s only available for WSL).

Windows

Windows users can use Podman Desktop, but setup has its own challenges. Docker Rootless is not available on traditional Windows (it works in WSL2, see the Linux and WSL2 section).

Installing Podman

Install Podman Desktop, which includes Podman.

Alternatively, install Podman directly following the official Podman installation guide for Windows.

For more information, see the Podman tutorials.

The setup and configuration follow similar patterns to the Linux/WSL2 setup, but with Podman Desktop managing the VM for you. Follow the Linux and WSL2 instructions.

Running Multiple Container Runtimes

You can run Docker and Podman sockets simultaneously and switch between them using Docker contexts.

For example, here’s a system with four active Docker contexts:

$ docker context ls
NAME                DESCRIPTION                               DOCKER ENDPOINT
default             Current DOCKER_HOST based configuration   unix:///var/run/docker.sock
podman              Podman (rootful)                          unix:///var/run/podman/podman.sock
podman-rootless *   Podman (rootless)                         unix:///run/user/1000/podman/podman.sock
rootless            Rootless runtime socket                   unix:///run/user/1000/docker.sock

Switch between them with:

docker context use "<context-name>"

Note: Running both Docker and Podman in rootful mode at the same time may cause network conflicts. See Podman and Docker network problem on Fedora 41.

Switching Runtimes with DDEV

DDEV automatically detects your active container runtime. To switch:

  1. Stop DDEV projects:

    ddev poweroff
  2. Switch Docker context or change the DOCKER_HOST environment variable

  3. Start your project:

    ddev start

Which Runtime Should You Choose?

Runtime Comparison

FeatureStandard DockerDocker RootlessPodman RootfulPodman Rootless
Platform SupportAllLinux, WSL2AllAll
Rootless Daemon
Has automated testing in DDEV
Mutagen
Bind Mounts❌, requires no-bind-mounts✅ (with --userns=keep-id)
PerformanceExcellentModerate (because of no-bind-mounts)Slow compared to DockerSlow compared to Docker
Privileged Ports (<1024)Works by defaultRequires sysctl configWorks by defaultRequires sysctl config or may not work
Setup ComplexitySimpleModerateModerateModerate
MaturityMost matureExperimentalExperimentalExperimental
Recommended ForMost usersDocker users needing rootlessOrganizations that forbid DockerOrganizations that forbid Docker

Recommendations

Use of the many standard Docker providers if:

  • You’re comfortable with the most widely used container runtime
  • You don’t have rootless security requirements

This is the recommended option for the vast majority of users.

Use Podman Rootless if:

  • Your organization forbids Docker
  • You want rootless security by default

Use Podman Rootful if:

  • Your organization forbids Docker
  • You want traditional container permissions without user namespace mapping overhead

Use Docker Rootless if:

  • You need full Docker compatibility
  • You want rootless security without changing runtimes

The Journey to Podman Support

Supporting Podman and Docker Rootless required major changes to DDEV’s Docker integration:

  • Switched to official Docker client library (#5787): DDEV previously used an unofficial library to communicate with the Docker API. We migrated to Docker’s official client library for better compatibility and long-term support.
  • Replaced direct CLI calls with proper API usage (#7189): DDEV used to call docker context inspect directly, which doesn’t work with Podman. We switched to using the docker/cli library to handle context operations properly.
  • Modernized SSH authentication (#7511): The ddev auth ssh command used to call docker run directly. We rewrote it to use the Docker API, making it compatible with alternative runtimes.
  • Optimized API call performance (#7587): DDEV’s Docker API logic was inefficient, making redundant calls without caching. We restructured the code to cache data and reduce unnecessary API requests.
  • Removed legacy docker-compose features (#7642): Podman refuses to work with deprecated links and external_links directives in docker-compose files. We removed these legacy features and modernized DDEV’s compose file generation.
  • Added Podman and Docker Rootless support (#7702): DDEV now detects and supports Podman (rootful and rootless) and Docker Rootless. We added handling for Podman-specific limitations and enabled rootless environments to work without root privileges.
  • Added support for SELinux environments (#7939): Podman has SELinux enabled by default on Fedora and some other distributions. We added support for SELinux by configuring volume mounts with the appropriate labels.

These changes enabled Podman and Docker Rootless support. These features were developed together because Podman’s primary use case is rootless operation. Once DDEV could handle rootless runtimes, supporting both became natural. They share the same security model and similar technical constraints.

Supporting DDEV Development

This Podman and Docker Rootless support was made possible by community financial support. The changes required hundreds of hours of development, code reviews, and testing.

DDEV relies on support from individuals and organizations who use it. With Podman rootless support, DDEV now works in corporate environments where Docker Desktop is not allowed. If you or your organization uses DDEV, please consider sponsoring the project to help keep DDEV free and open source.

Conclusion

DDEV now supports Podman and Docker Rootless as experimental features. This opens DDEV to corporate environments where traditional Docker is not allowed.

DDEV automatically detects your runtime and handles the complexity. Whether you choose Podman for rootless security, Docker Rootless for compatibility, or standard Docker, setup is straightforward.


This article was edited and refined with assistance from Claude Code.