Docker Community Forums

Share and learn in the Docker community.

Access container ONLY through reverse proxy

I wanted my application to be available on the internet ONLY through a reverse proxy (in my case Caddy) and not also from it’s port.
For example, I have the myapp that uses port 1234. I could access the myapp with myapp.example.com through reverse proxy, but also with ServerIpAddress:1234 which is what I did not want.
I have found the following solution and I’d like to know if it’s correct or there is a better one.
I created a new network docker network create proxyNet
In docker-compose of my app I set the port to 127.0.0.1:1234:1234 and the network to proxyNet
Example:

version: "3.8"
services:
  myapp:
    container_name: myapp
    image: sampleimage
    restart: unless-stopped
    ports:
      - 127.0.0.1:1234:1234
    volumes:
      - ./data:/data
    networks:
      - proxyNet

networks:
  proxyNet:
    external: true

Then I run my Caddy proxy on the same network proxyNet and on my Caddyfile:

myapp.example.com {
	reverse_proxy myapp:1234
}

It works as I want, but is it the correct way?

Thank you.

Hi olon!

First we must explain docker bridge feature.
Docker official Docs says:

In terms of Docker, a bridge network uses a software bridge which allows containers connected to the same bridge network to communicate, while providing isolation from containers which are not connected to that bridge network. The Docker bridge driver automatically installs rules in the host machine so that containers on different bridge networks cannot communicate directly with each other.

So basiclly docker bridge allows u to connect many containers in one network and automaticly comunicate each other even with DNS names of service.

for good practice, it is good to expose only a reverse proxy service to the world and leave the rest of the containers without exposing their ports. Then in the reverse proxy container you can use the names of the containers to forward traffic to them.

If your reverse proxy is off-bridge and a separate static application on the host then you need to expose the application to your localhost so that the static reverse proxy can communicate over localhost and port.

in your case, I would remove the entry for issuing port to localhost, write your site caddy to the compose file and only put this site to the world.
Then, in the container, caddy configured the forwarding of communication to the name of the application container so that the application service was not accessible via localhost, but only in the docker network. This is the safest solution.

Thank you @matixooo for the answer. I created the external network proxyNet because I wanted to connect there, all my containers (that are on different docker-compose.yml files, to be accessible from the internet only through the reverse proxy (which is also on the same network).
But I have a question:
How can I handle situations where two or more containers use the same port?
In my example I could use for app1:

    ports:
      - 127.0.0.1:10001:1234

and for app2

    ports:
      - 127.0.0.1:10002:1234

and in my reverse proxy container:

app1.example.com {
	reverse_proxy app1:10001
}
app2.example.com {
	reverse_proxy app2:10002
}

Or I understood wrong?
Can you give me a simple example like the above?

If app1 and app2 containers are in the same external docker network u dont need exposing them on localhost they are accessible on container port in the network.

your reverse proxy conf is good to go.

Excuse my ignorance, but by saying “not exposing to localhost” do you mean to remove 127.0.0.1 from ports or delete the ports completely?
If I remove 127.0.0.1 then the container is accessible by serverip:10001 which I don’t want.
If I remove the ports completely, there would be 2 apps with the same port 1234 on the same network bridge, which I don’t know if it works.

if you completely remove the entry about listing your ports from the compose, the application will be visible only in the bridge network, it will not be visible outside the docker network, so it will also not be available on the ip or localhost address.

if you do, the applications will be available to your proxy on your bridge without exposing them to any port on the host.
you will be able to ping them, for example, from another container in this network (you can check it by typing ping app02 in the container app01)

Docker bridges work like this, they allow for communication between containers within one network without the need to expose ports to the outside.

Ok. It’s clear that to me. What I don’t understand is what will happen if two apps are on the same network bridge and both have the same exposed port.

this will not work because the host cannot work simultaneously with two same ports.

but I see that you have set application ports in the proxy:
app1 10001
app2 10002

I understand that applications in containers work on these ports, if so, you do not need to expose them to other ports.

If you read my previous messages, you will see that app1 and app2 expose the same port 1234. The only way to access both is to use on docker-compose ports 10001:1234 and 10002:1234 and that is why on proxy I use reverse_proxy app1:10001 and reverse_proxy app2:10002
I suppose there is no workaround to this.

Update:
According to this post, it is possible. I’ll try it.