A standard docker push command (docs) looks like this:


#!/bin/bash
docker push {registry hostname}:{listening port}/{image name}:{image tag}
docker push registry.mydomain.com:5000/really_cool_image:3.1.2

But this assumes that the registry is accessible via your network. If it wasn’t, your push command would fail. Let’s say that your docker registry is running on a server whose firewall denies most incoming connections - you can only access it over ssh.

Setup an ssh tunnel from your local machine to the remote server. In this example the registry is listening on port 5000 of the server.


$ ssh -f -N -L 5000:localhost:5000 -l my_username registry.mydomain.com

Options explained:

  • -f puts ssh into background mode
  • -N means that no command will be run on the remote machine, we’re just forwarding traffic
  • -L port:host:host_port
  • -l is the username you want to use on the remote machine. Leave it out to use your current username.

Now, traffic directed to localhost:5000 will be forwarded to registry.mydomain.com:5000 over the ssh tunnel.

You can now run docker push like this:


$ docker tag really_cool_image:3.1.2 localhost:5000/really_cool_image:3.1.2
$ docker push localhost:5000/really_cool_image:3.1.2

Doing this on macOS

If you try to do the above with docker for mac, you’ll probably find yourself with an error like this:


The push refers to a repository [localhost:5000/really_cool_image]
Put http://localhost:5000/v1/repositories/really_cool_image/: dial tcp 127.0.0.1:5000: getsockopt: connection refused

What’s happening here is that docker can’t access the ssh tunnel you setup on the mac, because of the way Docker works on macOS. Essentially, your mac and docker have two different 127.0.0.1 addresses. You can get around this by explicitly setting up the ssh tunnel within docker instead of on your mac. First, open Docker’s own terminal via screen:


screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty

Hit enter and you should see a / # appear. You can now setup the ssh tunnel from within Docker itself:


ssh -f -N -L 5000:localhost:5000 -l my_username registry.mydomain.com

Once that’s setup, you should be able to run your normal docker push command from the macOS terminal.