Build and host your own Docker images locally, without relying on an upstream registry.
Images are built for amd64 and arm64 (multi-arch) and tagged with a date-based tag (YYYYMMDD), then pushed to a local Docker Registry v2 running on localhost:5000.
- Docker with Buildx support (included in Docker Desktop and Docker Engine ≥ 19.03)
- Docker Compose v2+
make,curl,python3(for thelisttarget)
docker-builder/
├── Makefile ← build entrypoint
├── docker-compose.yml ← local registry
├── .env ← configuration
├── images/
│ └── debian-base/
│ └── Dockerfile
└── README.md
Edit .env to change defaults:
REGISTRY=localhost:5000 # local registry address
BUILDX_BUILDER=multiarch # buildx builder namemake registry-upThis starts a Docker Registry v2 container at http://localhost:5000. Image data is persisted in a Docker named volume (registry-data).
Add localhost:5000 to your Docker daemon's insecure registries.
Linux (/etc/docker/daemon.json):
{
"insecure-registries": ["localhost:5000"]
}Then restart Docker: sudo systemctl restart docker
Docker Desktop (Mac/Windows): go to Settings → Docker Engine and add the same JSON snippet.
make build IMAGE=debian-baseThis builds images/debian-base/Dockerfile for both linux/amd64 and linux/arm64, tags it as:
localhost:5000/debian-base:YYYYMMDDlocalhost:5000/debian-base:latest
and pushes it directly to the local registry.
make allmake listdocker pull localhost:5000/debian-base:latest- Create a new directory under
images/:mkdir images/my-new-image
- Add a
Dockerfileinside it. - Build it:
make build IMAGE=my-new-image
The make all target automatically discovers all directories under images/.
make registry-downImage data is preserved in the registry-data volume. To also remove the data:
docker compose down -vIn any docker-compose.yml, prefix the image name with localhost:5000:
services:
myapp:
image: localhost:5000/debian-base:latest
pull_policy: alwaysTip:
pull_policy: alwaysensures Docker checks the local registry for updates on everydocker compose up.
Replace localhost with the builder machine's IP address:
services:
myapp:
image: 192.168.1.100:5000/debian-base:latestOn the consuming machine, also add the remote address to insecure registries:
Linux (/etc/docker/daemon.json):
{
"insecure-registries": ["192.168.1.100:5000"]
}Then restart Docker: sudo systemctl restart docker
Docker Desktop (Mac/Windows): go to Settings → Docker Engine and add the same snippet.
If you built an image elsewhere and want to push it into this local registry:
Add the registry to insecure registries in /etc/docker/daemon.json:
{
"insecure-registries": ["192.168.1.100:5000"]
}Then restart Docker: sudo systemctl restart docker
Replace 192.168.1.100 with your registry machine's actual IP (hostname -I to find it).
# Retag your local image to point at the registry
docker tag my-image:latest 192.168.1.100:5000/my-image:latest
# Push it
docker push 192.168.1.100:5000/my-image:latestOr use the import Makefile target from the other machine:
make import IMAGE=my-image TAG=latest REGISTRY=192.168.1.100:5000make list| Target | Description |
|---|---|
registry-up |
Start the local Docker registry |
registry-down |
Stop the local Docker registry |
buildx-setup |
Create the multi-arch buildx builder |
build IMAGE=<name> |
Build + push a single image |
push IMAGE=<name> |
Push a pre-built image to local registry |
import IMAGE=<name> TAG=<tag> |
Retag a local image and push to registry |
all |
Build + push all images |
list |
List all repositories in the registry |