Knowledge Cut-Off: February 2024
Last Updated: February 2026
- Introduction
- System-Level Setup & Persistence
- Permissions & Identity Mapping (The "keep-id" Interaction)
- Security Trade-offs (SELinux)
- Universal Compose Strategy (Base vs. Template)
- Networking & DNS Nuances
- Troubleshooting
Running Docker Compose via Rootless Podman on macOS involves a nested architecture: your macOS host runs a Fedora-based Linux VM (the Podman Machine), which executes containers within a user namespace. This guide provides a production-grade workflow that ensures Podman functionality while maintaining Docker compatibility for your team.
Most Compose tools look for /var/run/docker.sock. Use the built-in helper to symlink the macOS system path to your user-level Podman machine socket:
sudo podman-mac-helper install
By default, the Podman VM blocks non-root users from binding to ports below 1024. To make this change survive both VM restarts and machine stops, write the configuration to the VM's persistent sysctl directory:
podman machine ssh "sudo bash -c 'echo \"net.ipv4.ip_unprivileged_port_start=80\" > /etc/sysctl.d/99-podman.conf' && sudo sysctl -p /etc/sysctl.d/99-podman.conf"
This combination is the standard for rootless success:
- userns_mode: "keep-id": Maps your Mac UID (e.g., 501) to that same UID inside the container.
- user: "0:0": Forces the process to run as "root" inside the container namespace.
- The Result: The process has internal root privileges (to bind ports or modify internal config) but writes files to your Mac as your actual user (UID 501).
- Why: Required for Traefik to write to the socket in rootless mode.
- Impact: Disables SELinux Mandatory Access Control for that specific container.
- Alternative: Use a custom SELinux policy if you require high-security isolation, though this is significantly more complex to maintain across Podman VM updates.
Keep your primary configuration clean. Use an override file for Podman-specific "breaking" changes.
services:
traefik:
image: traefik:v3.0
ports:
- "80:80"
- "443:443"
cap_add:
- NET_BIND_SERVICE
dns:
- 8.8.8.8
- 1.1.1.1
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data:/data:Z
# =========================================================================
# PODMAN ROOTLESS OVERRIDE TEMPLATE
# INSTRUCTIONS: Rename this file to 'docker-compose.override.yml' to
# activate Podman-specific settings. Ensure 'docker-compose.override.yml'
# is added to your .gitignore to avoid breaking Docker-based environments.
# =========================================================================
services:
traefik:
userns_mode: "keep-id"
security_opt:
- "label=disable"
user: "0:0"
- Internal Resolution: Use the service name defined in Compose.
- Host Access: To reach services running natively on your Mac (e.g., a local DB), use the address
host.containers.internal. - DNS Configuration: Podman networking sometimes fails to inherit Mac DNS settings. Always define
dnsat the service level in the base file if resolution fails.
If you encounter "Permission Denied" on a folder (common when NOT using keep-id), run this from your macOS terminal to align host UIDs with the Podman user namespace:
podman unshare chown -R $(id -u):$(id -g) ./data
ls -l /var/run/docker.sockpoints to your user's socket path.podman machine inspectconfirms the machine is "running".- Your
.gitignorecontainsdocker-compose.override.yml.