0

I have installed a webserver in an lxc container. This webserver can be accessed from the outside world via its URL thanks to the following iptable rule:

sudo iptables -t nat -A PREROUTING -i eno1 -p tcp --dport 80 -j DNAT --to 10.42.XXX.XXX:80

My problem is that when I try to access my webserver from the lxc container of the websever itself, it does not work.

curl http://my.url.com
curl: (7) Failed to connect to my.url.com port 80: Connection refused

Please, notice that it works fine from another computer.

I have tried to add another iptable rule:

sudo iptables -t nat -A PREROUTING -i lxcbr0 -p tcp --dport 80 -j DNAT --to 10.42.XXX.XXX:80

and I get:

curl http://my.url.com
curl: (7) Failed to connect to my.url.com port 80: Connection timed out
1

What happens with the 2nd PREROUTING rule added is that the container receives its own request mirrored to itself with its own source IP as source (as well as destination). It's a no go for various reasons: rp_filter triggers, the network stack doesn't know this connection attempt (it sent it to my.url.com, not itself) etc. If there were a second container in the same LAN doing the request, there would still be an asymmetric routing + NAT problem that would prevent it to work correctly either.

That won't work without altering also the source address. So a double NAT must be done in the end.

With this rule to complete what was already done:

sudo iptables -t nat -A POSTROUTING -o lxcbr0 -s 10.42.XXX.XXX -j SNAT 10.43.XXX.XXX

it will work correctly, because the only case IP 10.42.XXX.XXX is going to lxcbr0 instead of from is when the previous PREROUTING DNAT rule triggered. Note it's 43, not 42 anymore with 10.43.XXX.XXX. It's still easy in the logs to know where the request came from, because that will be reserved for this case. Any IP can do, public, private, existing or not, even belonging to the LXC host (eg: my.url.com), as long as it's not the same LAN and is routed by the LXC host.

As a variant one can NAT the whole subnet with NETMAP allowing other containers behind lxcbr0 to do the same request without routing problem anymore and still having useful logs. So instead of the previous rule that would be, for a /24 (OP's informations are not precise enough to guess what is the LAN netmask. Replace below with 10.42.0.0/16 and 10.43.0.0/16 for a /16):

sudo iptables -t nat -A POSTROUTING -o lxcbr0 -s 10.42.XXX.0/24 -j NETMAP 10.43.XXX.0/24

There's still a problem: with OP's 2nd rule as a test, the container(s) cannot do http requests on internet anymore, since every request will come back to 10.42.XXX.XXX. So in the end it might be more useful to rewrite and factorize the total of 3 rules like this with only these 2 rules:

sudo iptables -t nat -A PREROUTING -d my.url.com -p tcp --dport 80 -j DNAT --to 10.42.XXX.XXX
sudo iptables -t nat -A POSTROUTING -o lxcbr0 -s 10.42.XXX.0/24 -j NETMAP --to 10.43.XXX.0/24

Complete with this one for the same request to also work from the LXC host itself:

sudo iptables -t nat -A OUTPUT -d my.url.com -p tcp --dport 80 -j DNAT --to 10.42.XXX.XXX

More complex cases would require marking packets in PREROUTING and matching the mark in POSTROUTING, but that's not needed here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.