What container interface(s) does Docker port mapping (`-p <host-port>:<container-port>`) apply to? - linux

Which container interface does Docker port mapping (-p <host-port>:<container-port>) apply to?
After having read the Docker documentation, I'm not sure what network interface(s) in the Docker container a Docker port mapping like (1) and (2) applies to.
By default a new container is created with two interfaces eth0 and lo, but more can be added.
(1) is shorthand for -p 0.0.0.0:8080:80.
(2) refers to the network interface on the host with IP address 192.168.1.100, and it maps host port 8080 to container port 80, but on what container interface?
(1) -p 8080:80 Map TCP port 80 in the container to port 8080 on the Docker host.
(2) -p 192.168.1.100:8080:80 Map TCP port 80 in the container to port 8080 on the Docker host for connections to host IP 192.168.1.100.
Do (1) and (2) map host port 8080 to container port 80 on ALL container interfaces (0.0.0.0)? If, so where can I see that in the documentation, and can this behaviour be restricted to a specific set of container interfaces?
https://docs.docker.com/config/containers/container-networking/

TCP connections have a single starting point (IP+port) and single end point (IP+port). As such, the port forwarding can only map to one IP address in the container. Specifically, the bridge network interface.
"Can this behavior be restricted to a specific set of container interfaces" doesn't really make sense, then: by the nature of TCP, there's only ever one interface that's being connected to.
If you're worried that things listening on 127.0.0.1 inside the container will be come public, then don't; they won't (and can't).
https://pythonspeed.com/articles/docker-connection-refused/ has a bunch of diagrams that might make this clearer.

Do (1) and (2) map host port 8080 to container port 80 on ALL container interfaces (0.0.0.0)
Not exactly. (1) maps host port 8080 to container port 80 on all host interfaces. (2) maps host port 8080 on host interface with ip address 192.168.1.100 to containers port 80.
Specifically, it does something along (copying from my machine):
iptables -t nat -A PREROUTING -m addrypte --dst-type LOCAL -j DOCKER
iptables -t nat -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
iptables -t nat -A DOCKER ! -i <bridge docker interface> -p tcp -m tcp --dport 8080 -j DNAT --to-destination <container-IP-address>
In net:PREROUTING the traffic for dport 8080 is redirected to container IP Address.
I believe you seem to be confused and assume that containers have multiple interfaces. Container has (usually) one interface and is connected to one docker network.

Related

Is it possible to assign port mapping to an existing Docker container by iptables on Linux?

Operating system : ubuntu 16.04 LTS ,here's my problem.
Recently I'm building a application rely on a Redis(Docker) offered data service. A customary way of creating new Redis service is kind of like this:
docker pull redis:latest
docker run -d --name redis -p 6379:6379 redis:latest
Assuming my WAN IP is 201.201.201.201 ,then it should just fine to access Redis via address:201.201.201.201:6379.
However this approach exposes a redis server's port to public network ,even though you can give a supper long password ,potential safety hazard remains.
Since docker do not support port mapping changing within a running container ,I need to shut down the whole docker service ,that takes a long time ,nearly impossible.
Then I'm trying to use IP table mapping instead of creating a docker map ,due to iptables 's flexibility ,theoretically it allows benefits from both sides -- uoload files from wherever else in the world(out side zz) ,but can also close this
iptables -t nat -A PREROUTING -d 172.245.210.199 -p tcp --dport 6379 -j DNAT --to-destination 172.17.0.5:6379
iptables -t nat -A POSTROUTING -d 172.17.0.5 -p tcp --dport 6379 -j SNAT --to 172.17.0.1
But it do not work ,I can't ping container 17.17.0.162
Does anyone knows resolution ,or could propose some other ways to implement this port mapping (such as nginx or caddy?)
Thanks!
What I suggest is to use an assistant container, in this container add port forward for your service container which did not do port mapping:
docker run -idt --link redis -p 6379:6379 alpine/socat TCP4-LISTEN:6379,fork,reuseaddr TCP4:redis:6379
Above container will use --link redis so it can resolve the name of your redis container, and when receive the traffic from host's 6379, it will first forward to assistant container's 6379, then will use socat to forward the traffic to the redis container's 6379, so it works although your service container did not port mapping 6379.
As --link was deprecated, you can also customize your network, as you like:
docker network create my_network
docker network connect my_network redis
docker run -idt --network my_network -p 6379:6379 alpine/socat TCP4-LISTEN:6379,fork,reuseaddr TCP4:redis:6379

How to restrict access from internet to containers ports on remote linux server?

I use docker-compose on ubuntu 18 on remote server.
How, with iptables, can i block access from the internet to the docker port and only allow access to it from the localhost of this server?
For instance, i want to block 4150 port for internet. Trying this:
iptables -A DOCKER-USER -p tcp --dport 4150 -j DROP does not block the port - still can access to it from the internet (not from server machine).
How can i block access from internet to all ports that are on the server, but allow only 22,80 ? And keep that ports available from localhost of the server (eg from the server itself) ?
Not the IPTables based solution you're looking for, but a much simpler solution is to only publish to a specific interface, instead of all interfaces. And when that interface is the loopback interface, e.g. 127.0.0.1, you'll only be able to access the port locally. To do this, add the interface to the beginning of the publish spec:
docker run -p 127.0.0.1:4150:4150 ...
Or a similar syntax in the compose file:
...
ports:
- 127.0.0.1:4150:4150
...
As for why the command you tried using didn't work, this needs conntrack to get the original port rather than the docker mapped port:
iptables -I DOCKER-USER -p tcp -m contrack --ctorigdstport 4150 -j DROP
This also changed from -A (append) to -I (insert) because there's a default rule to accept everything in that list.

Having Apache httpd listen on port 80, but not started as root?

I would like to have my Apache httpd launch as non-route user (httpd) and still listen on port 80/443. This server will be running on a Linux host.
Given that the first 1024 ports are reserved, how would I go about having a reserved port handled by a non-root daemon? Alternatively, can I run my apache on a non-reserved port and have the port's traffic redirect locally to that other port?
You can use iptables for port redirecting:
# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

How to access Weave DNS-Server from external?

I use the Weave network plugin on a Docker-Swarm.
I created a docker network with a specific IP-Range, different from the default Weave Network, to which I route from my internal network.
To make the containers even better accessible I use weave to attach DNS names like containername.auto.mycompany.de. Now I want to access those from my company Network. The Problem is, that weave only allows access to the weave DNS from the local host.
Like on one of my swarm nodes i can do:
host foobar.auto.mycompany.de 172.17.0.1
Using domain server:
Name: 172.17.0.1
Address: 172.17.0.1#53
Aliases:
foobar.auto.mycompany.de has address 10.40.13.3
Host foobar.auto.mycompany.de not found: 3(NXDOMAIN)
Host foobar.auto.mycompany.de not found: 3(NXDOMAIN)
But I don't find a way to make the weave container accessible on one of the IP's from this (10.40.130/24) docker network or expose the port to the swarm node.
The only way I can think of, but don't like, is doing something like this:
iptables -t nat -A DOCKER -p tcp --dport 53 -j DNAT --to-destination 172.17.0.1:53
(this does not work, it's just the idea)
Or tamper with the weave script to make it expose the port on start of the weave container.
Does anybody know of a better solution?
In fact setting the rules
iptables -A DOCKER -p tcp -m tcp --dport 53 -j DNAT --to-destination 172.17.0.1:53
iptables -A DOCKER -p udp -m udp --dport 53 -j DNAT --to-destination 172.17.0.1:53
does it. When I first tried that, I simply missed to see, that my request would have come from "outside" the server to work, not from inside to the loopback device.
Still not a pretty solution but it does the job. I'm looking forward to see better solutions from you guys.
(Bounty stands!)

Check if port forwarding worked for node server on AWS machine

I have deployed a node application that listens to port 5000 on a free usage tier ubuntu machine from AWS.
I've followed suggestions from:
How to start node.js on port 80 on a linux server?
and from: Best practices when running Node.js with port 80 (Ubuntu / Linode)
Answers to both these questions suggest port forwarding and I have done the same. But my server still doesn't respond to requests on port 80.
Is there a way I can check if the port forwarding was successful?
The permission settings to listen to HTTP requests have been setup through the AWS console.
Also there is nothing listening to port 80 on the machine as of now. netstat -l | grep :80 comes up empty.
The server runs fine if I access it as: http://<elastic-ip>:5000
You will not see port 80 listening since there is no daemon using that socket; the kernel is performing a packet redirect.
To check how many packets traversed the port forwarding rule you set up, inspect the PREROUTING chain on the nat tables with sudo iptables -t nat -L PREROUTING -n -v. It will show output like:
Chain PREROUTING (policy ACCEPT 15 packets, 1226 bytes)
pkts bytes target prot opt in out source destination
3 180 REDIRECT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 3000
If you are testing from localhost, you must also redirect on OUTPUT since PREROUTING isn't used by the loopback interface. Do that with
iptables -t nat -A OUTPUT -p tcp --dport 80 -j REDIRECT --to-port 3000
And of course, check that port 80 is open to allow external traffic.

Resources