I’ve rented a server on which I’d like to host my own Docker container registry. The server uses Ubuntu 24.04, docker and docker compose are installed.
Now, I’ve created this docker-compose.yml to run a registry on the server:
version: '3'
services:
registry:
image: registry:2
ports:
- "127.0.0.1:5000:5000"
environment:
REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /var/lib/registry
volumes:
- ./data:/var/lib/registry
I’m running this with docker compose up
.
Then I’ve set up an ssh tunnel from my client to the server ssh -L 5000:localhost:5000 user@server
.
Now, as a sanity check, I’m running this command on my client:
$ curl -X GET http://127.0.0.1:5000/v2/_catalog
{"repositories":[]}
The output looks reasonable, an empty list of repositories. On the server I’m running docker compose up
without -d
flag, to look at the logging output and it says:
registry-1 | time="2024-10-08T10:24:16.455126761Z" level=info msg="response completed" go.version=go1.20.8 http.request.host="127.0.0.1:5000" http.request.id=133d3573-9be6-48fe-9102-ffdac2706c93 http.request.method=GET http.request.remoteaddr="172.18.0.1:35336" http.request.uri="/v2/_catalog" http.request.useragent="curl/8.4.0" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.285188ms http.response.status=200 http.response.written=20
registry-1 | 172.18.0.1 - - [08/Oct/2024:10:24:16 +0000] "GET /v2/_catalog HTTP/1.1" 200 20 "" "curl/8.4.0"
Now I’d like to tag and push an image. I’m running the following commands on the client:
$ docker tag hello-world 127.0.0.1:5000/test:latest
$ docker push 127.0.0.1:5000/test:latest
The push refers to repository [127.0.0.1:5000/test]
Get "http://127.0.0.1:5000/v2/": dial tcp 127.0.0.1:5000: connect: connection refused
I’ve also tried tagging this with localhost
instead of 127.0.0.1
but the result is the same.
To sanity check whether the registry is working, I’ve tried the same on the server:
root@Ubuntu-2404-noble-amd64-base ~ # docker tag hello-world 127.0.0.1:5000/test:latest
root@Ubuntu-2404-noble-amd64-base ~ # docker push 127.0.0.1:5000/test:latest
The push refers to repository [127.0.0.1:5000/test]
ac28800ec8bb: Pushed latest: digest: sha256:d37ada95d47ad12224c205a938129df7a3e52345828b4fa27b03a98825d1e2e7 size: 524
So this works, the registry seems to work correctly. As another sanity check, let’s repeat the curl command on the client:
$ curl -X GET http://127.0.0.1:5000/v2/_catalog
{"repositories":["test"]}
So this seems to correctly point to the docker registry on the remote server. The ssh tunnel seems to work.
But the exact same commands that can tag and push an image on the server, fail with a connection error on the client.
I’m using MacOS on the client. I’ve set insecure registries in the settings of the Docker engine:
"insecure-registries": [
"127.0.0.1:5000",
"localhost:5000"
]
At this point I’m at a loss. Can you advise me how to proceed with troubleshooting this?
2
Answers
The following is a proof of concept. Use https , not SSH.
Architecture
Please confirm the following information about your Server:
The following will use the machine in my internal environment as an example, so the IP and Server FQDN name are examples. Please adjust them according to your own Sercer settings.
For my example:
Since I don’t have DNS, to simplify things, I directly modified the file contents of
/etc/hosts
./etc/hosts
ADD this line to
/etc/hosts
file(Both clientA and serverB need to be modified.)
serverB
create a directory
my_docker_registry
as your project directory.Project Tree
config registry
All instructions are executed in the
my_docker_registry
(project root directory).add user id and password
create two users:
config nginx
All instructions are executed in the
my_docker_registry
(project root directory).create ssl certificate
The following contents are adjusted according to the contents of https://goharbor.io/docs/2.5.0/install-config/configure-https/ to generate ssl credentials.
The following will switch the instruction execution directory to the nginx/certs directory.
Step 01 : Generate a CA certificate private key.
Step 02 : Generate the CA certificate.
Note, please adjust the content of the following commands according to the FQDN name of the server you set (for example:
demoserver.demo.local
).Step 03 : Generate a Server Certificate
Step 03-1 : Generate a private key.
Step 03-2 : Generate a certificate signing request (CSR).
Step 03-3 : Generate an x509 v3 extension file.
Step 03-4 : Use the v3.ext file to generate a certificate for your Server host.
Step 04 : Convert demoserver.demo.local.crt to demoserver.demo.local.cert, for use by Docker.
Step 05 : Copy the server certificate, key and CA files into the Docker certificates folder on your server host. You must create the appropriate folders first.
nginx/Dockerfile
nginx/nginx.conf
docker-compose.yml
Start
check
You will see two containers being executed. One is
nginx
and theregistry
.Test
login
input username and password. (my example:
demo01user
)will return
Login Succeeded
get
clientA – your macOS
Now copy the nginx/certs directory on serverB to your clientA host (your macOS)
Execute the following instructions
Note that related instructions may need to be adjusted under macOS.
Note: This is executed on clientA which is your macOS.
Since I don’t have DNS, to simplify things, I directly modified the file contents of
/etc/hosts
./etc/hosts
ADD this is
/etc/hosts
Now, on clientA execute:
You should be able to see the execution results of hello-world` retrieved from serveB.
You can also check the image on your local machine.
localhost
points to multiple things with Docker on MacOS. Inside the container it points to that container. On your MacOS host, it points to your host. But to the docker engine, it points to the VM where docker is running.From the docker engine, to point to the IP of your MacOS host, you would point to
host.docker.internal
instead oflocalhost
. Or as another alternative, you could run the ssh proxy inside of a container. This is also why running the registry inside of a container works.For more details, see: From inside of a Docker container, how do I connect to the localhost of the machine?