Configuring Registry Server for Woodpecker
In CI/CD processes, various Docker images are used for execution environments. While public Docker images are commonly used, sometimes locally built Docker images are necessary. If the Docker image changes frequently, it’s better to include the build process in the CI/CD pipeline, but if not, using pre-built images can be a good choice.
This is where a Registry Server comes in handy. In this post, we’ll explain how to set up a Registry server and use it with Woodpecker.
Setting up Registry Server
Registry Server can also be easily set up using Docker. Let’s configure the Compose file as follows:
version: "3.8"
services:
registry:
image: registry:latest
container_name: registry
restart: unless-stopped
ports:
- 5000:5000
networks:
- net
volumes:
- data:/var/lib/registry:rw
environment:
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin=['*']
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods=['HEAD', 'GET', 'OPTIONS', 'DELETE']
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials=['true']
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers=['Authorization', 'Accept', 'Cache-Control']
- REGISTRY_HTTP_HEADERS_Access-Control-Expose-Headers=['Docker-Content-Digest']
- REGISTRY_STORAGE_DELETE_ENABLED='true'
volumes:
data:
networks:
net:
After running the docker compose up -d command, the Registry Server will be started.
If it runs properly, you can upload images to the Registry Server as follows:
>>> docker tag <image_name> localhost:5000/<image_name>
>>> docker push localhost:5000/<image_name>
Registry UI Configuration
There are many ways to check if the images are uploaded properly, but the easiest way is to use a GUI tool. The tool used most often is joxit’s tool. The compose content to set it up is as follows:
services:
ui:
image: joxit/docker-registry-ui
container_name: registry-ui
restart: unless-stopped
ports:
- <port>:80
networks:
- net
environment:
- SINGLE_REGISTRY=true
- REGISTRY_TITLE=Docker Registry UI
- DELETE_IMAGES=true
- SHOW_CONTENT_DIGEST=true
- NGINX_PROXY_PASS_URL=http://registry:5000 # registry와 docker bridge로 연결되어 있어야 함.
- SHOW_CATALOG_NB_TAGS=true
- CATALOG_MIN_BRANCHES=1
- CATALOG_MAX_BRANCHES=1
- TAGLIST_PAGE_SIZE=100
- REGISTRY_SECURED=false
- CATALOG_ELEMENTS_LIMIT=1000
The important part is the NGINX_PROXY_PASS_URL section.
The Registry Server and Docker Bridge must be connected, and the Registry Server’s name should be used as the hostname.
If you change the <port> and set up a reverse proxy so that it can be accessed from the outside, you will see the following screen.

Registry Server Security
Since it’s a local server, it’s better to set up security. There are two ways to secure it: one is to restrict the access protocol to https, and the other is to set a password.
Restricting Access Protocol
I usually handle https protocols in the reverse proxy stage and have the internal service run on http. You can refer to the settings using HAProxy or nginx. Alternatively, if you have a DNS managed by services like CloudFlare, they may also provide proxy services. However, since there is often a capacity limit, it may not be suitable for a registry server that handles images in GB units.
Setting a Password
The password is set using htpasswd as follows:
>>> docker run --rm -it --entrypoint htpasswd registry:latest -Bbn <id> <password> > .htpasswd
This creates a .htpasswd file, which can be used to set the password.
In the docker compose file, it should be set as follows:
services:
registry:
image: registry:latest
container_name: registry
restart: unless-stopped
ports:
- 5000:5000
networks:
- net
volumes:
- data:/var/lib/registry:rw
- ./htpasswd:/auth/htpasswd
environment:
- ...
- REGISTRY_AUTH=htpasswd
- REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm
- REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
Using Registry Server in Woodpecker
Now, let’s set up Woodpecker to use the Registry Server. We’ll use the alpine image for testing. Let’s push the image to the repository.
>>> docker pull alpine:latest
>>> docker tag alpine:latest localhost:5000/alpine:latest
>>> docker push localhost:5000/alpine:latest
Then, create a test step in the repository that will run in CI in Woodpecker.
# .woodpecker.yml
steps:
test:
image: localhost:5000/alpine:latest
commands:
- echo "Hello, World!"
If you set it up this way, you can see the attempt to pull the image from the Registry Server. However, since there is no authentication information, a permission denied error occurs. To check the authentication information, the following settings should be added:
>>> docker login -u <username> -p <password> localhost:5000
Since the login information is stored in the current user’s docker config, the docker config should be added to the woodpecker environment.
environment:
- ...
- WOODPECKER_DOCKER_CONFIG=/home/<username>/.docker/config.json
This way, the image can be pulled using the login information.
Can Docker bridge network be used?
I didn’t want to expose the registry server.
I wanted to access it only through the docker bridge network.
I thought Woodpecker would also run on docker, so I could access the image pull from registry:5000 in the CI/CD process.
However, it seems impossible. The workspace where Woodpecker pulls the image is the same as the docker workspace on the host machine. If you look at the Woodpecker settings, you can see the following part:
volumes:
- /var/run/user/<uid>/docker.sock:/var/run/docker.sock
This means that the docker inside Woodpecker uses the docker socket of the host machine.
Therefore, the network information in the image pull stage is not the host that is accessible to the Woodpecker docker, but the host that is accessible to the host machine, so accessing registry:5000 is not possible.