Quickly expose Docker ports

When running Docker containers you can easily publish ports on the container level or directly onto the host system so the service could be accessible from outsite (internet). This is true for systems that need to be exposed publicly, like web servers, however it's highly recommended to keep all sensitive services (like Redis) only available on the local network due to security risks.

Let's say you start Redis daemon in the container with the following command:

docker run -d --restart=always --name=redis redis

Redis container will be started in the background and expose ony 1 port. Check it with docker ps command:

CONTAINER ID  IMAGE   COMMAND                 STATUS        PORTS     NAMES
8648ad732d40  redis   "docker-entrypoint.s…"  Up 7 minutes  6379/tcp  redis

In case if you wanted to expose Redis to the public for troubleshooting you'd have to remove and create a new container. That won't work since all the data and logs will be lost. So we need to somehow temporarily expose the container to the public net. Here's when socat might come handy.

The goal is to create a new container (socat) that will talk to our redis service over the same docker network. There's already a socat docker image: alpine/socat, so we'll just use that. The following command should spawn the "proxy" container:

docker run \
  -d \
  --link=redis \
  -p 16379:6379 \
  --name=redis-public \
  alpine/socat \
  TCP4-LISTEN:6379,fork,reuseaddr TCP4:redis:6379

We are exposing port 16379 on the host system so that it won't be picked up by the network scanners right away, but you can pick any port you'd like. Check if our proxy is up with docker ps:

CONTAINER ID  IMAGE         COMMAND                  STATUS         PORTS                     NAMES
17322b86a601  alpine/socat  "socat TCP4-LISTEN:6…"   Up 1 second    0.0.0.0:16379->6379/tcp   redis-public
8648ad732d40  redis         "docker-entrypoint.s…"   Up 12 minutes  6379/tcp                  redis

Now we can access the redis container via the proxy:

telnet localhost 16379

Trying ::1...
Connected to localhost.
Escape character is '^]'.

info
$2643
# Server
redis_version:4.0.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:b6959c1042901757
# ... other stuff

Cool, so it works. Same process works if you want to connect to the remote host: telnet public-ip 16379. Once we're done troubleshooting the issues (or whatever), simply kill the container:

docker rm -f redis-public

All of above should work with any type of service (PostegreSQL, http servers, etc) as long as they run over TCP protocol.