How to Run a Private Docker Registry on Raspberry Pi
A private Docker registry lets you store your own container images locally instead of relying on Docker Hub. This is useful for home lab projects, CI/CD pipelines, and keeping your images on your own network. The official registry:2 image is lightweight and runs well on a Raspberry Pi.
Prerequisites
Before getting started, make sure you have:
- A Raspberry Pi 3 or newer running Raspberry Pi OS (64-bit recommended).
- Docker and Docker Compose installed. If you need to set these up, see our Docker setup guide.
- SSH access to your Raspberry Pi.
- Another machine on your network with Docker installed for testing pushes and pulls.
Step 1: Create the Project Directory
SSH into your Raspberry Pi and create a directory for the registry:
mkdir -p ~/docker-registry && cd ~/docker-registry
Step 2: Create the Docker Compose File
Create a docker-compose.yml file with the following content:
version: "3"
services:
registry:
image: registry:2
container_name: docker-registry
restart: always
ports:
- "5000:5000"
volumes:
- ./registry-data:/var/lib/registry
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
This maps port 5000 on the Pi to the registry container and stores all image data in the ./registry-data directory on disk.
Step 3: Start the Registry
Launch the registry container and verify it is running:
cd ~/docker-registry
docker compose up -d
docker compose ps
curl http://localhost:5000/v2/_catalog
You should see {"repositories":[]} since no images have been pushed yet.
Step 4: Configure Docker for Insecure Registries
By default, Docker requires HTTPS for registry communication. Since we are running on a local network without TLS, you need to configure Docker to allow insecure connections. On each machine that will push or pull images, edit or create the daemon configuration file:
sudo nano /etc/docker/daemon.json
Add the following content, replacing <your-pi-ip> with the actual IP address of your Raspberry Pi:
{
"insecure-registries": ["<your-pi-ip>:5000"]
}
Then restart Docker for the change to take effect:
sudo systemctl restart docker
Step 5: Tag, Push, and Pull Images
Now you can push images to your private registry. Pull a test image, tag it, and push:
docker pull alpine:latest
docker tag alpine:latest <your-pi-ip>:5000/my-alpine:latest
docker push <your-pi-ip>:5000/my-alpine:latest
Verify it was stored:
curl http://<your-pi-ip>:5000/v2/_catalog
You should now see {"repositories":["my-alpine"]}. To pull from another machine (after configuring insecure registries on that machine), run docker pull <your-pi-ip>:5000/my-alpine:latest.
You can also list tags for a specific image:
curl http://<your-pi-ip>:5000/v2/my-alpine/tags/list
Step 6: Add Basic Authentication
For additional security, you can protect your registry with basic authentication using htpasswd. Install the tool, create an auth directory, and generate a password file:
sudo apt install -y apache2-utils
mkdir -p ~/docker-registry/auth
htpasswd -Bc ~/docker-registry/auth/htpasswd myuser
You will be prompted to enter and confirm a password. Now update your docker-compose.yml to enable authentication:
version: "3"
services:
registry:
image: registry:2
container_name: docker-registry
restart: always
ports:
- "5000:5000"
volumes:
- ./registry-data:/var/lib/registry
- ./auth:/auth
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
Restart the registry to apply the changes:
cd ~/docker-registry
docker compose down
docker compose up -d
Now, before pushing or pulling images, you must log in:
docker login <your-pi-ip>:5000
Enter the username and password you created with htpasswd. If you have authentication enabled and want to use the API with curl, add credentials: curl -u myuser:mypassword http://<your-pi-ip>:5000/v2/_catalog.
Troubleshooting
- "http: server gave HTTP response to HTTPS client": You need to add your registry to
insecure-registriesin/etc/docker/daemon.jsonand restart Docker. - Push fails with authentication error: Run
docker login <your-pi-ip>:5000before pushing. - Cannot connect to port 5000: Check your firewall settings. If UFW is enabled, run
sudo ufw allow 5000. - Registry data growing too large: Enable the garbage collector by running
docker exec docker-registry bin/registry garbage-collect /etc/docker/registry/config.ymlto clean up unreferenced layers. - Container won't start after enabling auth: Verify the
auth/htpasswdfile exists and the path in the compose file is correct.
Conclusion
You now have a private Docker registry running on your Raspberry Pi. This gives you a local, fast, and private place to store your container images. Combined with a CI/CD pipeline, your registry can serve as the backbone of a fully self-hosted development workflow right from your home network.