Bits Beyond

How to Access Raspberry Pi GPIO Pins Inside a Docker Container

Cover Image for How to Access Raspberry Pi GPIO Pins Inside a Docker Container

Disclosure: This post may contain affiliate links. If you make a purchase through these links, I may earn a small commission at no additional cost to you. If you are building a homelab or automating your home network, you'll eventually want to run lightweight services on a Raspberry Pi 4 using Docker. Docker is fantastic for keeping your dependencies isolated, but that isolation becomes a hurdle when your containerized app needs to interact with physical hardware—like the Pi's GPIO (General Purpose Input/Output) pins.

By default, Docker containers do not have access to the host machine's hardware. If you try to run a script inside a container that toggles a GPIO pin, it will likely crash with a "permission denied" or "device not found" error.

Here is how to fix it properly without compromising your system's security.

The Solution: Mapping /dev/gpiomem

Many tutorials online will tell you to run your Docker container in --privileged mode to solve hardware access issues. Avoid doing this if possible. Privileged mode strips away almost all of Docker's security isolation, giving the container root-level access to your entire host system.

Instead, the secure and elegant solution is to explicitly pass only the GPIO memory interface into the container. Linux handles hardware as files, and on a Raspberry Pi, the GPIO memory is located at /dev/gpiomem.

Using Docker Compose

If you are managing your deployments with docker-compose.yml (which is highly recommended for homelab setups), you can use the devices directive to map the GPIO interface from your host into the container.

Add this to your service configuration:

version: '3.8'
services:
  my-gpio-app:
    image: my-node-red-or-python-app:latest
    restart: unless-stopped
    # This is the magic line that passes the GPIO hardware into the container
    devices:
      - /dev/gpiomem:/dev/gpiomem

Using the Docker CLI

If you prefer to spin up your containers manually using the command line, you can achieve the exact same result using the --device flag:

docker run -d \
  --name my-gpio-app \
  --device /dev/gpiomem:/dev/gpiomem \
  my-node-red-or-python-app:latest

Why /dev/gpiomem and not /dev/mem?

In older versions of the Raspberry Pi OS, developers often had to map /dev/mem to access GPIO. The problem is that /dev/mem gives access to all physical memory on the device, requiring your container to run as root.

/dev/gpiomem was introduced as a safer alternative. It restricts access purely to the GPIO registers, meaning your containerized scripts can run safely as a non-root user while still blinking LEDs, reading sensor data, or controlling relays. Conclusion

By mapping /dev/gpiomem, you keep your Docker containers secure, maintain the principle of least privilege, and successfully bridge the gap between containerized software and physical hardware. Happy tinkering!


A quick tip for this post:

Make sure you create a folder at /assets/blog/pi-docker-gpio/ in your Next.js project and drop a relevant cover.jpg in there so your build doesn't fail!

Read Next

Cover Image for How to deploy a next.js application on docker hub

How to deploy a next.js application on docker hub

Explore how to deploy a next.js application on docker hub.

Cover Image for Internal TryHackMe Write-Up

Internal TryHackMe Write-Up

The Internal room on TryHackMe is an hard challenge that let's you slip in the role of a penetration tester, where your objective is to perform a thorough penetration test

Cover Image for Daily Bugle TryHackMe Write-Up

Daily Bugle TryHackMe Write-Up

The Daily Bugle room on TryHackMe is a hard room that requires you to compromise a Joomla CMS account.